Handle dns addrs in HP service (#890)

This commit is contained in:
diegomrsantos 2023-05-16 14:59:02 +02:00 committed by GitHub
parent a1eb53b181
commit 7d6bc545e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 7 deletions

View File

@ -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)

View File

@ -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

View File

@ -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(

View File

@ -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.} =