package server import ( "encoding/binary" "errors" "github.com/cnlh/easyProxy/bridge" "github.com/cnlh/easyProxy/utils" "io" "log" "net" "strconv" "strings" ) const ( ipV4 = 1 domainName = 3 ipV6 = 4 connectMethod = 1 bindMethod = 2 associateMethod = 3 // The maximum packet size of any udp Associate packet, based on ethernet's max size, // minus the IP and UDP headers. IPv4 has a 20 byte header, UDP adds an // additional 4 bytes. This is a total overhead of 24 bytes. Ethernet's // max packet size is 1500 bytes, 1500 - 24 = 1476. maxUDPPacketSize = 1476 ) const ( succeeded uint8 = iota serverFailure notAllowed networkUnreachable hostUnreachable connectionRefused ttlExpired commandNotSupported addrTypeNotSupported ) const ( UserPassAuth = uint8(2) userAuthVersion = uint8(1) authSuccess = uint8(0) authFailure = uint8(1) ) type Sock5ModeServer struct { server isVerify bool listener net.Listener } //req func (s *Sock5ModeServer) handleRequest(c net.Conn) { /* The SOCKS request is formed as follows: +----+-----+-------+------+----------+----------+ |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | +----+-----+-------+------+----------+----------+ | 1 | 1 | X'00' | 1 | Variable | 2 | +----+-----+-------+------+----------+----------+ */ header := make([]byte, 3) _, err := io.ReadFull(c, header) if err != nil { log.Println("illegal request", err) c.Close() return } switch header[1] { case connectMethod: s.handleConnect(c) case bindMethod: s.handleBind(c) case associateMethod: s.handleUDP(c) default: s.sendReply(c, commandNotSupported) c.Close() } } //reply func (s *Sock5ModeServer) sendReply(c net.Conn, rep uint8) { reply := []byte{ 5, rep, 0, 1, } localAddr := c.LocalAddr().String() localHost, localPort, _ := net.SplitHostPort(localAddr) ipBytes := net.ParseIP(localHost).To4() nPort, _ := strconv.Atoi(localPort) reply = append(reply, ipBytes...) portBytes := make([]byte, 2) binary.BigEndian.PutUint16(portBytes, uint16(nPort)) reply = append(reply, portBytes...) c.Write(reply) } //do conn func (s *Sock5ModeServer) doConnect(c net.Conn, command uint8) (proxyConn *utils.Conn, err error) { addrType := make([]byte, 1) c.Read(addrType) var host string switch addrType[0] { case ipV4: ipv4 := make(net.IP, net.IPv4len) c.Read(ipv4) host = ipv4.String() case ipV6: ipv6 := make(net.IP, net.IPv6len) c.Read(ipv6) host = ipv6.String() case domainName: var domainLen uint8 binary.Read(c, binary.BigEndian, &domainLen) domain := make([]byte, domainLen) c.Read(domain) host = string(domain) default: s.sendReply(c, addrTypeNotSupported) err = errors.New("Address type not supported") return nil, err } var port uint16 binary.Read(c, binary.BigEndian, &port) // connect to host addr := net.JoinHostPort(host, strconv.Itoa(int(port))) var ltype string if command == associateMethod { ltype = utils.CONN_UDP } else { ltype = utils.CONN_TCP } if proxyConn, err = s.GetTunnelAndWriteHost(ltype, s.task.Client.Id, s.config, addr); err != nil { log.Println("get bridge tunnel error: ", err) return } s.sendReply(c, succeeded) var flag string if flag, err = proxyConn.ReadFlag(); err == nil { if flag != utils.CONN_SUCCESS { err = errors.New("conn failed") } } return } //conn func (s *Sock5ModeServer) handleConnect(c net.Conn) { proxyConn, err := s.doConnect(c, connectMethod) defer func() { if s.config.Mux && proxyConn != nil { s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id) } }() if err != nil { c.Close() } else { out, in := utils.ReplayWaitGroup(proxyConn.Conn, c, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux, s.task.Client.Rate) s.FlowAdd(in, out) } } // passive mode func (s *Sock5ModeServer) handleBind(c net.Conn) { } //udp func (s *Sock5ModeServer) handleUDP(c net.Conn) { log.Println("UDP Associate") /* +----+------+------+----------+----------+----------+ |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | +----+------+------+----------+----------+----------+ | 2 | 1 | 1 | Variable | 2 | Variable | +----+------+------+----------+----------+----------+ */ buf := make([]byte, 3) c.Read(buf) // relay udp datagram silently, without any notification to the requesting client if buf[2] != 0 { // does not support fragmentation, drop it log.Println("does not support fragmentation, drop") dummy := make([]byte, maxUDPPacketSize) c.Read(dummy) } proxyConn, err := s.doConnect(c, associateMethod) defer func() { if s.config.Mux && proxyConn != nil { s.bridge.ReturnTunnel(proxyConn, s.task.Client.Id) } }() if err != nil { c.Close() } else { out, in := utils.ReplayWaitGroup(proxyConn.Conn, c, s.config.CompressEncode, s.config.CompressDecode, s.config.Crypt, s.config.Mux, s.task.Client.Rate) s.FlowAdd(in, out) } } //new conn func (s *Sock5ModeServer) handleConn(c net.Conn) { buf := make([]byte, 2) if _, err := io.ReadFull(c, buf); err != nil { log.Println("negotiation err", err) c.Close() return } if version := buf[0]; version != 5 { log.Println("only support socks5, request from: ", c.RemoteAddr()) c.Close() return } nMethods := buf[1] methods := make([]byte, nMethods) if len, err := c.Read(methods); len != int(nMethods) || err != nil { log.Println("wrong method") c.Close() return } if s.isVerify { buf[1] = UserPassAuth c.Write(buf) if err := s.Auth(c); err != nil { c.Close() log.Println("验证失败:", err) return } } else { buf[1] = 0 c.Write(buf) } s.handleRequest(c) } //socks5 auth func (s *Sock5ModeServer) Auth(c net.Conn) error { header := []byte{0, 0} if _, err := io.ReadAtLeast(c, header, 2); err != nil { return err } if header[0] != userAuthVersion { return errors.New("验证方式不被支持") } userLen := int(header[1]) user := make([]byte, userLen) if _, err := io.ReadAtLeast(c, user, userLen); err != nil { return err } if _, err := c.Read(header[:1]); err != nil { return errors.New("密码长度获取错误") } passLen := int(header[0]) pass := make([]byte, passLen) if _, err := io.ReadAtLeast(c, pass, passLen); err != nil { return err } if string(pass) == s.config.U && string(user) == s.config.P { if _, err := c.Write([]byte{userAuthVersion, authSuccess}); err != nil { return err } return nil } else { if _, err := c.Write([]byte{userAuthVersion, authFailure}); err != nil { return err } return errors.New("验证不通过") } return errors.New("未知错误") } //start func (s *Sock5ModeServer) Start() error { var err error s.listener, err = net.Listen("tcp", ":"+strconv.Itoa(s.task.TcpPort)) if err != nil { return err } for { conn, err := s.listener.Accept() if err != nil { if strings.Contains(err.Error(), "use of closed network connection") { break } log.Fatal("accept error: ", err) } if !s.ResetConfig() { conn.Close() continue } go s.handleConn(conn) } return nil } //close func (s *Sock5ModeServer) Close() error { return s.listener.Close() } //new func NewSock5ModeServer(bridge *bridge.Bridge, task *utils.Tunnel) *Sock5ModeServer { s := new(Sock5ModeServer) s.bridge = bridge s.task = task s.config = utils.DeepCopyConfig(task.Config) if s.config.U != "" && s.config.P != "" { s.isVerify = true } else { s.isVerify = false } return s }