浏览代码

username/password support for socks proxy

V2Ray 10 年之前
父节点
当前提交
4c963a51ed
共有 2 个文件被更改,包括 70 次插入1 次删除
  1. 51 0
      io/socks/socks.go
  2. 19 1
      net/socks/socks.go

+ 51 - 0
io/socks/socks.go

@@ -86,6 +86,57 @@ func WriteAuthentication(writer io.Writer, response *Socks5AuthenticationRespons
 	return err
 }
 
+type Socks5UserPassRequest struct {
+  version byte
+  username string
+  password string
+}
+
+func (request Socks5UserPassRequest) IsValid(username string, password string) bool {
+  return request.username == username && request.password == password
+}
+
+func ReadUserPassRequest(reader io.Reader) (request Socks5UserPassRequest, err error) {
+  buffer := make([]byte, 256)
+  _, err = reader.Read(buffer[0:2])
+  if err != nil {
+    return
+  }
+  request.version = buffer[0]
+  nUsername := buffer[1]
+  nBytes, err := reader.Read(buffer[:nUsername])
+  if err != nil {
+    return
+  }
+  request.username = string(buffer[:nBytes])
+  
+  _, err = reader.Read(buffer[0:1])
+  if err != nil {
+    return
+  }
+  nPassword := buffer[0]
+  nBytes, err = reader.Read(buffer[:nPassword])
+  if err != nil {
+    return
+  }
+  request.password = string(buffer[:nBytes])
+  return
+}
+
+type Socks5UserPassResponse struct {
+  version byte
+  status byte
+}
+
+func NewSocks5UserPassResponse(status byte) Socks5UserPassResponse {
+  return Socks5UserPassResponse{socksVersion, status}
+}
+
+func WriteUserPassResponse(writer io.Writer, response Socks5UserPassResponse) error {
+  _, err := writer.Write([]byte{response.version, response.status})
+  return err
+}
+
 const (
 	AddrTypeIPv4   = byte(0x01)
 	AddrTypeIPv6   = byte(0x04)

+ 19 - 1
net/socks/socks.go

@@ -16,6 +16,7 @@ import (
 var (
 	ErrorAuthenticationFailed = errors.New("None of the authentication methods is allowed.")
 	ErrorCommandNotSupported  = errors.New("Client requested an unsupported command.")
+  ErrorInvalidUser = errors.New("Invalid username or password.")
 )
 
 // SocksServer is a SOCKS 5 proxy server
@@ -84,8 +85,25 @@ func (server *SocksServer) HandleConnection(connection net.Conn) error {
 		return ErrorAuthenticationFailed
 	}
 
-	authResponse := socksio.NewAuthenticationResponse(socksio.AuthNotRequired)
+	authResponse := socksio.NewAuthenticationResponse(expectedAuthMethod)
 	socksio.WriteAuthentication(connection, authResponse)
+  
+  if server.config.AuthMethod == JsonAuthMethodUserPass {
+    upRequest, err := socksio.ReadUserPassRequest(reader)
+    if err != nil {
+      log.Error("Failed to read username and password: %v", err)
+      return err
+    }
+    status := byte(0)
+    if ! upRequest.IsValid(server.config.Username, server.config.Password) {
+      status = byte(0xFF)
+    }
+    upResponse := socksio.NewSocks5UserPassResponse(status)
+    socksio.WriteUserPassResponse(connection, upResponse)
+    if status != byte(0) {
+      return ErrorInvalidUser
+    }
+  }
 
 	request, err := socksio.ReadRequest(reader)
 	if err != nil {