33# SPDX-License-Identifier: Apache-2.0 OR MIT
44# Copyright (c) Status Research & Development GmbH
55
6- import chronos, net
6+ import chronos, net, sequtils
77import
88 ../../../ libp2p/ [
99 switch,
10+ multiaddress,
1011 transports/ tcptransport,
1112 upgrademngrs/ upgrade,
1213 builders,
@@ -19,16 +20,13 @@ import
1920import ../../ tools/ [unittest, crypto, switch_builder, multiaddress]
2021
2122proc setupAutonat (
22- srcAddrs: seq [MultiAddress ] = newSeq [MultiAddress ](),
23+ srcAddrs: seq [MultiAddress ] = @ [TcpAutoAddress ],
24+ dstAddrs: seq [MultiAddress ] = @ [TcpAutoAddress ],
2325 config: AutonatV2Config = AutonatV2Config .new (),
2426): Future [(Switch , Switch , AutonatV2Client )] {.async .} =
25- var srcBuilder = makeStandardSwitchBuilder (TcpAutoAddress )
26- if srcAddrs.len > 0 :
27- srcBuilder = srcBuilder.withAddresses (srcAddrs)
28-
2927 let
30- src = srcBuilder .build ()
31- dst = makeStandardSwitchBuilder (TcpAutoAddress ).withAutonatV2Server (config).build ()
28+ src = makeStandardSwitchBuilder (srcAddrs) .build ()
29+ dst = makeStandardSwitchBuilder (dstAddrs ).withAutonatV2Server (config).build ()
3230 client = AutonatV2Client .new (rng ())
3331
3432 client.setup (src)
@@ -70,7 +68,7 @@ suite "AutonatV2":
7068 ) == Reachable
7169
7270 asyncTest " asAutonatV2Response" :
73- let addrs = @ [MultiAddress . init (" /ip4/127.0.0.1/tcp/4000" ). get ( )]
71+ let addrs = @ [ma (" /ip4/127.0.0.1/tcp/4000" )]
7472 let errorDialResp = DialResponse (
7573 status: ResponseStatus .Ok ,
7674 addrIdx: Opt .none (AddrIdx ),
@@ -137,8 +135,7 @@ suite "AutonatV2":
137135 # use ip address other than 127.0.0.1 for client
138136 let
139137 listenAddrs = @ [
140- MultiAddress .init (" /ip4/" & checkedGetIPAddress () & " /tcp/4040" ).get (),
141- MultiAddress .init (" /ip4/127.0.0.1/tcp/4040" ).get (),
138+ ma (" /ip4/" & checkedGetIPAddress () & " /tcp/4040" ), ma (" /ip4/127.0.0.1/tcp/4040" )
142139 ]
143140 reqAddrs = @ [listenAddrs[0 ]]
144141 (src, dst, client) = await setupAutonat (srcAddrs = listenAddrs)
@@ -163,9 +160,7 @@ suite "AutonatV2":
163160 await allFutures (src.stop (), dst.stop ())
164161
165162 check (
166- await client.sendDialRequest (
167- dst.peerInfo.peerId, @ [MultiAddress .init (" /ip4/1.1.1.1/tcp/4040" ).get ()]
168- )
163+ await client.sendDialRequest (dst.peerInfo.peerId, @ [ma (" /ip4/1.1.1.1/tcp/4040" )])
169164 ) ==
170165 AutonatV2Response (
171166 reachability: NotReachable ,
@@ -174,17 +169,16 @@ suite "AutonatV2":
174169 dialStatus: Opt .some (DialStatus .EDialError ),
175170 addrIdx: Opt .some (0 .AddrIdx ),
176171 ),
177- addrs: Opt .some (MultiAddress . init (" /ip4/1.1.1.1/tcp/4040" ). get ( )),
172+ addrs: Opt .some (ma (" /ip4/1.1.1.1/tcp/4040" )),
178173 )
179174
180175 asyncTest " Failed DialRequest with amplification attack prevention" :
181176 # use ip address other than 127.0.0.1 for client
182177 let
183178 listenAddrs = @ [
184- MultiAddress .init (" /ip4/" & checkedGetIPAddress () & " /tcp/4040" ).get (),
185- MultiAddress .init (" /ip4/127.0.0.1/tcp/4040" ).get (),
179+ ma (" /ip4/" & checkedGetIPAddress () & " /tcp/4040" ), ma (" /ip4/127.0.0.1/tcp/4040" )
186180 ]
187- reqAddrs = @ [MultiAddress . init (" /ip4/1.1.1.1/tcp/4040" ). get ( )]
181+ reqAddrs = @ [ma (" /ip4/1.1.1.1/tcp/4040" )]
188182 (src, dst, client) = await setupAutonat (
189183 srcAddrs = listenAddrs, config = AutonatV2Config .new (dialTimeout = 1 .seconds)
190184 )
@@ -202,13 +196,122 @@ suite "AutonatV2":
202196 addrs: Opt .some (reqAddrs[0 ]),
203197 )
204198
199+ asyncTest " DialRequest with IPv6 addr refused by IPv4-only server" :
200+ # server listens on IPv4 only, so it refuses to dial any IPv6 addr
201+ let (src, dst, client) = await setupAutonat ()
202+ defer :
203+ await allFutures (src.stop (), dst.stop ())
204+
205+ let reqAddrs = @ [ma (" /ip6/2001:db8::1/tcp/4040" )]
206+ check (await client.sendDialRequest (dst.peerInfo.peerId, reqAddrs)) ==
207+ AutonatV2Response (
208+ reachability: Unknown ,
209+ dialResp: DialResponse (
210+ status: EDialRefused ,
211+ addrIdx: Opt .none (AddrIdx ),
212+ dialStatus: Opt .none (DialStatus ),
213+ ),
214+ addrs: Opt .none (MultiAddress ),
215+ )
216+
217+ asyncTest " DialRequest with IPv4 addr refused by IPv6-only server" :
218+ # server listens on IPv6 only, so it refuses to dial any IPv4 addr
219+ let (src, dst, client) = await setupAutonat (dstAddrs = @ [TcpAutoAddressIP6 ])
220+ defer :
221+ await allFutures (src.stop (), dst.stop ())
222+
223+ let reqAddrs = @ [ma (" /ip4/1.1.1.1/tcp/4040" )]
224+ check (await client.sendDialRequest (dst.peerInfo.peerId, reqAddrs)) ==
225+ AutonatV2Response (
226+ reachability: Unknown ,
227+ dialResp: DialResponse (
228+ status: EDialRefused ,
229+ addrIdx: Opt .none (AddrIdx ),
230+ dialStatus: Opt .none (DialStatus ),
231+ ),
232+ addrs: Opt .none (MultiAddress ),
233+ )
234+
235+ asyncTest " DialRequest with private IPv6 addr succeeds despite allowPrivateAddresses=false" :
236+ # TODO : nim-libp2p#2710
237+ # isPrivate classifies every IPv6 address as non-private
238+ # the server therefore dials back the loopback IPv6 addr instead of refusing it
239+ let
240+ dualStackAddrs = @ [TcpAutoAddressIP4 , TcpAutoAddressIP6 ]
241+ (src, dst, client) =
242+ await setupAutonat (srcAddrs = dualStackAddrs, dstAddrs = dualStackAddrs)
243+ defer :
244+ await allFutures (src.stop (), dst.stop ())
245+
246+ # request only the IPv6 listen addr of the client
247+ let reqAddrs = src.peerInfo.addrs.filterIt (TCP_IP6 .match (it))
248+ check reqAddrs.len == 1
249+
250+ check (await client.sendDialRequest (dst.peerInfo.peerId, reqAddrs)) ==
251+ AutonatV2Response (
252+ reachability: Reachable ,
253+ dialResp: DialResponse (
254+ status: ResponseStatus .Ok ,
255+ dialStatus: Opt .some (DialStatus .Ok ),
256+ addrIdx: Opt .some (0 .AddrIdx ),
257+ ),
258+ addrs: Opt .some (reqAddrs[0 ]),
259+ )
260+
261+ asyncTest " Amplification attack prevention skipped when observed IPv4 addr matches a requested addr" :
262+ # the requested addr matches the observed addr of the client,
263+ # so the server dials back right away without demanding dial data
264+ # dialDataSize is set above what the client accepts to prove the skip:
265+ # a DialDataRequest would have failed the request with AutonatV2Error
266+ let (src, dst, client) = await setupAutonat (
267+ config = AutonatV2Config .new (
268+ dialDataSize = (MaxAcceptedDialDataRequest + 1 ).uint64 ,
269+ allowPrivateAddresses = true ,
270+ )
271+ )
272+ defer :
273+ await allFutures (src.stop (), dst.stop ())
274+
275+ check (await client.sendDialRequest (dst.peerInfo.peerId, src.peerInfo.addrs)) ==
276+ AutonatV2Response (
277+ reachability: Reachable ,
278+ dialResp: DialResponse (
279+ status: ResponseStatus .Ok ,
280+ dialStatus: Opt .some (DialStatus .Ok ),
281+ addrIdx: Opt .some (0 .AddrIdx ),
282+ ),
283+ addrs: Opt .some (src.peerInfo.addrs[0 ]),
284+ )
285+
286+ asyncTest " Amplification attack prevention not skipped when observed IPv6 addr matches a requested addr" :
287+ # TODO : nim-libp2p#2731
288+ # the requested addr matches the observed addr of the client,
289+ # yet the server demands dial data before the dial back
290+ # dialDataSize is set above what the client accepts to prove the demand:
291+ # the DialDataRequest fails the request with AutonatV2Error
292+ let
293+ ipv6Addrs = @ [TcpAutoAddressIP6 ]
294+ (src, dst, client) = await setupAutonat (
295+ srcAddrs = ipv6Addrs,
296+ dstAddrs = ipv6Addrs,
297+ config = AutonatV2Config .new (
298+ dialDataSize = (MaxAcceptedDialDataRequest + 1 ).uint64 ,
299+ allowPrivateAddresses = true ,
300+ ),
301+ )
302+ defer :
303+ await allFutures (src.stop (), dst.stop ())
304+
305+ expect (AutonatV2Error ):
306+ discard await client.sendDialRequest (dst.peerInfo.peerId, src.peerInfo.addrs)
307+
205308 asyncTest " Server responding with invalid messages" :
206309 let
207310 src = makeStandardSwitch ()
208311 dst = makeStandardSwitch ()
209312 client = AutonatV2Client .new (rng ())
210313 autonatV2Mock = AutonatV2Mock .new ()
211- reqAddrs = @ [MultiAddress . init (" /ip4/127.0.0.1/tcp/4040" ). get ( )]
314+ reqAddrs = @ [ma (" /ip4/127.0.0.1/tcp/4040" )]
212315
213316 client.setup (src)
214317 dst.mount (autonatV2Mock)
0 commit comments