소스 검색

🧦 Fix socks client UDP outbound's wrong destination (#522)

- When you connect to a non-localhost socks5 server, in the response of a UdpAssociate from a socks5 server, the remote address may be `::` or `0.0.0.0`. The previous behavior is to connect to the remote address in the response, which obviously fails.
- This commit changes the behavior to dial to the outbound server's address when the remote address in the response is `::` or `0.0.0.0`.
- Rename `cmdUDPPort` to `cmdUDPAssociate` for clarity.
database64128 5 년 전
부모
커밋
0eccf52399
2개의 변경된 파일14개의 추가작업 그리고 4개의 파일을 삭제
  1. 11 1
      proxy/socks/client.go
  2. 3 3
      proxy/socks/protocol.go

+ 11 - 1
proxy/socks/client.go

@@ -53,14 +53,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
 	if outbound == nil || !outbound.Target.IsValid() {
 		return newError("target not specified.")
 	}
+	// Destination of the inner request.
 	destination := outbound.Target
 
+	// Outbound server.
 	var server *protocol.ServerSpec
+	// Outbound server's destination.
+	var dest net.Destination
+	// Connection to the outbound server.
 	var conn internet.Connection
 
 	if err := retry.ExponentialBackoff(5, 100).On(func() error {
 		server = c.serverPicker.PickServer()
-		dest := server.Destination()
+		dest = server.Destination()
 		rawConn, err := dialer.Dial(ctx, dest)
 		if err != nil {
 			return err
@@ -103,6 +108,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
 	if err != nil {
 		return newError("failed to establish connection to server").AtWarning().Base(err)
 	}
+	if udpRequest != nil {
+		if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
+			udpRequest.Address = dest.Address
+		}
+	}
 
 	if err := conn.SetDeadline(time.Time{}); err != nil {
 		newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))

+ 3 - 3
proxy/socks/protocol.go

@@ -18,7 +18,7 @@ const (
 
 	cmdTCPConnect    = 0x01
 	cmdTCPBind       = 0x02
-	cmdUDPPort       = 0x03
+	cmdUDPAssociate  = 0x03
 	cmdTorResolve    = 0xF0
 	cmdTorResolvePTR = 0xF1
 
@@ -164,7 +164,7 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
 	case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
 		// We don't have a solution for Tor case now. Simply treat it as connect command.
 		request.Command = protocol.RequestCommandTCP
-	case cmdUDPPort:
+	case cmdUDPAssociate:
 		if !s.config.UdpEnabled {
 			writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
 			return nil, newError("UDP is not enabled.")
@@ -448,7 +448,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
 
 	command := byte(cmdTCPConnect)
 	if request.Command == protocol.RequestCommandUDP {
-		command = byte(cmdUDPPort)
+		command = byte(cmdUDPAssociate)
 	}
 	common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
 	if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {