diff --git a/libp2p/services/autorelayservice.nim b/libp2p/services/autorelayservice.nim index defd42f17..2c5a66096 100644 --- a/libp2p/services/autorelayservice.nim +++ b/libp2p/services/autorelayservice.nim @@ -53,6 +53,7 @@ proc reserveAndUpdate(self: AutoRelayService, relayPid: PeerId, switch: Switch) if relayPid notin self.relayAddresses or self.relayAddresses[relayPid] != relayedAddr: self.relayAddresses[relayPid] = relayedAddr await switch.peerInfo.update() + debug "Updated relay addresses", relayPid, relayedAddr if not self.onReservation.isNil(): self.onReservation(concat(toSeq(self.relayAddresses.values))) await sleepAsync chronos.seconds(ttl - 30) diff --git a/libp2p/services/hpservice.nim b/libp2p/services/hpservice.nim index a2ee4974a..9cf45e673 100644 --- a/libp2p/services/hpservice.nim +++ b/libp2p/services/hpservice.nim @@ -43,14 +43,21 @@ proc new*(T: typedesc[HPService], autonatService: AutonatService, autoRelayServi return T(autonatService: autonatService, autoRelayService: autoRelayService, isPublicIPAddrProc: isPublicIPAddrProc) proc tryStartingDirectConn(self: HPService, switch: Switch, peerId: PeerId): Future[bool] {.async.} = + proc tryConnect(address: MultiAddress): Future[bool] {.async.} = + debug "Trying to create direct connection", peerId, address + await switch.connect(peerId, @[address], true, false) + debug "Direct connection created." + return true + await sleepAsync(500.milliseconds) # wait for AddressBook to be populated for address in switch.peerStore[AddressBook][peerId]: try: - let ta = initTAddress(address) - if ta.isOk() and self.isPublicIPAddrProc(ta.get()): - await switch.connect(peerId, @[address], true, false) - debug "Direct connection created." - return true + if DNS.matchPartial(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: debug "Failed to create direct connection.", err = err.msg continue diff --git a/libp2p/switch.nim b/libp2p/switch.nim index bc2975d33..eb2d6f80c 100644 --- a/libp2p/switch.nim +++ b/libp2p/switch.nim @@ -339,7 +339,7 @@ proc start*(s: Switch) {.async, gcsafe, public.} = warn "Switch has already been started" return - trace "starting switch for peer", peerInfo = s.peerInfo + debug "starting switch for peer", peerInfo = s.peerInfo var startFuts: seq[Future[void]] for t in s.transports: let addrs = s.peerInfo.listenAddrs.filterIt( diff --git a/tests/testhpservice.nim b/tests/testhpservice.nim index 572727899..9dfce61db 100644 --- a/tests/testhpservice.nim +++ b/tests/testhpservice.nim @@ -26,12 +26,15 @@ import ../libp2p/[builders, import ../libp2p/protocols/connectivity/relay/[relay, client] import ../libp2p/protocols/connectivity/autonat/[service] import ../libp2p/wire +import ../libp2p/nameresolving/nameresolver +import ../libp2p/nameresolving/mockresolver + import stubs/autonatclientstub proc isPublicAddrIPAddrMock(ta: TransportAddress): bool = return true -proc createSwitch(r: Relay = nil, hpService: Service = nil): Switch {.raises: [LPError, Defect].} = +proc createSwitch(r: Relay = nil, hpService: Service = nil, nameResolver: NameResolver = nil): Switch {.raises: [LPError, Defect].} = var builder = SwitchBuilder.new() .withRng(newRng()) .withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ]) @@ -46,6 +49,9 @@ proc createSwitch(r: Relay = nil, hpService: Service = nil): Switch {.raises: [L if r != nil: builder = builder.withCircuitRelay(r) + if nameResolver != nil: + builder = builder.withNameResolver(nameResolver) + return builder.build() proc buildRelayMA(switchRelay: Switch, switchClient: Switch): MultiAddress = @@ -90,6 +96,51 @@ suite "Hole Punching": await allFuturesThrowing( privatePeerSwitch.stop(), publicPeerSwitch.stop(), switchRelay.stop()) + asyncTest "Direct connection must work when peer address is public and dns is used": + + let autonatClientStub = AutonatClientStub.new(expectedDials = 1) + autonatClientStub.answer = NotReachable + let autonatService = AutonatService.new(autonatClientStub, newRng(), maxQueueSize = 1) + + let relayClient = RelayClient.new() + let privatePeerRelayAddr = newFuture[seq[MultiAddress]]() + + + let resolver = MockResolver.new() + resolver.ipResponses[("localhost", false)] = @["127.0.0.1"] + 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]) = + if not privatePeerRelayAddr.completed(): + privatePeerRelayAddr.complete(address) + + let autoRelayService = AutoRelayService.new(1, relayClient, checkMA, newRng()) + + let hpservice = HPService.new(autonatService, autoRelayService, isPublicAddrIPAddrMock) + + let privatePeerSwitch = createSwitch(relayClient, hpservice, nameResolver = resolver) + let switchRelay = createSwitch(Relay.new()) + + await allFutures(switchRelay.start(), privatePeerSwitch.start(), publicPeerSwitch.start()) + + await privatePeerSwitch.connect(switchRelay.peerInfo.peerId, switchRelay.peerInfo.addrs) + + await publicPeerSwitch.connect(privatePeerSwitch.peerInfo.peerId, (await privatePeerRelayAddr)) + + checkExpiring: + privatePeerSwitch.connManager.connCount(publicPeerSwitch.peerInfo.peerId) == 1 and + not isRelayed(privatePeerSwitch.connManager.selectMuxer(publicPeerSwitch.peerInfo.peerId).connection) + + await allFuturesThrowing( + privatePeerSwitch.stop(), publicPeerSwitch.stop(), switchRelay.stop()) + proc holePunchingTest(connectStub: proc (): Future[void] {.async.}, isPublicIPAddrProc: IsPublicIPAddrProc, answer: Answer) {.async.} =