Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

139 lines
4.6 KiB
Nim
Raw Normal View History

2026-05-19 14:59:23 +04:00
import std/[net]
import pkg/chronos
import pkg/libp2p/[multiaddress, multihash, multicodec]
2026-06-04 14:36:12 +04:00
import pkg/libp2p/protocols/connectivity/autonat/types
2026-04-22 12:21:43 +04:00
import pkg/libp2p/protocols/connectivity/relay/client as relayClientModule
2026-05-22 22:54:07 +04:00
import pkg/libp2p/protocols/connectivity/dcutr/core as dcutrCore
import pkg/libp2p/multistream
2026-04-22 12:21:43 +04:00
import pkg/libp2p/services/autorelayservice except setup
import pkg/results
2026-04-22 12:21:43 +04:00
import ./helpers
import ../asynctest
2026-05-12 10:03:54 +04:00
import ../../storage/utils/natutils
import ../../storage/nat
import ../../storage/discovery
import ../../storage/rng
import ../../storage/utils
type MockNatPortMapper = ref object of NatPortMapper
2026-05-19 14:59:23 +04:00
mappedPorts: Option[(Port, Port, MappingProtocol)]
2026-05-08 14:56:42 +04:00
method mapNatPorts*(
m: MockNatPortMapper
2026-05-19 14:59:23 +04:00
): Future[Option[(Port, Port, MappingProtocol)]] {.
async: (raises: [CancelledError]), gcsafe
.} =
m.mappedPorts
2026-06-04 14:36:12 +04:00
asyncchecksuite "NAT - handleNatStatus":
2026-04-22 12:21:43 +04:00
var sw: Switch
var key: PrivateKey
var disc: Discovery
2026-06-04 14:36:12 +04:00
var autoRelay: AutoRelayService
2026-04-22 12:21:43 +04:00
setup:
2026-06-04 14:36:12 +04:00
autoRelay =
AutoRelayService.new(1, relayClientModule.RelayClient.new(), nil, Rng.instance())
2026-04-22 12:21:43 +04:00
key = PrivateKey.random(Rng.instance[]).get()
disc = Discovery.new(key, announceAddrs = @[])
sw = newStandardSwitch()
await sw.start()
teardown:
await sw.stop()
if autoRelay.isRunning:
discard await autoRelay.stop(sw)
let discoveryPort = Port(8090)
2026-04-22 12:21:43 +04:00
test "handleNatStatus announces mapped address when NotReachable and UPnP succeeds":
let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid")
2026-05-22 22:54:07 +04:00
let mapper = MockNatPortMapper(
mappedPorts: some((Port(9000), Port(9001), MappingProtocol.UPnP))
)
2026-04-22 12:21:43 +04:00
2026-06-04 14:35:46 +04:00
await mapper.handleNatStatus(
NotReachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay
)
2026-04-22 12:21:43 +04:00
check disc.announceAddrs ==
@[MultiAddress.init("/ip4/1.2.3.4/tcp/9000").expect("valid")]
check not autoRelay.isRunning
2026-05-14 12:15:14 +04:00
check disc.protocol.clientMode
2026-04-22 12:21:43 +04:00
test "handleNatStatus starts autoRelay when NotReachable and UPnP failed":
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
2026-04-22 12:21:43 +04:00
2026-06-04 14:35:46 +04:00
await mapper.handleNatStatus(
NotReachable, Opt.none(MultiAddress), discoveryPort, disc, sw, autoRelay
)
2026-04-22 12:21:43 +04:00
check autoRelay.isRunning
2026-05-14 10:56:56 +04:00
check disc.protocol.clientMode
2026-04-22 12:21:43 +04:00
2026-06-04 14:35:46 +04:00
test "handleNatStatus starts autoRelay when NotReachable and mapping fails":
let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid")
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
2026-06-04 14:35:46 +04:00
await mapper.handleNatStatus(
NotReachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay
)
check autoRelay.isRunning
check disc.announceAddrs == newSeq[MultiAddress]()
2026-05-14 10:56:56 +04:00
check disc.protocol.clientMode
2026-06-04 14:35:46 +04:00
test "handleNatStatus does not announce address when Reachable and no dialBackAddr":
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
2026-04-22 12:21:43 +04:00
2026-06-04 14:35:46 +04:00
await mapper.handleNatStatus(
Reachable, Opt.none(MultiAddress), discoveryPort, disc, sw, autoRelay
)
2026-04-22 12:21:43 +04:00
check disc.announceAddrs == newSeq[MultiAddress]()
check not autoRelay.isRunning
2026-05-14 10:56:56 +04:00
check not disc.protocol.clientMode
test "handleNatStatus stops relay and announces dialBackAddr when Reachable":
let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid")
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
2026-04-22 12:21:43 +04:00
discard await autorelayservice.setup(autoRelay, sw)
2026-06-04 14:35:46 +04:00
await mapper.handleNatStatus(
Reachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay
)
2026-04-22 12:21:43 +04:00
check not autoRelay.isRunning
check disc.announceAddrs == @[dialBack]
2026-05-14 10:56:56 +04:00
check not disc.protocol.clientMode
2026-05-22 22:54:07 +04:00
asyncchecksuite "NAT - Hole punching":
test "setupHolePunching mounts the dcutr protocol on the switch":
let sw = newStandardSwitch()
setupHolePunching(sw)
check sw.ms.handlers.anyIt(dcutrCore.DcutrCodec in it.protos)
test "holePunchIfRelayed returns early when the peer has no connections":
let sw1 = newStandardSwitch()
let sw2 = newStandardSwitch()
await allFutures(sw1.start(), sw2.start())
await holePunchIfRelayed(sw1, sw2.peerInfo.peerId)
await allFutures(sw1.stop(), sw2.stop())
test "holePunchIfRelayed returns early when a direct connection already exists":
let sw1 = newStandardSwitch()
let sw2 = newStandardSwitch()
await allFutures(sw1.start(), sw2.start())
await sw1.connect(sw2.peerInfo.peerId, sw2.peerInfo.addrs)
check sw1.isConnected(sw2.peerInfo.peerId)
await holePunchIfRelayed(sw1, sw2.peerInfo.peerId)
check sw1.isConnected(sw2.peerInfo.peerId)
await allFutures(sw1.stop(), sw2.stop())