1package socks5 2 3import ( 4 "bufio" 5 "fmt" 6 "log" 7 "net" 8 "os" 9 10 "golang.org/x/net/context" 11) 12 13const ( 14 socks5Version = uint8(5) 15) 16 17// Config is used to setup and configure a Server 18type Config struct { 19 // AuthMethods can be provided to implement custom authentication 20 // By default, "auth-less" mode is enabled. 21 // For password-based auth use UserPassAuthenticator. 22 AuthMethods []Authenticator 23 24 // If provided, username/password authentication is enabled, 25 // by appending a UserPassAuthenticator to AuthMethods. If not provided, 26 // and AUthMethods is nil, then "auth-less" mode is enabled. 27 Credentials CredentialStore 28 29 // Resolver can be provided to do custom name resolution. 30 // Defaults to DNSResolver if not provided. 31 Resolver NameResolver 32 33 // Rules is provided to enable custom logic around permitting 34 // various commands. If not provided, PermitAll is used. 35 Rules RuleSet 36 37 // Rewriter can be used to transparently rewrite addresses. 38 // This is invoked before the RuleSet is invoked. 39 // Defaults to NoRewrite. 40 Rewriter AddressRewriter 41 42 // BindIP is used for bind or udp associate 43 BindIP net.IP 44 45 // Logger can be used to provide a custom log target. 46 // Defaults to stdout. 47 Logger *log.Logger 48 49 // Optional function for dialing out 50 Dial func(ctx context.Context, network, addr string) (net.Conn, error) 51} 52 53// Server is reponsible for accepting connections and handling 54// the details of the SOCKS5 protocol 55type Server struct { 56 config *Config 57 authMethods map[uint8]Authenticator 58} 59 60// New creates a new Server and potentially returns an error 61func New(conf *Config) (*Server, error) { 62 // Ensure we have at least one authentication method enabled 63 if len(conf.AuthMethods) == 0 { 64 if conf.Credentials != nil { 65 conf.AuthMethods = []Authenticator{&UserPassAuthenticator{conf.Credentials}} 66 } else { 67 conf.AuthMethods = []Authenticator{&NoAuthAuthenticator{}} 68 } 69 } 70 71 // Ensure we have a DNS resolver 72 if conf.Resolver == nil { 73 conf.Resolver = DNSResolver{} 74 } 75 76 // Ensure we have a rule set 77 if conf.Rules == nil { 78 conf.Rules = PermitAll() 79 } 80 81 // Ensure we have a log target 82 if conf.Logger == nil { 83 conf.Logger = log.New(os.Stdout, "", log.LstdFlags) 84 } 85 86 server := &Server{ 87 config: conf, 88 } 89 90 server.authMethods = make(map[uint8]Authenticator) 91 92 for _, a := range conf.AuthMethods { 93 server.authMethods[a.GetCode()] = a 94 } 95 96 return server, nil 97} 98 99// ListenAndServe is used to create a listener and serve on it 100func (s *Server) ListenAndServe(network, addr string) error { 101 l, err := net.Listen(network, addr) 102 if err != nil { 103 return err 104 } 105 return s.Serve(l) 106} 107 108// Serve is used to serve connections from a listener 109func (s *Server) Serve(l net.Listener) error { 110 for { 111 conn, err := l.Accept() 112 if err != nil { 113 return err 114 } 115 go s.ServeConn(conn) 116 } 117 return nil 118} 119 120// ServeConn is used to serve a single connection. 121func (s *Server) ServeConn(conn net.Conn) error { 122 defer conn.Close() 123 bufConn := bufio.NewReader(conn) 124 125 // Read the version byte 126 version := []byte{0} 127 if _, err := bufConn.Read(version); err != nil { 128 s.config.Logger.Printf("[ERR] socks: Failed to get version byte: %v", err) 129 return err 130 } 131 132 // Ensure we are compatible 133 if version[0] != socks5Version { 134 err := fmt.Errorf("Unsupported SOCKS version: %v", version) 135 s.config.Logger.Printf("[ERR] socks: %v", err) 136 return err 137 } 138 139 // Authenticate the connection 140 authContext, err := s.authenticate(conn, bufConn) 141 if err != nil { 142 err = fmt.Errorf("Failed to authenticate: %v", err) 143 s.config.Logger.Printf("[ERR] socks: %v", err) 144 return err 145 } 146 147 request, err := NewRequest(bufConn) 148 if err != nil { 149 if err == unrecognizedAddrType { 150 if err := sendReply(conn, addrTypeNotSupported, nil); err != nil { 151 return fmt.Errorf("Failed to send reply: %v", err) 152 } 153 } 154 return fmt.Errorf("Failed to read destination address: %v", err) 155 } 156 request.AuthContext = authContext 157 if client, ok := conn.RemoteAddr().(*net.TCPAddr); ok { 158 request.RemoteAddr = &AddrSpec{IP: client.IP, Port: client.Port} 159 } 160 161 // Process the client request 162 if err := s.handleRequest(request, conn); err != nil { 163 err = fmt.Errorf("Failed to handle request: %v", err) 164 s.config.Logger.Printf("[ERR] socks: %v", err) 165 return err 166 } 167 168 return nil 169} 170