diff --git a/cert.pem b/cert.pem new file mode 100644 index 0000000..5650a1e --- /dev/null +++ b/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC5jCCAdCgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD +bzAeFw0xNDAzMTcwNjIwNTFaFw0xNTAzMTcwNjIwNTFaMBIxEDAOBgNVBAoTB0Fj +bWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDccNO1xmd4lWSf +d/0/QS3E93cYIWHw831i/IKxigdRD/XMZonLdEHywW6lOiXazaP8e6CqPGSmnl0x +5k/3dvGCMj2JCVxM6+z7NpL+AiwvXmvkj/TOciCgwqssCwYS2CiVwjfazRjx1ZUJ +VDC5qiyRsfktQ2fVHrpnJGVSRagmiQgwGWBilVG9B8QvRtpQKN/GQGq17oIQm8aK +kOdPt93g93ojMIg7YJpgDgOirvVz/hDn7YD4ryrtPos9CMafFkJprymKpRHyvz7P +8a3+OkuPjFjPnwOHQ5u1U3+8vC44vfb1ExWzDLoT8Xp8Gndx39k0f7MVOol3GnYu +MN/dvNUdAgMBAAGjSzBJMA4GA1UdDwEB/wQEAwIAoDATBgNVHSUEDDAKBggrBgEF +BQcDATAMBgNVHRMBAf8EAjAAMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDALBgkqhkiG +9w0BAQUDggEBAIG8CJqvTIgJnNOK+i5/IUc/3yF/mSCWuG8qP+Fmo2t6T0PVOtc0 +8wiWH5iWtCAhjn0MRY9l/hIjWm6gUZGHCGuEgsOPpJDYGoNLjH9Xwokm4y3LFNRK +UBrrrDbKRNibApBHCapPf6gC5sXcjOwx7P2/kiHDgY7YH47jfcRhtAPNsM4gjsEO +RmwENY+hRUFHIRfQTyalqND+x6PWhRo3K6hpHs4DQEYPq4P2kFPqUqSBymH+Ny5/ +BcQ3wdMNmC6Bm/oiL1QV0M+/InOsAgQk/EDd0kmoU1ZT2lYHQduGmP099bOlHNpS +uqO3vXF3q8SPPr/A9TqSs7BKkBQbe0+cdsA= +-----END CERTIFICATE----- diff --git a/client.go b/client.go index f6f22cd..964ef3e 100644 --- a/client.go +++ b/client.go @@ -3,6 +3,7 @@ package main import ( "bufio" "bytes" + "crypto/tls" "encoding/binary" "fmt" "github.com/ginuerzh/gosocks5" @@ -45,7 +46,7 @@ func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) { nm = 1 } b := make([]byte, 2+nm) - b[0] = Ver5 + b[0] = gosocks5.Ver5 b[1] = uint8(nm) copy(b[2:], methods) @@ -57,7 +58,7 @@ func handshake(conn net.Conn, methods ...uint8) (method uint8, err error) { return } - if b[0] != Ver5 { + if b[0] != gosocks5.Ver5 { err = gosocks5.ErrBadVersion } method = b[1] @@ -74,17 +75,31 @@ func cliHandle(conn net.Conn) { } defer sconn.Close() - method, err := handshake(sconn, MethodAES256, gosocks5.MethodNoAuth) - if err != nil || method == gosocks5.MethodNoAcceptable { + method := gosocks5.MethodNoAuth + for m, v := range Methods { + if Method == v { + method = m + } + } + + method, err = handshake(sconn, method) + if err != nil { return } - if method == MethodAES256 { - cipher, _ := shadowsocks.NewCipher(Cipher, Password) + + switch method { + case MethodTLS: + sconn = tls.Client(sconn, &tls.Config{InsecureSkipVerify: true}) + case MethodAES128, MethodAES192, MethodAES256, + MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: + cipher, _ := shadowsocks.NewCipher(Methods[method], Password) sconn = shadowsocks.NewConn(sconn, cipher) + case gosocks5.MethodNoAcceptable: + return } if Shadows { - cipher, _ := shadowsocks.NewCipher(Cipher, Password) + cipher, _ := shadowsocks.NewCipher(SMethod, SPassword) conn = shadowsocks.NewConn(conn, cipher) handleShadow(conn, sconn) return @@ -157,7 +172,7 @@ func handleSocks5(conn net.Conn, sconn net.Conn) { uconn, err := net.ListenUDP("udp", nil) if err != nil { log.Println(err) - gosocks5.NewReply(Failure, nil).Write(conn) + gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) return } defer uconn.Close() @@ -166,7 +181,7 @@ func handleSocks5(conn net.Conn, sconn net.Conn) { addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) //log.Println("udp:", addr) - rep = gosocks5.NewReply(Succeeded, addr) + rep = gosocks5.NewReply(gosocks5.Succeeded, addr) if err := rep.Write(conn); err != nil { log.Println(err) return diff --git a/key.pem b/key.pem new file mode 100644 index 0000000..3683350 --- /dev/null +++ b/key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA3HDTtcZneJVkn3f9P0EtxPd3GCFh8PN9YvyCsYoHUQ/1zGaJ +y3RB8sFupTol2s2j/Hugqjxkpp5dMeZP93bxgjI9iQlcTOvs+zaS/gIsL15r5I/0 +znIgoMKrLAsGEtgolcI32s0Y8dWVCVQwuaoskbH5LUNn1R66ZyRlUkWoJokIMBlg +YpVRvQfEL0baUCjfxkBqte6CEJvGipDnT7fd4Pd6IzCIO2CaYA4Doq71c/4Q5+2A ++K8q7T6LPQjGnxZCaa8piqUR8r8+z/Gt/jpLj4xYz58Dh0ObtVN/vLwuOL329RMV +swy6E/F6fBp3cd/ZNH+zFTqJdxp2LjDf3bzVHQIDAQABAoIBAHal26147nQ+pHwY +jxwers3XDCjWvup7g79lfcqlKi79UiUEA6KYHm7UogMYewt7p4nb2KwH+XycvDiB +aAUf5flXpTs+6IkWauUDiLZi4PlV7uiEexUq5FjirlL0U/6MjbudX4bK4WQ4uxDc +WaV07Kw2iJFOOHLDKT0en9JaX5jtJNc4ZnE9efFoQ5jfypPWtRw65G1rULEg6nvc +GDh+1ce+4foCkpLRC9c24xAwJONZG6x3UqrSS9qfAsb73nWRQrTfUcO3nhoN8VvL +kL9skn1+S06NyUN0KoEtyRBp+RcpXSsBWAo6qZmo/WqhB/gjzWrxVwn20+yJSm35 +ZsMc6QECgYEA8GS+Mp9xfB2szWHz6YTOO1Uu4lHM1ccZMwS1G+dL0KO3uGAiPdvp +woVot6v6w88t7onXsLo5pgz7SYug0CpkF3K/MRd1Ar4lH7PK7IBQ6rFr9ppVxDbx +AEWRswUoPbKCr7W6HU8LbQHDavsDlEIwc6+DiwnL4BzlKjb7RpgQEz0CgYEA6sB5 +uHvx3Y5FDcGk1n73leQSAcq14l3ZLNpjrs8msoREDil/j5WmuSN58/7PGMiMgHEi +1vLm3H796JmvGr9OBvspOjHyk07ui2/We/j9Hoxm1VWhyi8HkLNDj70HKalTTFMz +RHO4O+0xCva+h9mKZrRMVktXr2jjdFn/0MYIZ2ECgYAIIsC1IeRLWQ3CHbCNlKsO +IwHlMvOFwKk/qsceXKOaOhA7szU1dr3gkXdL0Aw6mEZrrkqYdpUA46uVf54/rU+Z +445I8QxKvXiwK/uQKX+TkdGflPWWIG3jnnch4ejMvb/ihnn4B/bRB6A/fKNQXzUY +lTYUfI5j1VaEKTwz1W2l2QKBgByFCcSp+jZqhGUpc3dDsZyaOr3Q/Mvlju7uEVI5 +hIAHpaT60a6GBd1UPAqymEJwivFHzW3D0NxU6VAK68UaHMaoWNfjHY9b9YsnKS2i +kE3XzN56Ks+/avHfdYPO+UHMenw5V28nh+hv5pdoZrlmanQTz3pkaOC8o3WNQZEB +nh/BAoGBAMY5z2f1pmMhrvtPDSlEVjgjELbaInxFaxPLR4Pdyzn83gtIIU14+R8X +2LPs6PPwrNjWnIgrUSVXncIFL3pa45B+Mx1pYCpOAB1+nCZjIBQmpeo4Y0dwA/XH +85EthKPvoszm+OPbyI16OcePV5ocX7lupRYuAo0pek7bomhmHWHz +-----END RSA PRIVATE KEY----- diff --git a/main.go b/main.go index 65e055c..5e0b83a 100644 --- a/main.go +++ b/main.go @@ -10,17 +10,22 @@ import ( var ( Laddr, Saddr, Proxy string Shadows bool - Cipher, Password string + SMethod, SPassword string + Method, Password string + CertFile, KeyFile string ) func init() { flag.StringVar(&Proxy, "P", "", "proxy for forward") flag.StringVar(&Saddr, "S", "", "the server that connecting to") flag.StringVar(&Laddr, "L", ":8080", "listen address") - flag.StringVar(&Cipher, "cipher", "rc4-md5", "cipher method") - flag.StringVar(&Password, "password", "ginuerzh@gmail.com", "cipher password") + flag.StringVar(&Method, "m", "tls", "cipher method") + flag.StringVar(&Password, "p", "ginuerzh@gmail.com", "cipher password") + flag.StringVar(&CertFile, "cert", "cert.pem", "cert.pem file for tls") + flag.StringVar(&KeyFile, "key", "key.pem", "key.pem file for tls") flag.BoolVar(&Shadows, "ss", false, "shadowsocks compatible") - flag.BoolVar(&Debug, "d", false, "debug option") + flag.StringVar(&SMethod, "sm", "rc4-md5", "shadowsocks cipher method") + flag.StringVar(&SPassword, "sp", "ginuerzh@gmail.com", "shadowsocks cipher password") flag.Parse() log.SetFlags(log.LstdFlags | log.Lshortfile) @@ -30,9 +35,10 @@ func main() { //log.Fatal(gost.Run()) if len(Saddr) == 0 { srv := &gosocks5.Server{ - Addr: Laddr, - SelectMethod: selectMethod, - Handle: srvHandle, + Addr: Laddr, + SelectMethod: selectMethod, + MethodSelected: methodSelected, + Handle: srvHandle, } log.Fatal(srv.ListenAndServe()) return diff --git a/server.go b/server.go index d0dedbe..3c04461 100644 --- a/server.go +++ b/server.go @@ -5,37 +5,46 @@ import ( "github.com/shadowsocks/shadowsocks-go/shadowsocks" "net" //"strconv" + "crypto/tls" "log" ) -const ( - MethodAES256 uint8 = 0x88 -) - func selectMethod(methods ...uint8) uint8 { for _, method := range methods { - if method == MethodAES256 { + if _, ok := Methods[method]; ok { return method } } return gosocks5.MethodNoAuth } -func srvHandle(conn net.Conn, method uint8) { - defer conn.Close() - - if method == gosocks5.MethodNoAcceptable { - return - } - - if method == MethodAES256 { - cipher, _ := shadowsocks.NewCipher(Cipher, Password) +func methodSelected(method uint8, conn net.Conn) (net.Conn, error) { + switch method { + case MethodTLS: + cert, err := tls.LoadX509KeyPair(CertFile, KeyFile) + if err != nil { + log.Println(err) + return nil, err + } + conn = tls.Server(conn, &tls.Config{Certificates: []tls.Certificate{cert}}) + case MethodAES128, MethodAES192, MethodAES256, + MethodDES, MethodBF, MethodCAST5, MethodRC4MD5, MethodRC4, MethodTable: + cipher, err := shadowsocks.NewCipher(Methods[method], Password) + if err != nil { + return nil, err + } conn = shadowsocks.NewConn(conn, cipher) + case gosocks5.MethodNoAcceptable: + return nil, gosocks5.ErrBadMethod } + return conn, nil +} + +func srvHandle(conn net.Conn) { req, err := gosocks5.ReadRequest(conn) if err != nil { - log.Println(err) + //log.Println(err) return } @@ -96,7 +105,7 @@ func srvHandle(conn net.Conn, method uint8) { uconn, err := net.ListenUDP("udp", nil) if err != nil { log.Println(err) - gosocks5.NewReply(Failure, nil).Write(conn) + gosocks5.NewReply(gosocks5.Failure, nil).Write(conn) return } defer uconn.Close() @@ -104,7 +113,7 @@ func srvHandle(conn net.Conn, method uint8) { addr := ToSocksAddr(uconn.LocalAddr()) addr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) //log.Println("udp:", addr) - rep := gosocks5.NewReply(Succeeded, addr) + rep := gosocks5.NewReply(gosocks5.Succeeded, addr) if err := rep.Write(conn); err != nil { log.Println(err) return diff --git a/socks5.go b/socks5.go deleted file mode 100644 index 716f583..0000000 --- a/socks5.go +++ /dev/null @@ -1,287 +0,0 @@ -package main - -import ( - "bytes" - "encoding/binary" - "errors" - "fmt" - "io" - //"log" - "net" -) - -const ( - Ver5 = 5 -) - -const ( - MethodNoAuth uint8 = iota - MethodGSSAPI - MethodUserPass - // X'03' to X'7F' IANA ASSIGNED - // X'80' to X'FE' RESERVED FOR PRIVATE METHODS - MethodNoAcceptable = 0xFF -) - -const ( - CmdConnect uint8 = 1 - CmdBind = 2 - CmdUdp = 3 -) - -const ( - AddrIPv4 uint8 = 1 - AddrDomain = 3 - AddrIPv6 = 4 -) - -const ( - Succeeded uint8 = iota - Failure - NotAllowed - NetUnreachable - HostUnreachable - ConnRefused - TTLExpired - CmdUnsupported - AddrUnsupported -) - -var ( - ErrBadVersion = errors.New("Bad version") - ErrBadFormat = errors.New("Bad format") - ErrBadAddrType = errors.New("Bad address type") - ErrShortBuffer = errors.New("Short buffer") -) - -/* -+----+-----+-------+------+----------+----------+ -|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | -+----+-----+-------+------+----------+----------+ -| 1 | 1 | X'00' | 1 | Variable | 2 | -+----+-----+-------+------+----------+----------+ -*/ -type Cmd struct { - Cmd uint8 - AddrType uint8 - Addr string - Port uint16 -} - -func NewCmd(cmd uint8, atype uint8, addr string, port uint16) *Cmd { - if len(addr) == 0 { - addr = "0.0.0.0" - } - return &Cmd{ - Cmd: cmd, - AddrType: atype, - Addr: addr, - Port: port, - } -} - -func ReadCmd(r io.Reader) (*Cmd, error) { - b := make([]byte, 256) - n, err := r.Read(b) - //log.Println(b[:n]) - if err != nil { - //log.Println(err) - return nil, err - } - if n < 10 { - return nil, ErrBadFormat - } - if b[0] != Ver5 { - return nil, ErrBadVersion - } - - cmd := &Cmd{ - Cmd: b[1], - AddrType: b[3], - } - - pos := 4 - - switch cmd.AddrType { - case AddrIPv4: - if n != 10 { - return nil, ErrBadFormat - } - cmd.Addr = net.IP(b[pos : pos+net.IPv4len]).String() - pos += net.IPv4len - case AddrIPv6: - if n != 22 { - return nil, ErrBadFormat - } - cmd.Addr = net.IP(b[pos : pos+net.IPv6len]).String() - pos += net.IPv6len - case AddrDomain: - length := int(b[pos]) - if n != 4+1+length+2 { - return nil, ErrBadFormat - } - - pos++ - cmd.Addr = string(b[pos : pos+length]) - pos += length - default: - pos += 4 - } - - cmd.Port = binary.BigEndian.Uint16(b[pos:]) - - return cmd, nil -} - -func (cmd *Cmd) Write(w io.Writer) (err error) { - b := make([]byte, 256) - - b[0] = Ver5 - b[1] = cmd.Cmd - b[3] = cmd.AddrType - pos := 4 - - switch cmd.AddrType { - case AddrIPv4: - pos += copy(b[pos:], net.ParseIP(cmd.Addr).To4()) - case AddrDomain: - b[pos] = byte(len(cmd.Addr)) - pos++ - pos += copy(b[pos:], []byte(cmd.Addr)) - case AddrIPv6: - pos += copy(b[pos:], net.ParseIP(cmd.Addr).To16()) - } - binary.BigEndian.PutUint16(b[pos:], cmd.Port) - pos += 2 - - _, err = w.Write(b[:pos]) - - return -} - -func (cmd *Cmd) String() string { - return fmt.Sprintf("5 %d 0 %d %s %d", - cmd.Cmd, cmd.AddrType, cmd.Addr, cmd.Port) -} - -/* -+----+------+------+----------+----------+----------+ -|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | -+----+------+------+----------+----------+----------+ -| 2 | 1 | 1 | Variable | 2 | Variable | -+----+------+------+----------+----------+----------+ -*/ -type UdpPayload struct { - Rsv uint16 - Frag uint8 - AddrType uint8 - Addr string - Port uint16 - Data []byte -} - -func NewUdpPayload(rsv uint16, atype uint8, addr string, port uint16, data []byte) *UdpPayload { - if len(addr) == 0 { - addr = "0.0.0.0" - } - return &UdpPayload{ - Rsv: rsv, - AddrType: atype, - Addr: addr, - Port: port, - Data: data, - } -} - -func ReadUdpPayload(r io.Reader) (*UdpPayload, error) { - buf := make([]byte, 65797) - n, err := io.ReadAtLeast(r, buf, 5) - //log.Println("r", buf[:n]) - if err != nil { - return nil, err - } - - up := &UdpPayload{ - Rsv: binary.BigEndian.Uint16(buf[:2]), - Frag: buf[2], - AddrType: buf[3], - } - - dataIndex := 0 - switch up.AddrType { - case AddrIPv4: - dataIndex = 10 - case AddrIPv6: - dataIndex = 22 - case AddrDomain: - dataIndex = 7 + int(buf[4]) - default: - return nil, ErrBadAddrType - } - - dataLen := int(up.Rsv) - if n < dataIndex+dataLen { - if _, err := io.ReadFull(r, buf[n:dataIndex+dataLen]); err != nil { - return nil, err - } - } - - pos := 4 - switch up.AddrType { - case AddrIPv4: - up.Addr = net.IP(buf[pos : pos+net.IPv4len]).String() - pos += net.IPv4len - case AddrIPv6: - up.Addr = net.IP(buf[pos : pos+net.IPv6len]).String() - pos += net.IPv6len - case AddrDomain: - length := int(buf[pos]) - pos++ - up.Addr = string(buf[pos : pos+length]) - pos += length - } - - up.Port = binary.BigEndian.Uint16(buf[pos:]) - //log.Println(up.Addr, up.Port) - if dataLen > 0 { - up.Data = buf[dataIndex : dataIndex+dataLen] - } else { - up.Data = buf[dataIndex:n] - } - - return up, nil -} - -func (up *UdpPayload) Write(w io.Writer) error { - buffer := &bytes.Buffer{} - - b := make([]byte, 2) - - binary.BigEndian.PutUint16(b, up.Rsv) - buffer.Write(b) - buffer.WriteByte(up.Frag) - buffer.WriteByte(up.AddrType) - - switch up.AddrType { - case AddrIPv4: - buffer.Write(net.ParseIP(up.Addr).To4()) - case AddrDomain: - buffer.WriteByte(uint8(len(up.Addr))) - buffer.Write([]byte(up.Addr)) - case AddrIPv6: - buffer.Write(net.ParseIP(up.Addr).To16()) - } - - binary.BigEndian.PutUint16(b, up.Port) - buffer.Write(b) - buffer.Write(up.Data) - - _, err := w.Write(buffer.Bytes()) - - return err -} - -func (up *UdpPayload) String() string { - return fmt.Sprintf("%d %d %d %s %d [%d]", - up.Rsv, up.Frag, up.AddrType, up.Addr, up.Port, len(up.Data)) -} diff --git a/util.go b/util.go index 44aa0f6..52f6555 100644 --- a/util.go +++ b/util.go @@ -13,12 +13,38 @@ import ( "strconv" ) +const ( + MethodTLS uint8 = 0x80 + iota + MethodAES128 + MethodAES192 + MethodAES256 + MethodDES + MethodBF + MethodCAST5 + MethodRC4MD5 + MethodRC4 + MethodTable +) + +var Methods = map[uint8]string{ + MethodTLS: "tls", // 0x80 + MethodAES128: "aes-128-cfb", // 0x81 + MethodAES192: "aes-192-cfb", // 0x82 + MethodAES256: "aes-256-cfb", // 0x83 + MethodDES: "des-cfb", // 0x84 + MethodBF: "bf-cfb", // 0x85 + MethodCAST5: "cast5-cfb", // 0x86 + MethodRC4MD5: "rc4-md5", // 8x87 + MethodRC4: "rc4", // 0x88 + MethodTable: "table", // 0x89 +} + func ToSocksAddr(addr net.Addr) *gosocks5.Addr { host, port, _ := net.SplitHostPort(addr.String()) p, _ := strconv.Atoi(port) return &gosocks5.Addr{ - Type: AddrIPv4, + Type: gosocks5.AddrIPv4, Host: host, Port: uint16(p), }