Consider dns as public address (#913)

This commit is contained in:
diegomrsantos 2023-06-13 17:58:41 +02:00 committed by GitHub
parent c28d8bb353
commit 67711478ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 127 additions and 72 deletions

View File

@ -171,8 +171,7 @@ proc addressMapper(
for listenAddr in listenAddrs: for listenAddr in listenAddrs:
var processedMA = listenAddr var processedMA = listenAddr
try: try:
let hostIP = initTAddress(listenAddr).get() if not listenAddr.isPublicMA() and self.networkReachability == NetworkReachability.Reachable:
if not hostIP.isGlobal() and self.networkReachability == NetworkReachability.Reachable:
processedMA = peerStore.guessDialableAddr(listenAddr) # handle manual port forwarding processedMA = peerStore.guessDialableAddr(listenAddr) # handle manual port forwarding
except CatchableError as exc: except CatchableError as exc:
debug "Error while handling address mapper", msg = exc.msg debug "Error while handling address mapper", msg = exc.msg

View File

@ -81,8 +81,8 @@ proc startSync*(self: DcutrClient, switch: Switch, remotePeerId: PeerId, addrs:
debug "Dcutr initiator could not connect to the remote peer, all connect attempts timed out", peerDialableAddrs, msg = err.msg debug "Dcutr initiator could not connect to the remote peer, all connect attempts timed out", peerDialableAddrs, msg = err.msg
raise newException(DcutrError, "Dcutr initiator could not connect to the remote peer, all connect attempts timed out", err) raise newException(DcutrError, "Dcutr initiator could not connect to the remote peer, all connect attempts timed out", err)
except CatchableError as err: except CatchableError as err:
debug "Unexpected error when trying direct conn", err = err.msg debug "Unexpected error when Dcutr initiator tried to connect to the remote peer", err = err.msg
raise newException(DcutrError, "Unexpected error when trying a direct conn", err) raise newException(DcutrError, "Unexpected error when Dcutr initiator tried to connect to the remote peer", err)
finally: finally:
if stream != nil: if stream != nil:
await stream.close() await stream.close()

View File

@ -72,8 +72,8 @@ proc new*(T: typedesc[Dcutr], switch: Switch, connectTimeout = 15.seconds, maxDi
debug "Dcutr receiver could not connect to the remote peer, all connect attempts timed out", peerDialableAddrs, msg = err.msg debug "Dcutr receiver could not connect to the remote peer, all connect attempts timed out", peerDialableAddrs, msg = err.msg
raise newException(DcutrError, "Dcutr receiver could not connect to the remote peer, all connect attempts timed out", err) raise newException(DcutrError, "Dcutr receiver could not connect to the remote peer, all connect attempts timed out", err)
except CatchableError as err: except CatchableError as err:
warn "Unexpected error in dcutr handler", msg = err.msg warn "Unexpected error when Dcutr receiver tried to connect to the remote peer", msg = err.msg
raise newException(DcutrError, "Unexpected error in dcutr handler", err) raise newException(DcutrError, "Unexpected error when Dcutr receiver tried to connect to the remote peer", err)
let self = T() let self = T()
self.handler = handleStream self.handler = handleStream

View File

@ -30,13 +30,9 @@ type
onNewStatusHandler: StatusAndConfidenceHandler onNewStatusHandler: StatusAndConfidenceHandler
autoRelayService: AutoRelayService autoRelayService: AutoRelayService
autonatService: AutonatService autonatService: AutonatService
isPublicIPAddrProc: IsPublicIPAddrProc
IsPublicIPAddrProc* = proc(ta: TransportAddress): bool {.gcsafe, raises: [].} proc new*(T: typedesc[HPService], autonatService: AutonatService, autoRelayService: AutoRelayService): T =
return T(autonatService: autonatService, autoRelayService: autoRelayService)
proc new*(T: typedesc[HPService], autonatService: AutonatService, autoRelayService: AutoRelayService,
isPublicIPAddrProc: IsPublicIPAddrProc = isGlobal): T =
return T(autonatService: autonatService, autoRelayService: autoRelayService, isPublicIPAddrProc: isPublicIPAddrProc)
proc tryStartingDirectConn(self: HPService, switch: Switch, peerId: PeerId): Future[bool] {.async.} = proc tryStartingDirectConn(self: HPService, switch: Switch, peerId: PeerId): Future[bool] {.async.} =
proc tryConnect(address: MultiAddress): Future[bool] {.async.} = proc tryConnect(address: MultiAddress): Future[bool] {.async.} =
@ -51,12 +47,8 @@ proc tryStartingDirectConn(self: HPService, switch: Switch, peerId: PeerId): Fut
let isRelayed = address.contains(multiCodec("p2p-circuit")) let isRelayed = address.contains(multiCodec("p2p-circuit"))
if isRelayed.isErr() or isRelayed.get(): if isRelayed.isErr() or isRelayed.get():
continue continue
if DNS.matchPartial(address): if address.isPublicMA():
return await tryConnect(address) return await tryConnect(address)
else:
let ta = initTAddress(address)
if ta.isOk() and self.isPublicIPAddrProc(ta.get()):
return await tryConnect(address)
except CatchableError as err: except CatchableError as err:
debug "Failed to create direct connection.", err = err.msg debug "Failed to create direct connection.", err = err.msg
continue continue

View File

@ -20,14 +20,14 @@ else:
const const
RTRANSPMA* = mapOr( RTRANSPMA* = mapOr(
TCP_IP, TCP,
WebSockets_IP, WebSockets,
UNIX UNIX
) )
TRANSPMA* = mapOr( TRANSPMA* = mapOr(
RTRANSPMA, RTRANSPMA,
UDP_IP UDP,
) )
@ -37,7 +37,7 @@ proc initTAddress*(ma: MultiAddress): MaResult[TransportAddress] =
## MultiAddress must be wire address, e.g. ``{IP4, IP6, UNIX}/{TCP, UDP}``. ## MultiAddress must be wire address, e.g. ``{IP4, IP6, UNIX}/{TCP, UDP}``.
## ##
if TRANSPMA.match(ma): if mapOr(TCP_IP, WebSockets_IP, UNIX, UDP_IP).match(ma):
var pbuf: array[2, byte] var pbuf: array[2, byte]
let code = (?(?ma[0]).protoCode()) let code = (?(?ma[0]).protoCode())
if code == multiCodec("unix"): if code == multiCodec("unix"):
@ -213,3 +213,10 @@ proc getLocalAddress*(sock: AsyncFD): TransportAddress =
if getsockname(SocketHandle(sock), cast[ptr SockAddr](addr saddr), if getsockname(SocketHandle(sock), cast[ptr SockAddr](addr saddr),
addr slen) == 0: addr slen) == 0:
fromSAddr(addr saddr, slen, result) fromSAddr(addr saddr, slen, result)
proc isPublicMA*(ma: MultiAddress): bool =
if DNS.matchPartial(ma):
return true
let hostIP = initTAddress(ma).valueOr: return false
return hostIP.isGlobal()

View File

@ -10,10 +10,11 @@ import ../libp2p/stream/lpstream
import ../libp2p/stream/chronosstream import ../libp2p/stream/chronosstream
import ../libp2p/muxers/mplex/lpchannel import ../libp2p/muxers/mplex/lpchannel
import ../libp2p/protocols/secure/secure import ../libp2p/protocols/secure/secure
import ../libp2p/switch
import ../libp2p/nameresolving/[nameresolver, mockresolver]
import ./asyncunit import ./asyncunit
export asyncunit export asyncunit, mockresolver
const const
StreamTransportTrackerName = "stream.transport" StreamTransportTrackerName = "stream.transport"
@ -138,3 +139,15 @@ proc unorderedCompare*[T](a, b: seq[T]): bool =
return true return true
return false return false
proc default*(T: typedesc[MockResolver]): T =
let resolver = MockResolver.new()
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"]
resolver.ipResponses[("localhost", true)] = @["::1"]
resolver
proc setDNSAddr*(switch: Switch) {.gcsafe, async.} =
proc addressMapper(listenAddrs: seq[MultiAddress]): Future[seq[MultiAddress]] {.gcsafe, async.} =
return @[MultiAddress.init("/dns4/localhost/").tryGet() & listenAddrs[0][1].tryGet()]
switch.peerInfo.addressMappers.add(addressMapper)
await switch.peerInfo.update()

View File

@ -17,7 +17,14 @@ import ../../libp2p/[peerid, multiaddress, switch]
type type
SwitchStub* = ref object of Switch SwitchStub* = ref object of Switch
switch*: Switch switch*: Switch
connectStub*: proc(): Future[void] {.async.} connectStub*: connectStubType
connectStubType* = proc (self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.gcsafe, async.}
method connect*( method connect*(
self: SwitchStub, self: SwitchStub,
@ -27,11 +34,11 @@ method connect*(
reuseConnection = true, reuseConnection = true,
upgradeDir = Direction.Out) {.async.} = upgradeDir = Direction.Out) {.async.} =
if (self.connectStub != nil): if (self.connectStub != nil):
await self.connectStub() await self.connectStub(self, peerId, addrs, forceDial, reuseConnection, upgradeDir)
else: else:
await self.switch.connect(peerId, addrs, forceDial, reuseConnection, upgradeDir) await self.switch.connect(peerId, addrs, forceDial, reuseConnection, upgradeDir)
proc new*(T: typedesc[SwitchStub], switch: Switch, connectStub: proc (): Future[void] {.async.} = nil): T = proc new*(T: typedesc[SwitchStub], switch: Switch, connectStub: connectStubType = nil): T =
return SwitchStub( return SwitchStub(
switch: switch, switch: switch,
peerInfo: switch.peerInfo, peerInfo: switch.peerInfo,

View File

@ -107,13 +107,9 @@ suite "Autonat":
await allFutures(doesNothingListener.stop(), src.stop(), dst.stop()) await allFutures(doesNothingListener.stop(), src.stop(), dst.stop())
asyncTest "dialMe dials dns and returns public address": asyncTest "dialMe dials dns and returns public address":
let resolver = MockResolver.new()
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"]
resolver.ipResponses[("localhost", true)] = @["::1"]
let let
src = newStandardSwitch() src = newStandardSwitch()
dst = createAutonatSwitch(nameResolver = resolver) dst = createAutonatSwitch(nameResolver = MockResolver.default())
await src.start() await src.start()
await dst.start() await dst.start()

View File

@ -16,10 +16,11 @@ import ../libp2p/[builders,
switch, switch,
protocols/connectivity/autonat/client, protocols/connectivity/autonat/client,
protocols/connectivity/autonat/service] protocols/connectivity/autonat/service]
import ../libp2p/nameresolving/[nameresolver, mockresolver]
import ./helpers import ./helpers
import stubs/autonatclientstub import stubs/autonatclientstub
proc createSwitch(autonatSvc: Service = nil, withAutonat = true, maxConnsPerPeer = 1, maxConns = 100): Switch = proc createSwitch(autonatSvc: Service = nil, withAutonat = true, maxConnsPerPeer = 1, maxConns = 100, nameResolver: NameResolver = nil): Switch =
var builder = SwitchBuilder.new() var builder = SwitchBuilder.new()
.withRng(newRng()) .withRng(newRng())
.withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ]) .withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ])
@ -35,6 +36,9 @@ proc createSwitch(autonatSvc: Service = nil, withAutonat = true, maxConnsPerPeer
if autonatSvc != nil: if autonatSvc != nil:
builder = builder.withServices(@[autonatSvc]) builder = builder.withServices(@[autonatSvc])
if nameResolver != nil:
builder = builder.withNameResolver(nameResolver)
return builder.build() return builder.build()
suite "Autonat Service": suite "Autonat Service":
@ -257,7 +261,9 @@ suite "Autonat Service":
let autonatService = AutonatService.new(AutonatClient.new(), newRng(), some(1.seconds), maxQueueSize = 1) let autonatService = AutonatService.new(AutonatClient.new(), newRng(), some(1.seconds), maxQueueSize = 1)
let switch1 = createSwitch(autonatService, maxConnsPerPeer = 0) let switch1 = createSwitch(autonatService, maxConnsPerPeer = 0)
let switch2 = createSwitch(maxConnsPerPeer = 0) await switch1.setDNSAddr()
let switch2 = createSwitch(maxConnsPerPeer = 0, nameResolver = MockResolver.default())
let awaiter = newFuture[void]() let awaiter = newFuture[void]()

View File

@ -90,7 +90,12 @@ suite "Dcutr":
asyncTest "Client connect timeout": asyncTest "Client connect timeout":
proc connectTimeoutProc(): Future[void] {.async.} = proc connectTimeoutProc(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
await sleepAsync(100.millis) await sleepAsync(100.millis)
let behindNATSwitch = SwitchStub.new(newStandardSwitch(), connectTimeoutProc) let behindNATSwitch = SwitchStub.new(newStandardSwitch(), connectTimeoutProc)
@ -104,7 +109,12 @@ suite "Dcutr":
asyncTest "All client connect attempts fail": asyncTest "All client connect attempts fail":
proc connectErrorProc(): Future[void] {.async.} = proc connectErrorProc(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
raise newException(CatchableError, "error") raise newException(CatchableError, "error")
let behindNATSwitch = SwitchStub.new(newStandardSwitch(), connectErrorProc) let behindNATSwitch = SwitchStub.new(newStandardSwitch(), connectErrorProc)
@ -116,7 +126,7 @@ suite "Dcutr":
except DcutrError as err: except DcutrError as err:
check err.parent of AllFuturesFailedError check err.parent of AllFuturesFailedError
proc ductrServerTest(connectStub: proc (): Future[void] {.async.}) {.async.} = proc ductrServerTest(connectStub: connectStubType) {.async.} =
let behindNATSwitch = newStandardSwitch() let behindNATSwitch = newStandardSwitch()
let publicSwitch = SwitchStub.new(newStandardSwitch()) let publicSwitch = SwitchStub.new(newStandardSwitch())
@ -144,14 +154,24 @@ suite "Dcutr":
asyncTest "DCUtR server timeout when establishing a new connection": asyncTest "DCUtR server timeout when establishing a new connection":
proc connectProc(): Future[void] {.async.} = proc connectProc(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
await sleepAsync(100.millis) await sleepAsync(100.millis)
await ductrServerTest(connectProc) await ductrServerTest(connectProc)
asyncTest "DCUtR server error when establishing a new connection": asyncTest "DCUtR server error when establishing a new connection":
proc connectProc(): Future[void] {.async.} = proc connectProc(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
raise newException(CatchableError, "error") raise newException(CatchableError, "error")
await ductrServerTest(connectProc) await ductrServerTest(connectProc)

View File

@ -18,18 +18,14 @@ import ./helpers
import ./stubs/switchstub import ./stubs/switchstub
import ../libp2p/[builders, import ../libp2p/[builders,
switch, switch,
wire,
services/hpservice, services/hpservice,
services/autorelayservice] services/autorelayservice]
import ../libp2p/protocols/connectivity/relay/[relay, client] import ../libp2p/protocols/connectivity/relay/[relay, client]
import ../libp2p/protocols/connectivity/autonat/[service] import ../libp2p/protocols/connectivity/autonat/[service]
import ../libp2p/nameresolving/nameresolver import ../libp2p/nameresolving/[nameresolver, mockresolver]
import ../libp2p/nameresolving/mockresolver
import stubs/autonatclientstub import stubs/autonatclientstub
proc isPublicAddrIPAddrMock(ta: TransportAddress): bool =
return true
proc createSwitch(r: Relay = nil, hpService: Service = nil, nameResolver: NameResolver = nil): Switch {.raises: [LPError].} = proc createSwitch(r: Relay = nil, hpService: Service = nil, nameResolver: NameResolver = nil): Switch {.raises: [LPError].} =
var builder = SwitchBuilder.new() var builder = SwitchBuilder.new()
.withRng(newRng()) .withRng(newRng())
@ -68,19 +64,25 @@ suite "Hole Punching":
let privatePeerRelayAddr = newFuture[seq[MultiAddress]]() let privatePeerRelayAddr = newFuture[seq[MultiAddress]]()
let publicPeerSwitch = createSwitch(RelayClient.new()) let publicPeerSwitch = createSwitch(RelayClient.new())
proc addressMapper(listenAddrs: seq[MultiAddress]): Future[seq[MultiAddress]] {.gcsafe, async.} =
return @[MultiAddress.init("/dns4/localhost/").tryGet() & listenAddrs[0][1].tryGet()]
publicPeerSwitch.peerInfo.addressMappers.add(addressMapper)
await publicPeerSwitch.peerInfo.update()
proc checkMA(address: seq[MultiAddress]) = proc checkMA(address: seq[MultiAddress]) =
if not privatePeerRelayAddr.completed(): if not privatePeerRelayAddr.completed():
privatePeerRelayAddr.complete(address) privatePeerRelayAddr.complete(address)
let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng()) let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng())
let hpservice = HPService.new(autonatService, autoRelayService, isPublicAddrIPAddrMock) let hpservice = HPService.new(autonatService, autoRelayService)
let privatePeerSwitch = createSwitch(relayClient, hpservice) let privatePeerSwitch = createSwitch(relayClient, hpservice, nameresolver = MockResolver.default())
let peerSwitch = createSwitch() let peerSwitch = createSwitch()
let switchRelay = createSwitch(Relay.new()) let switchRelay = createSwitch(Relay.new())
await allFutures(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start(), peerSwitch.start()) await allFuturesThrowing(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start(), peerSwitch.start())
await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs) await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs)
await privatePeerSwitch.connect(peerSwitch.peerInfo.peerId, peerSwitch.peerInfo.addrs) # for autonat await privatePeerSwitch.connect(peerSwitch.peerInfo.peerId, peerSwitch.peerInfo.addrs) # for autonat
@ -103,16 +105,8 @@ suite "Hole Punching":
let relayClient = RelayClient.new() let relayClient = RelayClient.new()
let privatePeerRelayAddr = newFuture[seq[MultiAddress]]() let privatePeerRelayAddr = newFuture[seq[MultiAddress]]()
let resolver = MockResolver.new() let publicPeerSwitch = createSwitch(RelayClient.new())
resolver.ipResponses[("localhost", false)] = @["127.0.0.1"] await publicPeerSwitch.setDNSAddr()
resolver.ipResponses[("localhost", true)] = @["::1"]
let publicPeerSwitch = createSwitch(RelayClient.new(), nameResolver = resolver)
proc addressMapper(listenAddrs: seq[MultiAddress]): Future[seq[MultiAddress]] {.gcsafe, async.} =
return @[MultiAddress.init("/dns4/localhost/").tryGet() & listenAddrs[0][1].tryGet()]
publicPeerSwitch.peerInfo.addressMappers.add(addressMapper)
await publicPeerSwitch.peerInfo.update()
proc checkMA(address: seq[MultiAddress]) = proc checkMA(address: seq[MultiAddress]) =
if not privatePeerRelayAddr.completed(): if not privatePeerRelayAddr.completed():
@ -120,13 +114,13 @@ suite "Hole Punching":
let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng()) let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng())
let hpservice = HPService.new(autonatService, autoRelayService, isPublicAddrIPAddrMock) let hpservice = HPService.new(autonatService, autoRelayService)
let privatePeerSwitch = createSwitch(relayClient, hpservice, nameResolver = resolver) let privatePeerSwitch = createSwitch(relayClient, hpservice, nameResolver = MockResolver.default())
let peerSwitch = createSwitch() let peerSwitch = createSwitch()
let switchRelay = createSwitch(Relay.new()) let switchRelay = createSwitch(Relay.new())
await allFutures(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start(), peerSwitch.start()) await allFuturesThrowing(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start(), peerSwitch.start())
await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs) await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs)
await privatePeerSwitch.connect(peerSwitch.peerInfo.peerId, peerSwitch.peerInfo.addrs) # for autonat await privatePeerSwitch.connect(peerSwitch.peerInfo.peerId, peerSwitch.peerInfo.addrs) # for autonat
@ -140,9 +134,7 @@ suite "Hole Punching":
await allFuturesThrowing( await allFuturesThrowing(
privatePeerSwitch.stop(), publicPeerSwitch.stop(), switchRelay.stop(), peerSwitch.stop()) privatePeerSwitch.stop(), publicPeerSwitch.stop(), switchRelay.stop(), peerSwitch.stop())
proc holePunchingTest(connectStub: proc (): Future[void] {.async.}, proc holePunchingTest(initiatorConnectStub: connectStubType, rcvConnectStub: connectStubType, answer: Answer) {.async.} =
isPublicIPAddrProc: IsPublicIPAddrProc,
answer: Answer) {.async.} =
# There's no check in this test cause it can't test hole punching locally. It exists just to be sure the rest of # There's no check in this test cause it can't test hole punching locally. It exists just to be sure the rest of
# the code works properly. # the code works properly.
@ -165,11 +157,12 @@ suite "Hole Punching":
let autoRelayService1 = AutoRelayService.new(1, relayClient1, checkMA, newRng()) let autoRelayService1 = AutoRelayService.new(1, relayClient1, checkMA, newRng())
let autoRelayService2 = AutoRelayService.new(1, relayClient2, nil, newRng()) let autoRelayService2 = AutoRelayService.new(1, relayClient2, nil, newRng())
let hpservice1 = HPService.new(autonatService1, autoRelayService1, isPublicIPAddrProc) let hpservice1 = HPService.new(autonatService1, autoRelayService1)
let hpservice2 = HPService.new(autonatService2, autoRelayService2) let hpservice2 = HPService.new(autonatService2, autoRelayService2)
let privatePeerSwitch1 = SwitchStub.new(createSwitch(relayClient1, hpservice1)) let privatePeerSwitch1 = SwitchStub.new(createSwitch(relayClient1, hpservice1, nameresolver = MockResolver.default()))
let privatePeerSwitch2 = createSwitch(relayClient2, hpservice2) let privatePeerSwitch2 = SwitchStub.new(createSwitch(relayClient2, hpservice2))
await privatePeerSwitch2.setDNSAddr()
let switchRelay = createSwitch(Relay.new()) let switchRelay = createSwitch(Relay.new())
let switchAux = createSwitch() let switchAux = createSwitch()
let switchAux2 = createSwitch() let switchAux2 = createSwitch()
@ -178,7 +171,7 @@ suite "Hole Punching":
var awaiter = newFuture[void]() var awaiter = newFuture[void]()
await allFutures( await allFuturesThrowing(
switchRelay.start(), privatePeerSwitch1.start(), privatePeerSwitch2.start(), switchRelay.start(), privatePeerSwitch1.start(), privatePeerSwitch2.start(),
switchAux.start(), switchAux2.start(), switchAux3.start(), switchAux4.start() switchAux.start(), switchAux2.start(), switchAux3.start(), switchAux4.start()
) )
@ -196,21 +189,43 @@ suite "Hole Punching":
await privatePeerSwitch2.connect(switchAux3.peerInfo.peerId, switchAux3.peerInfo.addrs) await privatePeerSwitch2.connect(switchAux3.peerInfo.peerId, switchAux3.peerInfo.addrs)
await privatePeerSwitch2.connect(switchAux4.peerInfo.peerId, switchAux4.peerInfo.addrs) await privatePeerSwitch2.connect(switchAux4.peerInfo.peerId, switchAux4.peerInfo.addrs)
privatePeerSwitch1.connectStub = connectStub privatePeerSwitch1.connectStub = initiatorConnectStub
await privatePeerSwitch2.connect(privatePeerSwitch1.peerInfo.peerId, (await privatePeerRelayAddr1)) await privatePeerSwitch2.connect(privatePeerSwitch1.peerInfo.peerId, (await privatePeerRelayAddr1))
privatePeerSwitch2.connectStub = rcvConnectStub
await sleepAsync(200.millis) checkExpiring:
# we can't hole punch when both peers are in the same machine. This means that the simultaneous dialings will result
# in two connections attemps, instead of one. The server dial is going to fail because it is acting as the
# tcp simultaneous incoming upgrader in the dialer which works only in the simultaneous open case, but the client
# dial will succeed.
privatePeerSwitch1.connManager.connCount(privatePeerSwitch2.peerInfo.peerId) == 1 and
not isRelayed(privatePeerSwitch1.connManager.selectMuxer(privatePeerSwitch2.peerInfo.peerId).connection)
await allFuturesThrowing( await allFuturesThrowing(
privatePeerSwitch1.stop(), privatePeerSwitch2.stop(), switchRelay.stop(), privatePeerSwitch1.stop(), privatePeerSwitch2.stop(), switchRelay.stop(),
switchAux.stop(), switchAux2.stop(), switchAux3.stop(), switchAux4.stop()) switchAux.stop(), switchAux2.stop(), switchAux3.stop(), switchAux4.stop())
asyncTest "Hole punching when peers addresses are private": asyncTest "Hole punching when peers addresses are private":
await holePunchingTest(nil, isGlobal, NotReachable) proc connectStub(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
self.connectStub = nil # this stub should be called only once
await sleepAsync(100.millis) # avoid simultaneous dialing that causes address in use error
await self.switch.connect(peerId, addrs, forceDial, reuseConnection, upgradeDir)
await holePunchingTest(nil, connectStub, NotReachable)
asyncTest "Hole punching when there is an error during unilateral direct connection": asyncTest "Hole punching when there is an error during unilateral direct connection":
proc connectStub(): Future[void] {.async.} = proc connectStub(self: SwitchStub,
peerId: PeerId,
addrs: seq[MultiAddress],
forceDial = false,
reuseConnection = true,
upgradeDir = Direction.Out): Future[void] {.async.} =
self.connectStub = nil # this stub should be called only once
raise newException(CatchableError, "error") raise newException(CatchableError, "error")
await holePunchingTest(connectStub, isPublicAddrIPAddrMock, Reachable) await holePunchingTest(connectStub, nil, Reachable)