@@ -14,12 +14,12 @@ import (
1414)
1515
1616var (
17- errNATRequriesMapping = errors .New ("1:1 NAT requires more than one mapping" )
18- errMismatchLengthIP = errors .New ("length mismtach between mappedIPs and localIPs" )
19- errNonUDPTranslationNotSupported = errors .New ("non-udp translation is not supported yet " )
20- errNoAssociatedLocalAddress = errors .New ("no associated local address" )
21- errNoNATBindingFound = errors .New ("no NAT binding found" )
22- errHasNoPermission = errors .New ("has no permission" )
17+ errNATRequiresMapping = errors .New ("1:1 NAT requires at least one mapping" )
18+ errMismatchLengthIP = errors .New ("length mismatch between mappedIPs and localIPs" )
19+ errTranslationNotSupported = errors .New ("translation is not supported for this protocol " )
20+ errNoAssociatedLocalAddress = errors .New ("no associated local address" )
21+ errNoNATBindingFound = errors .New ("no NAT binding found" )
22+ errHasNoPermission = errors .New ("has no permission" )
2323)
2424
2525// EndpointDependencyType defines a type of behavioral dependendency on the
@@ -92,6 +92,7 @@ type networkAddressTranslator struct {
9292 outboundMap map [string ]* mapping // key: "<proto>:<local-ip>:<local-port>[:remote-ip[:remote-port]]
9393 inboundMap map [string ]* mapping // key: "<proto>:<mapped-ip>:<mapped-port>"
9494 udpPortCounter int
95+ tcpPortCounter int
9596 mutex sync.RWMutex
9697 log logging.LeveledLogger
9798}
@@ -107,7 +108,7 @@ func newNAT(config *natConfig) (*networkAddressTranslator, error) {
107108 natType .MappingLifeTime = 0
108109
109110 if len (config .mappedIPs ) == 0 {
110- return nil , errNATRequriesMapping
111+ return nil , errNATRequiresMapping
111112 }
112113 if len (config .mappedIPs ) != len (config .localIPs ) {
113114 return nil , errMismatchLengthIP
@@ -151,13 +152,73 @@ func (n *networkAddressTranslator) getPairedLocalIP(mappedIP net.IP) net.IP {
151152 return nil
152153}
153154
154- func (n * networkAddressTranslator ) translateOutbound (from Chunk ) (Chunk , error ) { //nolint:cyclop
155+ func (n * networkAddressTranslator ) translateOutbound (from Chunk ) (Chunk , error ) { //nolint:cyclop,gocognit
155156 n .mutex .Lock ()
156157 defer n .mutex .Unlock ()
157158
158159 to := from .Clone ()
159160
160- if from .Network () == udp { //nolint:nestif
161+ translateOutboundNAPT := func (proto string , portBase int , portCounter * int ) (Chunk , error ) {
162+ var bound , filterKey string
163+ switch n .natType .MappingBehavior {
164+ case EndpointIndependent :
165+ bound = ""
166+ case EndpointAddrDependent :
167+ bound = from .getDestinationIP ().String ()
168+ case EndpointAddrPortDependent :
169+ bound = from .DestinationAddr ().String ()
170+ }
171+
172+ switch n .natType .FilteringBehavior {
173+ case EndpointIndependent :
174+ filterKey = ""
175+ case EndpointAddrDependent :
176+ filterKey = from .getDestinationIP ().String ()
177+ case EndpointAddrPortDependent :
178+ filterKey = from .DestinationAddr ().String ()
179+ }
180+
181+ oKey := fmt .Sprintf ("%s:%s:%s" , proto , from .SourceAddr ().String (), bound )
182+
183+ mapp := n .findOutboundMapping (oKey )
184+ if mapp == nil {
185+ mappedPort := portBase + * portCounter
186+ if mappedPort > 65535 {
187+ return nil , errPortSpaceExhausted
188+ }
189+ (* portCounter )++
190+
191+ mapp = & mapping {
192+ proto : from .SourceAddr ().Network (),
193+ local : from .SourceAddr ().String (),
194+ bound : bound ,
195+ mapped : fmt .Sprintf ("%s:%d" , n .mappedIPs [0 ].String (), mappedPort ),
196+ filters : map [string ]struct {}{},
197+ expires : time .Now ().Add (n .natType .MappingLifeTime ),
198+ }
199+
200+ n .outboundMap [oKey ] = mapp
201+ iKey := fmt .Sprintf ("%s:%s" , proto , mapp .mapped )
202+
203+ n .log .Debugf ("[%s] created a new NAT binding oKey=%s iKey=%s" , n .name , oKey , iKey )
204+
205+ mapp .filters [filterKey ] = struct {}{}
206+ n .log .Debugf ("[%s] permit access from %s to %s" , n .name , filterKey , mapp .mapped )
207+ n .inboundMap [iKey ] = mapp
208+ } else if _ , ok := mapp .filters [filterKey ]; ! ok {
209+ n .log .Debugf ("[%s] permit access from %s to %s" , n .name , filterKey , mapp .mapped )
210+ mapp .filters [filterKey ] = struct {}{}
211+ }
212+
213+ if err := to .setSourceAddr (mapp .mapped ); err != nil {
214+ return nil , err
215+ }
216+
217+ return to , nil
218+ }
219+
220+ switch from .Network () {
221+ case udp :
161222 if n .natType .Mode == NATModeNAT1To1 {
162223 // 1:1 NAT behavior
163224 srcAddr := from .SourceAddr ().(* net.UDPAddr ) //nolint:forcetypeassert
@@ -172,132 +233,145 @@ func (n *networkAddressTranslator) translateOutbound(from Chunk) (Chunk, error)
172233 return nil , err
173234 }
174235 } else {
175- // Normal (NAPT) behavior
176- var bound , filterKey string
177- switch n .natType .MappingBehavior {
178- case EndpointIndependent :
179- bound = ""
180- case EndpointAddrDependent :
181- bound = from .getDestinationIP ().String ()
182- case EndpointAddrPortDependent :
183- bound = from .DestinationAddr ().String ()
236+ var err error
237+ to , err = translateOutboundNAPT ("udp" , 0xC000 , & n .udpPortCounter )
238+ if err != nil {
239+ return nil , err
184240 }
241+ }
185242
186- switch n .natType .FilteringBehavior {
187- case EndpointIndependent :
188- filterKey = ""
189- case EndpointAddrDependent :
190- filterKey = from .getDestinationIP ().String ()
191- case EndpointAddrPortDependent :
192- filterKey = from .DestinationAddr ().String ()
193- }
243+ n .log .Debugf ("[%s] translate outbound chunk from %s to %s" , n .name , from .String (), to .String ())
194244
195- oKey := fmt .Sprintf ("udp:%s:%s" , from .SourceAddr ().String (), bound )
196-
197- mapp := n .findOutboundMapping (oKey )
198- if mapp == nil {
199- // Create a new mapping
200- mappedPort := 0xC000 + n .udpPortCounter
201- n .udpPortCounter ++
202-
203- mapp = & mapping {
204- proto : from .SourceAddr ().Network (),
205- local : from .SourceAddr ().String (),
206- bound : bound ,
207- mapped : fmt .Sprintf ("%s:%d" , n .mappedIPs [0 ].String (), mappedPort ),
208- filters : map [string ]struct {}{},
209- expires : time .Now ().Add (n .natType .MappingLifeTime ),
210- }
211-
212- n .outboundMap [oKey ] = mapp
213-
214- iKey := fmt .Sprintf ("udp:%s" , mapp .mapped )
215-
216- n .log .Debugf ("[%s] created a new NAT binding oKey=%s iKey=%s" ,
217- n .name ,
218- oKey ,
219- iKey )
220-
221- mapp .filters [filterKey ] = struct {}{}
222- n .log .Debugf ("[%s] permit access from %s to %s" , n .name , filterKey , mapp .mapped )
223- n .inboundMap [iKey ] = mapp
224- } else if _ , ok := mapp .filters [filterKey ]; ! ok {
225- n .log .Debugf ("[%s] permit access from %s to %s" , n .name , filterKey , mapp .mapped )
226- mapp .filters [filterKey ] = struct {}{}
227- }
245+ return to , nil
228246
229- if err := to .setSourceAddr (mapp .mapped ); err != nil {
247+ case tcp :
248+ if n .natType .Mode == NATModeNAT1To1 {
249+ srcAddr := from .SourceAddr ().(* net.TCPAddr ) //nolint:forcetypeassert
250+ srcIP := n .getPairedMappedIP (srcAddr .IP )
251+ if srcIP == nil {
252+ n .log .Debugf ("[%s] drop outbound chunk %s with not route" , n .name , from .String ())
253+
254+ return nil , nil // nolint:nilnil
255+ }
256+ srcPort := srcAddr .Port
257+ if err := to .setSourceAddr (fmt .Sprintf ("%s:%d" , srcIP .String (), srcPort )); err != nil {
258+ return nil , err
259+ }
260+ } else {
261+ var err error
262+ to , err = translateOutboundNAPT ("tcp" , 0x8000 , & n .tcpPortCounter )
263+ if err != nil {
230264 return nil , err
231265 }
232266 }
233267
234268 n .log .Debugf ("[%s] translate outbound chunk from %s to %s" , n .name , from .String (), to .String ())
235269
236270 return to , nil
237- }
238271
239- return nil , errNonUDPTranslationNotSupported
272+ default :
273+ return nil , errTranslationNotSupported
274+ }
240275}
241276
242- func (n * networkAddressTranslator ) translateInbound (from Chunk ) (Chunk , error ) { //nolint:cyclop
277+ func (n * networkAddressTranslator ) translateInbound (from Chunk ) (Chunk , error ) { //nolint:cyclop,gocognit
243278 n .mutex .Lock ()
244279 defer n .mutex .Unlock ()
245280
246281 to := from .Clone ()
247282
248- if from .Network () == udp { //nolint:nestif
283+ translateInboundNAT1To1 := func (dstPort int ) (Chunk , error ) {
284+ dstIP := n .getPairedLocalIP (from .getDestinationIP ())
285+ if dstIP == nil {
286+ return nil , fmt .Errorf ("drop %s as %w" , from .String (), errNoAssociatedLocalAddress )
287+ }
288+ if err := to .setDestinationAddr (fmt .Sprintf ("%s:%d" , dstIP , dstPort )); err != nil {
289+ return nil , err
290+ }
291+
292+ return to , nil
293+ }
294+
295+ translateInboundNAPT := func (proto string ) (Chunk , error ) {
296+ iKey := fmt .Sprintf ("%s:%s" , proto , from .DestinationAddr ().String ())
297+ mapp := n .findInboundMapping (iKey )
298+ if mapp == nil {
299+ return nil , fmt .Errorf ("drop %s as %w" , from .String (), errNoNATBindingFound )
300+ }
301+
302+ var filterKey string
303+ switch n .natType .FilteringBehavior {
304+ case EndpointIndependent :
305+ filterKey = ""
306+ case EndpointAddrDependent :
307+ filterKey = from .getSourceIP ().String ()
308+ case EndpointAddrPortDependent :
309+ filterKey = from .SourceAddr ().String ()
310+ }
311+
312+ if _ , ok := mapp .filters [filterKey ]; ! ok {
313+ return nil , fmt .Errorf ("drop %s as the remote %s %w" , from .String (), filterKey , errHasNoPermission )
314+ }
315+
316+ // See RFC 4847 Section 4.3. Mapping Refresh
317+ // a) Inbound refresh may be useful for applications with no outgoing
318+ // UDP traffic. However, allowing inbound refresh may allow an
319+ // external attacker or misbehaving application to keep a mapping
320+ // alive indefinitely. This may be a security risk. Also, if the
321+ // process is repeated with different ports, over time, it could
322+ // use up all the ports on the NAT.
323+
324+ if err := to .setDestinationAddr (mapp .local ); err != nil {
325+ return nil , err
326+ }
327+
328+ return to , nil
329+ }
330+
331+ switch from .Network () {
332+ case udp :
249333 if n .natType .Mode == NATModeNAT1To1 {
250- // 1:1 NAT behavior
251334 dstAddr := from .DestinationAddr ().(* net.UDPAddr ) //nolint:forcetypeassert
252- dstIP := n .getPairedLocalIP (dstAddr .IP )
253- if dstIP == nil {
254- return nil , fmt .Errorf ("drop %s as %w" , from .String (), errNoAssociatedLocalAddress )
255- }
256- dstPort := from .DestinationAddr ().(* net.UDPAddr ).Port //nolint:forcetypeassert
257- if err := to .setDestinationAddr (fmt .Sprintf ("%s:%d" , dstIP , dstPort )); err != nil {
335+ var err error
336+ to , err = translateInboundNAT1To1 (dstAddr .Port )
337+ if err != nil {
258338 return nil , err
259339 }
260340 } else {
261- // Normal (NAPT) behavior
262- iKey := fmt .Sprintf ("udp:%s" , from .DestinationAddr ().String ())
263- mapping := n .findInboundMapping (iKey )
264- if mapping == nil {
265- return nil , fmt .Errorf ("drop %s as %w" , from .String (), errNoNATBindingFound )
266- }
267-
268- var filterKey string
269- switch n .natType .FilteringBehavior {
270- case EndpointIndependent :
271- filterKey = ""
272- case EndpointAddrDependent :
273- filterKey = from .getSourceIP ().String ()
274- case EndpointAddrPortDependent :
275- filterKey = from .SourceAddr ().String ()
341+ var err error
342+ to , err = translateInboundNAPT (udp )
343+ if err != nil {
344+ return nil , err
276345 }
346+ }
277347
278- if _ , ok := mapping .filters [filterKey ]; ! ok {
279- return nil , fmt .Errorf ("drop %s as the remote %s %w" , from .String (), filterKey , errHasNoPermission )
280- }
348+ n .log .Debugf ("[%s] translate inbound chunk from %s to %s" , n .name , from .String (), to .String ())
281349
282- // See RFC 4847 Section 4.3. Mapping Refresh
283- // a) Inbound refresh may be useful for applications with no outgoing
284- // UDP traffic. However, allowing inbound refresh may allow an
285- // external attacker or misbehaving application to keep a mapping
286- // alive indefinitely. This may be a security risk. Also, if the
287- // process is repeated with different ports, over time, it could
288- // use up all the ports on the NAT.
350+ return to , nil
289351
290- if err := to .setDestinationAddr (mapping .local ); err != nil {
352+ case tcp :
353+ if n .natType .Mode == NATModeNAT1To1 {
354+ dstAddr := from .DestinationAddr ().(* net.TCPAddr ) //nolint:forcetypeassert
355+ var err error
356+ to , err = translateInboundNAT1To1 (dstAddr .Port )
357+ if err != nil {
358+ return nil , err
359+ }
360+ } else {
361+ var err error
362+ to , err = translateInboundNAPT (tcp )
363+ if err != nil {
291364 return nil , err
292365 }
293366 }
294367
295368 n .log .Debugf ("[%s] translate inbound chunk from %s to %s" , n .name , from .String (), to .String ())
296369
297370 return to , nil
298- }
299371
300- return nil , errNonUDPTranslationNotSupported
372+ default :
373+ return nil , errTranslationNotSupported
374+ }
301375}
302376
303377// caller must hold the mutex.
0 commit comments