2023-05-18 08:24:17 +00:00
|
|
|
{.used.}
|
|
|
|
|
|
|
|
# Nim-Libp2p
|
|
|
|
# Copyright (c) 2023 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
|
|
# at your option.
|
|
|
|
# This file may not be copied, modified, or distributed except according to
|
|
|
|
# those terms.
|
|
|
|
|
2022-08-23 15:49:07 +00:00
|
|
|
import std/options
|
|
|
|
import chronos
|
|
|
|
import
|
|
|
|
../libp2p/[
|
2022-12-22 19:29:31 +00:00
|
|
|
transports/tcptransport,
|
|
|
|
upgrademngrs/upgrade,
|
2022-08-23 15:49:07 +00:00
|
|
|
builders,
|
2023-01-06 10:14:38 +00:00
|
|
|
protocols/connectivity/autonat/client,
|
|
|
|
protocols/connectivity/autonat/server,
|
2023-02-09 15:53:46 +00:00
|
|
|
nameresolving/nameresolver,
|
|
|
|
nameresolving/mockresolver,
|
2022-08-23 15:49:07 +00:00
|
|
|
],
|
|
|
|
./helpers
|
|
|
|
|
2023-02-09 15:53:46 +00:00
|
|
|
proc createAutonatSwitch(nameResolver: NameResolver = nil): Switch =
|
|
|
|
var builder = SwitchBuilder.new()
|
2022-08-23 15:49:07 +00:00
|
|
|
.withRng(newRng())
|
|
|
|
.withAddresses(@[ MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ])
|
|
|
|
.withTcpTransport()
|
|
|
|
.withMplex()
|
|
|
|
.withAutonat()
|
|
|
|
.withNoise()
|
2023-02-09 15:53:46 +00:00
|
|
|
|
|
|
|
if nameResolver != nil:
|
|
|
|
builder = builder.withNameResolver(nameResolver)
|
|
|
|
|
|
|
|
return builder.build()
|
2022-08-23 15:49:07 +00:00
|
|
|
|
|
|
|
proc makeAutonatServicePrivate(): Switch =
|
|
|
|
var autonatProtocol = new LPProtocol
|
|
|
|
autonatProtocol.handler = proc (conn: Connection, proto: string) {.async, gcsafe.} =
|
|
|
|
discard await conn.readLp(1024)
|
|
|
|
await conn.writeLp(AutonatDialResponse(
|
|
|
|
status: DialError,
|
|
|
|
text: some("dial failed"),
|
|
|
|
ma: none(MultiAddress)).encode().buffer)
|
|
|
|
await conn.close()
|
|
|
|
autonatProtocol.codec = AutonatCodec
|
|
|
|
result = newStandardSwitch()
|
|
|
|
result.mount(autonatProtocol)
|
|
|
|
|
|
|
|
suite "Autonat":
|
|
|
|
teardown:
|
|
|
|
checkTrackers()
|
|
|
|
|
2022-12-22 16:33:59 +00:00
|
|
|
asyncTest "dialMe returns public address":
|
2022-08-23 15:49:07 +00:00
|
|
|
let
|
|
|
|
src = newStandardSwitch()
|
|
|
|
dst = createAutonatSwitch()
|
|
|
|
await src.start()
|
|
|
|
await dst.start()
|
|
|
|
|
|
|
|
await src.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
2023-01-06 10:14:38 +00:00
|
|
|
let ma = await AutonatClient.new().dialMe(src, dst.peerInfo.peerId, dst.peerInfo.addrs)
|
2022-12-22 16:33:59 +00:00
|
|
|
check ma in src.peerInfo.addrs
|
2022-08-23 15:49:07 +00:00
|
|
|
await allFutures(src.stop(), dst.stop())
|
|
|
|
|
2022-12-22 16:33:59 +00:00
|
|
|
asyncTest "dialMe handles dial error msg":
|
2022-08-23 15:49:07 +00:00
|
|
|
let
|
|
|
|
src = newStandardSwitch()
|
|
|
|
dst = makeAutonatServicePrivate()
|
|
|
|
|
|
|
|
await src.start()
|
|
|
|
await dst.start()
|
|
|
|
|
|
|
|
await src.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
2022-12-22 16:33:59 +00:00
|
|
|
expect AutonatUnreachableError:
|
2023-01-06 10:14:38 +00:00
|
|
|
discard await AutonatClient.new().dialMe(src, dst.peerInfo.peerId, dst.peerInfo.addrs)
|
2022-08-23 15:49:07 +00:00
|
|
|
await allFutures(src.stop(), dst.stop())
|
2022-12-22 19:29:31 +00:00
|
|
|
|
|
|
|
asyncTest "Timeout is triggered in autonat handle":
|
|
|
|
let
|
|
|
|
src = newStandardSwitch()
|
|
|
|
dst = newStandardSwitch()
|
|
|
|
autonat = Autonat.new(dst, dialTimeout = 1.seconds)
|
|
|
|
doesNothingListener = TcpTransport.new(upgrade = Upgrade())
|
|
|
|
|
|
|
|
dst.mount(autonat)
|
|
|
|
await src.start()
|
|
|
|
await dst.start()
|
|
|
|
await doesNothingListener.start(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
|
|
|
|
|
|
|
await src.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
|
|
|
let conn = await src.dial(dst.peerInfo.peerId, @[AutonatCodec])
|
|
|
|
let buffer = AutonatDial(peerInfo: some(AutonatPeerInfo(
|
|
|
|
id: some(src.peerInfo.peerId),
|
|
|
|
# we ask to be dialed in the does nothing listener instead
|
|
|
|
addrs: doesNothingListener.addrs
|
|
|
|
))).encode().buffer
|
|
|
|
await conn.writeLp(buffer)
|
|
|
|
let response = AutonatMsg.decode(await conn.readLp(1024)).get().response.get()
|
|
|
|
check:
|
|
|
|
response.status == DialError
|
2023-02-07 17:51:17 +00:00
|
|
|
response.text.get() == "Dial timeout"
|
2022-12-22 19:29:31 +00:00
|
|
|
response.ma.isNone()
|
|
|
|
await allFutures(doesNothingListener.stop(), src.stop(), dst.stop())
|
2023-02-09 15:53:46 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
src = newStandardSwitch()
|
|
|
|
dst = createAutonatSwitch(nameResolver = resolver)
|
|
|
|
|
|
|
|
await src.start()
|
|
|
|
await dst.start()
|
|
|
|
|
|
|
|
let testAddr = MultiAddress.init("/dns4/localhost/").tryGet() &
|
|
|
|
dst.peerInfo.addrs[0][1].tryGet()
|
|
|
|
|
|
|
|
await src.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
|
|
|
let ma = await AutonatClient.new().dialMe(src, dst.peerInfo.peerId, @[testAddr])
|
|
|
|
|
|
|
|
check ma in src.peerInfo.addrs
|
|
|
|
await allFutures(src.stop(), dst.stop())
|