From d77ba76ccf1762df318f26d1e8f20c61ba239ec6 Mon Sep 17 00:00:00 2001 From: V2Ray Date: Fri, 25 Sep 2015 17:59:45 +0200 Subject: [PATCH] Update error handling in socks proxy --- common/errors/errors.go | 30 ++++++++++++++++++++++ proxy/socks/protocol/socks.go | 28 +++----------------- proxy/socks/protocol/socks4.go | 25 ++++++++++++++++++ proxy/socks/socks.go | 47 +++++++++++++++------------------- spec/errors.md | 12 +++++++++ 5 files changed, 92 insertions(+), 50 deletions(-) diff --git a/common/errors/errors.go b/common/errors/errors.go index 44daf98e..bccc424f 100644 --- a/common/errors/errors.go +++ b/common/errors/errors.go @@ -87,3 +87,33 @@ func NewIPFormatError(ip []byte) IPFormatError { func (err IPFormatError) Error() string { return fmt.Sprintf("%sInvalid IP %v", err.Prefix(), err.IP) } + +type ConfigurationError struct { + ErrorCode +} + +var configurationErrorInstance = ConfigurationError{ErrorCode: 5} + +func NewConfigurationError() ConfigurationError { + return configurationErrorInstance +} + +func (r ConfigurationError) Error() string { + return r.Prefix() + "Invalid configuration." +} + +type InvalidOperationError struct { + ErrorCode + Operation string +} + +func NewInvalidOperationError(operation string) InvalidOperationError { + return InvalidOperationError{ + ErrorCode: 6, + Operation: operation, + } +} + +func (r InvalidOperationError) Error() string { + return r.Prefix() + "Invalid operation: " + r.Operation +} diff --git a/proxy/socks/protocol/socks.go b/proxy/socks/protocol/socks.go index dd6d4047..61e027a3 100644 --- a/proxy/socks/protocol/socks.go +++ b/proxy/socks/protocol/socks.go @@ -86,12 +86,6 @@ type Socks5AuthenticationResponse struct { authMethod byte } -type Socks4AuthenticationResponse struct { - result byte - port uint16 - ip []byte -} - func NewAuthenticationResponse(authMethod byte) *Socks5AuthenticationResponse { return &Socks5AuthenticationResponse{ version: socksVersion, @@ -99,29 +93,11 @@ func NewAuthenticationResponse(authMethod byte) *Socks5AuthenticationResponse { } } -func NewSocks4AuthenticationResponse(result byte, port uint16, ip []byte) *Socks4AuthenticationResponse { - return &Socks4AuthenticationResponse{ - result: result, - port: port, - ip: ip, - } -} - func WriteAuthentication(writer io.Writer, r *Socks5AuthenticationResponse) error { _, err := writer.Write([]byte{r.version, r.authMethod}) return err } -func WriteSocks4AuthenticationResponse(writer io.Writer, r *Socks4AuthenticationResponse) error { - buffer := make([]byte, 8) - // buffer[0] is always 0 - buffer[1] = r.result - binary.BigEndian.PutUint16(buffer[2:4], r.port) - copy(buffer[4:], r.ip) - _, err := writer.Write(buffer) - return err -} - type Socks5UserPassRequest struct { version byte username string @@ -132,6 +108,10 @@ func (request Socks5UserPassRequest) IsValid(username string, password string) b return request.username == username && request.password == password } +func (request Socks5UserPassRequest) AuthDetail() string { + return request.username + ":" + request.password +} + func ReadUserPassRequest(reader io.Reader) (request Socks5UserPassRequest, err error) { buffer := make([]byte, 256) _, err = reader.Read(buffer[0:2]) diff --git a/proxy/socks/protocol/socks4.go b/proxy/socks/protocol/socks4.go index c28615f8..fa690adc 100644 --- a/proxy/socks/protocol/socks4.go +++ b/proxy/socks/protocol/socks4.go @@ -27,3 +27,28 @@ type Socks4AuthenticationRequest struct { Port uint16 IP [4]byte } + +type Socks4AuthenticationResponse struct { + result byte + port uint16 + ip []byte +} + +func NewSocks4AuthenticationResponse(result byte, port uint16, ip []byte) *Socks4AuthenticationResponse { + return &Socks4AuthenticationResponse{ + result: result, + port: port, + ip: ip, + } +} + +func (r *Socks4AuthenticationResponse) ToBytes(buffer []byte) []byte { + if buffer == nil { + buffer = make([]byte, 8) + } + buffer[1] = r.result + buffer[2] = byte(r.port >> 8) + buffer[3] = byte(r.port) + copy(buffer[4:], r.ip) + return buffer +} diff --git a/proxy/socks/socks.go b/proxy/socks/socks.go index 5129e1e2..76b412a1 100644 --- a/proxy/socks/socks.go +++ b/proxy/socks/socks.go @@ -1,8 +1,6 @@ package socks import ( - _ "bufio" - e2 "errors" "io" "net" "strconv" @@ -15,12 +13,6 @@ import ( "github.com/v2ray/v2ray-core/proxy/socks/protocol" ) -var ( - ErrorAuthenticationFailed = e2.New("None of the authentication methods is allowed.") - ErrorCommandNotSupported = e2.New("Client requested an unsupported command.") - ErrorInvalidUser = e2.New("Invalid username or password.") -) - // SocksServer is a SOCKS 5 proxy server type SocksServer struct { accepting bool @@ -31,7 +23,8 @@ type SocksServer struct { func NewSocksServer(vp *core.Point, rawConfig []byte) *SocksServer { config, err := loadConfig(rawConfig) if err != nil { - panic(log.Error("Unable to load socks config: %v", err)) + log.Error("Unable to load socks config: %v", err) + panic(errors.NewConfigurationError()) } return &SocksServer{ vPoint: vp, @@ -42,10 +35,9 @@ func NewSocksServer(vp *core.Point, rawConfig []byte) *SocksServer { func (server *SocksServer) Listen(port uint16) error { listener, err := net.Listen("tcp", ":"+strconv.Itoa(int(port))) if err != nil { - log.Error("Error on listening port %d: %v", port, err) + log.Error("Socks failed to listen on port %d: %v", port, err) return err } - log.Debug("Working on tcp:%d", port) server.accepting = true go server.AcceptConnections(listener) return nil @@ -55,7 +47,8 @@ func (server *SocksServer) AcceptConnections(listener net.Listener) { for server.accepting { connection, err := listener.Accept() if err != nil { - log.Error("Error on accepting socks connection: %v", err) + log.Error("Socks failed to accept new connection %v", err) + return } go server.HandleConnection(connection) } @@ -68,7 +61,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { auth, auth4, err := protocol.ReadAuthentication(reader) if err != nil && !errors.HasCode(err, 1000) { - log.Error("Error on reading authentication: %v", err) + log.Error("Socks failed to read authentication: %v", err) return err } @@ -81,10 +74,10 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { result = protocol.Socks4RequestRejected } socks4Response := protocol.NewSocks4AuthenticationResponse(result, auth4.Port, auth4.IP[:]) - protocol.WriteSocks4AuthenticationResponse(connection, socks4Response) + connection.Write(socks4Response.ToBytes(nil)) if result == protocol.Socks4RequestRejected { - return ErrorCommandNotSupported + return errors.NewInvalidOperationError("Socks4 command " + strconv.Itoa(int(auth4.Command))) } dest = v2net.NewTCPDestination(v2net.IPAddress(auth4.IP[:], auth4.Port)) @@ -98,23 +91,23 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { authResponse := protocol.NewAuthenticationResponse(protocol.AuthNoMatchingMethod) err = protocol.WriteAuthentication(connection, authResponse) if err != nil { - log.Error("Error on socksio write authentication: %v", err) + log.Error("Socks failed to write authentication: %v", err) return err } - log.Warning("Client doesn't support allowed any auth methods.") - return ErrorAuthenticationFailed + log.Warning("Socks client doesn't support allowed any auth methods.") + return errors.NewInvalidOperationError("Unsupported auth methods.") } authResponse := protocol.NewAuthenticationResponse(expectedAuthMethod) err = protocol.WriteAuthentication(connection, authResponse) if err != nil { - log.Error("Error on socksio write authentication: %v", err) + log.Error("Socks failed to write authentication: %v", err) return err } if server.config.AuthMethod == JsonAuthMethodUserPass { upRequest, err := protocol.ReadUserPassRequest(reader) if err != nil { - log.Error("Failed to read username and password: %v", err) + log.Error("Socks failed to read username and password: %v", err) return err } status := byte(0) @@ -124,17 +117,19 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { upResponse := protocol.NewSocks5UserPassResponse(status) err = protocol.WriteUserPassResponse(connection, upResponse) if err != nil { - log.Error("Error on socksio write user pass response: %v", err) + log.Error("Socks failed to write user pass response: %v", err) return err } if status != byte(0) { - return ErrorInvalidUser + err = errors.NewAuthenticationError(upRequest.AuthDetail()) + log.Warning(err.Error()) + return err } } request, err := protocol.ReadRequest(reader) if err != nil { - log.Error("Error on reading socks request: %v", err) + log.Error("Socks failed to read request: %v", err) return err } @@ -145,11 +140,11 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { response.Error = protocol.ErrorCommandNotSupported err = protocol.WriteResponse(connection, response) if err != nil { - log.Error("Error on socksio write response: %v", err) + log.Error("Socks failed to write response: %v", err) return err } log.Warning("Unsupported socks command %d", request.Command) - return ErrorCommandNotSupported + return errors.NewInvalidOperationError("Socks command " + strconv.Itoa(int(request.Command))) } response.Error = protocol.ErrorSuccess @@ -165,7 +160,7 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error { } err = protocol.WriteResponse(connection, response) if err != nil { - log.Error("Error on socksio write response: %v", err) + log.Error("Socks failed to write response: %v", err) return err } diff --git a/spec/errors.md b/spec/errors.md index 5e30fb67..3ae1a244 100644 --- a/spec/errors.md +++ b/spec/errors.md @@ -23,3 +23,15 @@ * 原因:不正确的 IP 地址 * 解决:请检查客户端软件,如浏览器的配置 +## 0x0005 Configuration Error +* 原因:配置文件不能正常读取 +* 解决:请检查配置文件是否存在,权限是否合适,内容是否正常 + +## 0x0006 Invalid Operation Error +* 原因:不正确的操作 + + +## 0x03E8 Socks Version 4 +* 原因:客户端使用了 SOCKS 4 协议 +* 解决:升级客户端软件 +