From 019d8266bc66ed2cf30d28a26ec6aea4eda6c523 Mon Sep 17 00:00:00 2001
From: V2Ray <admin@v2ray.com>
Date: Tue, 22 Sep 2015 23:50:05 +0200
Subject: [PATCH] Basic implementation of socks udp listener.

---
 proxy/socks/protocol/udp.go | 20 +++++++-------
 proxy/socks/udp.go          | 52 +++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 10 deletions(-)
 create mode 100644 proxy/socks/udp.go

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)
+	}
+}