func (v *Server) handleUDP(reader io.Reader, writer *bufio.BufferedWriter) error { response := protocol.NewSocks5Response() response.Error = protocol.ErrorSuccess udpAddr := v.udpAddress response.Port = udpAddr.Port switch udpAddr.Address.Family() { case v2net.AddressFamilyIPv4: response.SetIPv4(udpAddr.Address.IP()) case v2net.AddressFamilyIPv6: response.SetIPv6(udpAddr.Address.IP()) case v2net.AddressFamilyDomain: response.SetDomain(udpAddr.Address.Domain()) } response.Write(writer) err := writer.Flush() if err != nil { log.Error("Socks: failed to write response: ", err) return err } // The TCP connection closes after v method returns. We need to wait until // the client closes it. // TODO: get notified from UDP part <-time.After(5 * time.Minute) return nil }
func (v *Server) handleSocks5(clientAddr v2net.Destination, reader *bufio.BufferedReader, writer *bufio.BufferedWriter, auth protocol.Socks5AuthenticationRequest) error { expectedAuthMethod := protocol.AuthNotRequired if v.config.AuthType == AuthType_PASSWORD { expectedAuthMethod = protocol.AuthUserPass } if !auth.HasAuthMethod(expectedAuthMethod) { authResponse := protocol.NewAuthenticationResponse(protocol.AuthNoMatchingMethod) err := protocol.WriteAuthentication(writer, authResponse) writer.Flush() if err != nil { log.Warning("Socks: failed to write authentication: ", err) return err } log.Warning("Socks: client doesn't support any allowed auth methods.") return ErrUnsupportedAuthMethod } authResponse := protocol.NewAuthenticationResponse(expectedAuthMethod) protocol.WriteAuthentication(writer, authResponse) err := writer.Flush() if err != nil { log.Error("Socks: failed to write authentication: ", err) return err } if v.config.AuthType == AuthType_PASSWORD { upRequest, err := protocol.ReadUserPassRequest(reader) if err != nil { log.Warning("Socks: failed to read username and password: "******"Socks: failed to write user pass response: ", err) return err } if status != byte(0) { log.Warning("Socks: Invalid user account: ", upRequest.AuthDetail()) log.Access(clientAddr, "", log.AccessRejected, crypto.ErrAuthenticationFailed) return crypto.ErrAuthenticationFailed } } request, err := protocol.ReadRequest(reader) if err != nil { log.Warning("Socks: failed to read request: ", err) return err } if request.Command == protocol.CmdUdpAssociate && v.config.UdpEnabled { return v.handleUDP(reader, writer) } if request.Command == protocol.CmdBind || request.Command == protocol.CmdUdpAssociate { response := protocol.NewSocks5Response() response.Error = protocol.ErrorCommandNotSupported response.Port = v2net.Port(0) response.SetIPv4([]byte{0, 0, 0, 0}) response.Write(writer) writer.Flush() if err != nil { log.Error("Socks: failed to write response: ", err) return err } log.Warning("Socks: Unsupported socks command ", request.Command) return ErrUnsupportedSocksCommand } response := protocol.NewSocks5Response() response.Error = protocol.ErrorSuccess // Some SOCKS software requires a value other than dest. Let's fake one: response.Port = v2net.Port(1717) response.SetIPv4([]byte{0, 0, 0, 0}) response.Write(writer) if err != nil { log.Error("Socks: failed to write response: ", err) return err } reader.SetCached(false) writer.SetCached(false) dest := request.Destination() session := &proxy.SessionInfo{ Source: clientAddr, Destination: dest, Inbound: v.meta, } log.Info("Socks: TCP Connect request to ", dest) log.Access(clientAddr, dest, log.AccessAccepted, "") v.transport(reader, writer, session) return nil }