@@ -65,28 +65,29 @@ func debugUDPAddr(addr net.Addr, template string, val interface{}) {
65
65
66
66
// Decrypts src into dst. It tries each cipher until it finds one that authenticates
67
67
// correctly. dst and src must not overlap.
68
- func findAccessKeyUDP (clientIP netip.Addr , dst , src []byte , cipherList CipherList ) ([]byte , string , * shadowsocks. EncryptionKey , error ) {
68
+ func findAccessKeyUDP (clientIP netip.Addr , dst , src []byte , cipherList CipherList ) (* CipherEntry , []byte , error ) {
69
69
// Try each cipher until we find one that authenticates successfully. This assumes that all ciphers are AEAD.
70
70
// We snapshot the list because it may be modified while we use it.
71
71
snapshot := cipherList .SnapshotForClientIP (clientIP )
72
- for ci , entry := range snapshot {
73
- id , cryptoKey := entry .Value .(* CipherEntry ). ID , entry . Value .( * CipherEntry ). CryptoKey
74
- buf , err := shadowsocks .Unpack (dst , src , cryptoKey )
72
+ for ci , elt := range snapshot {
73
+ entry := elt .Value .(* CipherEntry )
74
+ buf , err := shadowsocks .Unpack (dst , src , entry . CryptoKey )
75
75
if err != nil {
76
- debugUDP (id , "Failed to unpack: %v" , err )
76
+ debugUDP (entry . ID , "Failed to unpack: %v" , err )
77
77
continue
78
78
}
79
- debugUDP (id , "Found cipher at index %d" , ci )
79
+ debugUDP (entry . ID , "Found cipher at index %d" , ci )
80
80
// Move the active cipher to the front, so that the search is quicker next time.
81
- cipherList .MarkUsedByClientIP (entry , clientIP )
82
- return buf , id , cryptoKey , nil
81
+ cipherList .MarkUsedByClientIP (elt , clientIP )
82
+ return entry , buf , nil
83
83
}
84
- return nil , "" , nil , errors .New ("could not find valid UDP cipher" )
84
+ return nil , nil , errors .New ("could not find valid UDP cipher" )
85
85
}
86
86
87
87
type packetHandler struct {
88
88
natTimeout time.Duration
89
89
ciphers CipherList
90
+ nm * natmap
90
91
m UDPMetrics
91
92
targetIPValidator onet.TargetIPValidator
92
93
}
@@ -113,108 +114,94 @@ func (h *packetHandler) SetTargetIPValidator(targetIPValidator onet.TargetIPVali
113
114
func (h * packetHandler ) Handle (clientConn net.PacketConn ) {
114
115
var running sync.WaitGroup
115
116
116
- nm := newNATmap (h .natTimeout , h .m , & running )
117
- defer nm .Close ()
118
- cipherBuf := make ([]byte , serverUDPBufferSize )
119
- textBuf := make ([]byte , serverUDPBufferSize )
117
+ h .nm = newNATmap (h .natTimeout , h .m , & running )
118
+ defer h .nm .Close ()
120
119
121
120
for {
122
- clientProxyBytes , clientAddr , err := clientConn .ReadFrom (cipherBuf )
123
- if errors .Is (err , net .ErrClosed ) {
124
- break
121
+ status := "OK"
122
+ keyID , clientInfo , clientProxyBytes , proxyTargetBytes , connErr := h .handleConnection (clientConn )
123
+ if connErr != nil {
124
+ if errors .Is (connErr .Cause , net .ErrClosed ) {
125
+ break
126
+ }
127
+ logger .Debugf ("UDP Error: %v: %v" , connErr .Message , connErr .Cause )
128
+ status = connErr .Status
125
129
}
130
+ h .m .AddUDPPacketFromClient (clientInfo , keyID , status , clientProxyBytes , proxyTargetBytes )
131
+ }
132
+ }
126
133
127
- var clientInfo ipinfo.IPInfo
128
- keyID := ""
129
- var proxyTargetBytes int
134
+ func (h * packetHandler ) authenticate (clientConn net.PacketConn ) (* natconn , []byte , int , * onet.ConnectionError ) {
135
+ cipherBuf := make ([]byte , serverUDPBufferSize )
136
+ textBuf := make ([]byte , serverUDPBufferSize )
137
+ clientProxyBytes , clientAddr , err := clientConn .ReadFrom (cipherBuf )
138
+ if err != nil {
139
+ return nil , nil , 0 , onet .NewConnectionError ("ERR_READ" , "Failed to read from client" , err )
140
+ }
130
141
131
- connError := func () (connError * onet.ConnectionError ) {
132
- defer func () {
133
- if r := recover (); r != nil {
134
- logger .Errorf ("Panic in UDP loop: %v. Continuing to listen." , r )
135
- debug .PrintStack ()
136
- }
137
- }()
142
+ if logger .IsEnabledFor (logging .DEBUG ) {
143
+ defer logger .Debugf ("UDP(%v): done" , clientAddr )
144
+ logger .Debugf ("UDP(%v): Outbound packet has %d bytes" , clientAddr , clientProxyBytes )
145
+ }
138
146
139
- // Error from ReadFrom
140
- if err != nil {
141
- return onet .NewConnectionError ("ERR_READ" , "Failed to read from client" , err )
142
- }
143
- if logger .IsEnabledFor (logging .DEBUG ) {
144
- defer logger .Debugf ("UDP(%v): done" , clientAddr )
145
- logger .Debugf ("UDP(%v): Outbound packet has %d bytes" , clientAddr , clientProxyBytes )
146
- }
147
+ targetConn := h .nm .Get (clientAddr .String ())
148
+ remoteIP := clientAddr .(* net.UDPAddr ).AddrPort ().Addr ()
147
149
148
- cipherData := cipherBuf [:clientProxyBytes ]
149
- var payload []byte
150
- var tgtUDPAddr * net.UDPAddr
151
- targetConn := nm .Get (clientAddr .String ())
152
- if targetConn == nil {
153
- var locErr error
154
- clientInfo , locErr = ipinfo .GetIPInfoFromAddr (h .m , clientAddr )
155
- if locErr != nil {
156
- logger .Warningf ("Failed client info lookup: %v" , locErr )
157
- }
158
- debugUDPAddr (clientAddr , "Got info \" %#v\" " , clientInfo )
159
-
160
- ip := clientAddr .(* net.UDPAddr ).AddrPort ().Addr ()
161
- var textData []byte
162
- var cryptoKey * shadowsocks.EncryptionKey
163
- unpackStart := time .Now ()
164
- textData , keyID , cryptoKey , err = findAccessKeyUDP (ip , textBuf , cipherData , h .ciphers )
165
- timeToCipher := time .Since (unpackStart )
166
- h .m .AddUDPCipherSearch (err == nil , timeToCipher )
167
-
168
- if err != nil {
169
- return onet .NewConnectionError ("ERR_CIPHER" , "Failed to unpack initial packet" , err )
170
- }
150
+ unpackStart := time .Now ()
151
+ cipherEntry , textData , keyErr := findAccessKeyUDP (remoteIP , textBuf , cipherBuf [:clientProxyBytes ], h .ciphers )
152
+ timeToCipher := time .Since (unpackStart )
153
+ h .m .AddUDPCipherSearch (err == nil , timeToCipher )
154
+ if keyErr != nil {
155
+ return targetConn , nil , 0 , onet .NewConnectionError ("ERR_CIPHER" , "Failed to find a valid cipher" , keyErr )
156
+ }
171
157
172
- var onetErr * onet.ConnectionError
173
- if payload , tgtUDPAddr , onetErr = h .validatePacket (textData ); onetErr != nil {
174
- return onetErr
175
- }
158
+ if targetConn != nil {
159
+ return targetConn , textData , clientProxyBytes , nil
160
+ }
176
161
177
- udpConn , err := net .ListenPacket ("udp" , "" )
178
- if err != nil {
179
- return onet .NewConnectionError ("ERR_CREATE_SOCKET" , "Failed to create UDP socket" , err )
180
- }
181
- targetConn = nm .Add (clientAddr , clientConn , cryptoKey , udpConn , clientInfo , keyID )
182
- } else {
183
- clientInfo = targetConn .clientInfo
162
+ udpConn , err := net .ListenPacket ("udp" , "" )
163
+ if err != nil {
164
+ return targetConn , textData , clientProxyBytes , onet .NewConnectionError ("ERR_CREATE_SOCKET" , "Failed to create UDP socket" , err )
165
+ }
184
166
185
- unpackStart := time .Now ()
186
- textData , err := shadowsocks .Unpack (nil , cipherData , targetConn .cryptoKey )
187
- timeToCipher := time .Since (unpackStart )
188
- h .m .AddUDPCipherSearch (err == nil , timeToCipher )
167
+ clientInfo , locErr := ipinfo .GetIPInfoFromAddr (h .m , clientAddr )
168
+ if locErr != nil {
169
+ logger .Warningf ("Failed client info lookup: %v" , locErr )
170
+ }
171
+ debugUDPAddr (clientAddr , "Got info \" %#v\" " , clientInfo )
189
172
190
- if err != nil {
191
- return onet . NewConnectionError ( "ERR_CIPHER" , "Failed to unpack data from client" , err )
192
- }
173
+ targetConn = h . nm . Add ( clientAddr , clientConn , cipherEntry . CryptoKey , udpConn , clientInfo , cipherEntry . ID )
174
+ return targetConn , textData , clientProxyBytes , nil
175
+ }
193
176
194
- // The key ID is known with confidence once decryption succeeds.
195
- keyID = targetConn .keyID
177
+ func (h * packetHandler ) handleConnection (clientConn net.PacketConn ) (string , ipinfo.IPInfo , int , int , * onet.ConnectionError ) {
178
+ defer func () {
179
+ if r := recover (); r != nil {
180
+ logger .Errorf ("Panic in UDP loop: %v. Continuing to listen." , r )
181
+ debug .PrintStack ()
182
+ }
183
+ }()
196
184
197
- var onetErr * onet.ConnectionError
198
- if payload , tgtUDPAddr , onetErr = h .validatePacket (textData ); onetErr != nil {
199
- return onetErr
200
- }
201
- }
185
+ targetConn , textData , clientProxyBytes , authErr := h .authenticate (clientConn )
186
+ if authErr != nil {
187
+ var clientInfo ipinfo.IPInfo
188
+ if targetConn != nil {
189
+ clientInfo = targetConn .clientInfo
190
+ }
191
+ return "" , clientInfo , clientProxyBytes , 0 , authErr
192
+ }
202
193
203
- debugUDPAddr (clientAddr , "Proxy exit %v" , targetConn .LocalAddr ())
204
- proxyTargetBytes , err = targetConn .WriteTo (payload , tgtUDPAddr ) // accept only UDPAddr despite the signature
205
- if err != nil {
206
- return onet .NewConnectionError ("ERR_WRITE" , "Failed to write to target" , err )
207
- }
208
- return nil
209
- }()
194
+ payload , tgtUDPAddr , onetErr := h .validatePacket (textData )
195
+ if onetErr != nil {
196
+ return targetConn .keyID , targetConn .clientInfo , clientProxyBytes , 0 , onetErr
197
+ }
210
198
211
- status := "OK"
212
- if connError != nil {
213
- logger .Debugf ("UDP Error: %v: %v" , connError .Message , connError .Cause )
214
- status = connError .Status
215
- }
216
- h .m .AddUDPPacketFromClient (clientInfo , keyID , status , clientProxyBytes , proxyTargetBytes )
199
+ debugUDPAddr (targetConn .clientAddr , "Proxy exit %v" , targetConn .LocalAddr ())
200
+ proxyTargetBytes , err := targetConn .WriteTo (payload , tgtUDPAddr ) // accept only UDPAddr despite the signature
201
+ if err != nil {
202
+ return targetConn .keyID , targetConn .clientInfo , clientProxyBytes , proxyTargetBytes , onet .NewConnectionError ("ERR_WRITE" , "Failed to write to target" , err )
217
203
}
204
+ return targetConn .keyID , targetConn .clientInfo , clientProxyBytes , proxyTargetBytes , nil
218
205
}
219
206
220
207
// Given the decrypted contents of a UDP packet, return
@@ -245,8 +232,9 @@ func isDNS(addr net.Addr) bool {
245
232
246
233
type natconn struct {
247
234
net.PacketConn
248
- cryptoKey * shadowsocks.EncryptionKey
249
- keyID string
235
+ cryptoKey * shadowsocks.EncryptionKey
236
+ keyID string
237
+ clientAddr net.Addr
250
238
// We store the client information in the NAT map to avoid recomputing it
251
239
// for every downstream packet in a UDP-based connection.
252
240
clientInfo ipinfo.IPInfo
@@ -327,19 +315,20 @@ func (m *natmap) Get(key string) *natconn {
327
315
return m .keyConn [key ]
328
316
}
329
317
330
- func (m * natmap ) set (key string , pc net.PacketConn , cryptoKey * shadowsocks.EncryptionKey , keyID string , clientInfo ipinfo.IPInfo ) * natconn {
318
+ func (m * natmap ) set (clientAddr net. Addr , pc net.PacketConn , cryptoKey * shadowsocks.EncryptionKey , keyID string , clientInfo ipinfo.IPInfo ) * natconn {
331
319
entry := & natconn {
332
320
PacketConn : pc ,
333
321
cryptoKey : cryptoKey ,
334
322
keyID : keyID ,
323
+ clientAddr : clientAddr ,
335
324
clientInfo : clientInfo ,
336
325
defaultTimeout : m .timeout ,
337
326
}
338
327
339
328
m .Lock ()
340
329
defer m .Unlock ()
341
330
342
- m .keyConn [key ] = entry
331
+ m .keyConn [clientAddr . String () ] = entry
343
332
return entry
344
333
}
345
334
@@ -356,7 +345,7 @@ func (m *natmap) del(key string) net.PacketConn {
356
345
}
357
346
358
347
func (m * natmap ) Add (clientAddr net.Addr , clientConn net.PacketConn , cryptoKey * shadowsocks.EncryptionKey , targetConn net.PacketConn , clientInfo ipinfo.IPInfo , keyID string ) * natconn {
359
- entry := m .set (clientAddr . String () , targetConn , cryptoKey , keyID , clientInfo )
348
+ entry := m .set (clientAddr , targetConn , cryptoKey , keyID , clientInfo )
360
349
361
350
m .metrics .AddUDPNatEntry (clientAddr , keyID )
362
351
m .running .Add (1 )
0 commit comments