-
Notifications
You must be signed in to change notification settings - Fork 1
/
udp.go
167 lines (151 loc) · 5.21 KB
/
udp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package socks5
import (
"context"
"errors"
"fmt"
"net"
"sync"
)
const maxUDPPacketSize = 2 * 1024
var udpClientSrcAddr = &net.UDPAddr{IP: net.IPv4zero, Port: 0}
var udpPacketBufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, maxUDPPacketSize)
},
}
func getUDPPacketBuffer() []byte {
return udpPacketBufferPool.Get().([]byte)
}
func putUDPPacketBuffer(p []byte) {
p = p[:cap(p)]
udpPacketBufferPool.Put(&p)
}
//FIXME: insecure implementation of UDP server, anyone could send package here without authentication
func (s *Server) handleUDP(udpConn *net.UDPConn) {
for {
buffer := getUDPPacketBuffer()
n, src, err := udpConn.ReadFromUDP(buffer)
if err != nil {
s.config.Logger.Printf("udp socks: Failed to accept udp traffic: %v", err)
}
buffer = buffer[:n]
go func() {
defer putUDPPacketBuffer(buffer)
s.serveUDPConn(buffer, func(data []byte) error {
_, err := udpConn.WriteToUDP(data, src)
return err
})
}()
}
}
/*********************************************************
UDP PACKAGE to proxy
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
**********************************************************/
// ErrUDPFragmentNoSupported UDP fragments not supported error
var ErrUDPFragmentNoSupported = errors.New("")
func (s *Server) serveUDPConn(udpPacket []byte, reply func([]byte) error) error {
// RSV Reserved X'0000'
// FRAG Current fragment number, donnot support fragment here
header := []byte{0, 0, 0}
if len(udpPacket) <= 3 {
err := fmt.Errorf("short UDP package header, %d bytes only", len(udpPacket))
s.config.Logger.Printf("udp socks: Failed to get UDP package header: %v", err)
return err
}
if header[0] != 0x00 || header[1] != 0x00 {
err := fmt.Errorf("unsupported socks UDP package header, %+v", header[:2])
s.config.Logger.Printf("udp socks: Failed to parse UDP package header: %v", err)
return err
}
if header[2] != 0x00 {
s.config.Logger.Printf("udp socks: %+v", ErrUDPFragmentNoSupported)
return ErrUDPFragmentNoSupported
}
// Read in the destination address
targetAddrRaw := udpPacket[3:]
targetAddrSpec := &AddrSpec{}
targetAddrRawSize := 0
errShortAddrRaw := func() error {
err := fmt.Errorf("short UDP package Addr. header, %d bytes only", len(targetAddrRaw))
s.config.Logger.Printf("udp socks: Failed to get UDP package header: %v", err)
return err
}
if len(targetAddrRaw) < 1+4+2 /* ATYP + DST.ADDR.IPV4 + DST.PORT */ {
return errShortAddrRaw()
}
targetAddrRawSize = 1
switch targetAddrRaw[0] {
case AddressIPv4:
targetAddrSpec.IP = net.IP(targetAddrRaw[targetAddrRawSize : targetAddrRawSize+4])
targetAddrRawSize += 4
case AddressIPv6:
if len(targetAddrRaw) < 1+16+2 {
return errShortAddrRaw()
}
targetAddrSpec.IP = net.IP(targetAddrRaw[1 : 1+16])
targetAddrRawSize += 16
case AddressDomainName:
addrLen := int(targetAddrRaw[1])
if len(targetAddrRaw) < 1+1+addrLen+2 {
return errShortAddrRaw()
}
targetAddrSpec.FQDN = string(targetAddrRaw[1+1 : 1+1+addrLen])
targetAddrRawSize += (1 + addrLen)
default:
s.config.Logger.Printf("udp socks: Failed to get UDP package header: %v", errUnrecognizedAddrType)
return errUnrecognizedAddrType
}
targetAddrSpec.Port = (int(targetAddrRaw[targetAddrRawSize]) << 8) | int(targetAddrRaw[targetAddrRawSize+1])
targetAddrRawSize += 2
targetAddrRaw = targetAddrRaw[:targetAddrRawSize]
// resolve addr.
if targetAddrSpec.FQDN != "" {
_, addr, err := s.config.Resolver.Resolve(context.TODO(), targetAddrSpec.FQDN)
if err != nil {
err := fmt.Errorf("failed to resolve destination '%v': %v", targetAddrSpec.FQDN, err)
s.config.Logger.Printf("udp socks: %+v", err)
return err
}
targetAddrSpec.IP = addr
}
// make a writer and write to dst
targetUDPAddr, err := net.ResolveUDPAddr("udp", targetAddrSpec.Address())
if err != nil {
err := fmt.Errorf("failed to resolve destination UDP Addr '%v': %v", targetAddrSpec.Address(), err)
return err
}
target, err := net.DialUDP("udp", udpClientSrcAddr, targetUDPAddr)
if err != nil {
err = fmt.Errorf("connect to %v failed: %v", targetUDPAddr, err)
s.config.Logger.Printf("udp socks: %+v", err)
return err
}
defer target.Close()
// write data to target and read the response back
if _, err := target.Write(udpPacket[len(header)+len(targetAddrRaw):]); err != nil {
s.config.Logger.Printf("udp socks: fail to write udp data to dest %s: %+v",
targetUDPAddr.String(), err)
return err
}
respBuffer := getUDPPacketBuffer()
defer putUDPPacketBuffer(respBuffer)
copy(respBuffer[0:len(header)], header)
copy(respBuffer[len(header):len(header)+len(targetAddrRaw)], targetAddrRaw)
n, err := target.Read(respBuffer[len(header)+len(targetAddrRaw):])
if err != nil {
s.config.Logger.Printf("udp socks: fail to read udp resp from dest %s: %+v",
targetUDPAddr.String(), err)
return err
}
respBuffer = respBuffer[:len(header)+len(targetAddrRaw)+n]
if reply(respBuffer); err != nil {
s.config.Logger.Printf("udp socks: fail to send udp resp back: %+v", err)
return err
}
return nil
}