diff --git a/proxy/socks/protocol/udp.go b/proxy/socks/protocol/udp.go index b1e59289d..0a70bc76e 100644 --- a/proxy/socks/protocol/udp.go +++ b/proxy/socks/protocol/udp.go @@ -13,18 +13,18 @@ var ( ) type Socks5UDPRequest struct { - fragment byte - address v2net.Address - data []byte + Fragment byte + Address v2net.Address + Data []byte } func (request *Socks5UDPRequest) Destination() v2net.Destination { - return v2net.NewUDPDestination(request.address) + return v2net.NewUDPDestination(request.Address) } func ReadUDPRequest(packet []byte) (request Socks5UDPRequest, err error) { // packet[0] and packet[1] are reserved - request.fragment = packet[2] + request.Fragment = packet[2] addrType := packet[3] var dataBegin int @@ -33,18 +33,18 @@ func ReadUDPRequest(packet []byte) (request Socks5UDPRequest, err error) { case AddrTypeIPv4: ip := packet[4:8] port := binary.BigEndian.Uint16(packet[8:10]) - request.address = v2net.IPAddress(ip, port) + request.Address = v2net.IPAddress(ip, port) dataBegin = 10 case AddrTypeIPv6: ip := packet[4:20] port := binary.BigEndian.Uint16(packet[20:22]) - request.address = v2net.IPAddress(ip, port) + request.Address = v2net.IPAddress(ip, port) dataBegin = 22 case AddrTypeDomain: domainLength := int(packet[4]) domain := string(packet[5 : 5+domainLength]) port := binary.BigEndian.Uint16(packet[5+domainLength : 5+domainLength+2]) - request.address = v2net.DomainAddress(domain, port) + request.Address = v2net.DomainAddress(domain, port) dataBegin = 5 + domainLength + 2 default: log.Warning("Unknown address type %d", addrType) @@ -52,8 +52,8 @@ func ReadUDPRequest(packet []byte) (request Socks5UDPRequest, err error) { return } - request.data = make([]byte, len(packet)-dataBegin) - copy(request.data, packet[dataBegin:]) + request.Data = make([]byte, len(packet)-dataBegin) + copy(request.Data, packet[dataBegin:]) return } diff --git a/proxy/socks/udp.go b/proxy/socks/udp.go new file mode 100644 index 000000000..4bdeea55f --- /dev/null +++ b/proxy/socks/udp.go @@ -0,0 +1,52 @@ +package socks + +import ( + "net" + + "github.com/v2ray/v2ray-core/common/log" + v2net "github.com/v2ray/v2ray-core/common/net" + "github.com/v2ray/v2ray-core/proxy/socks/protocol" +) + +const ( + bufferSize = 2 * 1024 +) + +func (server *SocksServer) ListenUDP(port uint16) error { + addr := &net.UDPAddr{ + IP: net.IP{0, 0, 0, 0}, + Port: int(port), + Zone: "", + } + conn, err := net.ListenUDP("udp", addr) + if err != nil { + log.Error("Socks failed to listen UDP on port %d: %v", port, err) + return err + } + + go server.AcceptPackets(conn) + return nil +} + +func (server *SocksServer) AcceptPackets(conn *net.UDPConn) error { + for { + buffer := make([]byte, 0, bufferSize) + nBytes, _, err := conn.ReadFromUDP(buffer) + if err != nil { + log.Error("Socks failed to read UDP packets: %v", err) + return err + } + request, err := protocol.ReadUDPRequest(buffer[:nBytes]) + if err != nil { + log.Error("Socks failed to parse UDP request: %v", err) + return err + } + if request.Fragment != 0 { + // TODO handle fragments + continue + } + + udpPacket := v2net.NewUDPPacket(request.Destination(), request.Data) + server.vPoint.DispatchToOutbound(udpPacket) + } +}