2022-08-01 12:31:22 +00:00
|
|
|
{.used.}
|
|
|
|
|
2023-05-18 08:24:17 +00:00
|
|
|
# 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-01 12:31:22 +00:00
|
|
|
import options, bearssl, chronos
|
|
|
|
import stew/byteutils
|
2022-09-15 07:43:40 +00:00
|
|
|
import
|
|
|
|
../libp2p/[
|
|
|
|
protocols/connectivity/relay/relay,
|
|
|
|
protocols/connectivity/relay/client,
|
|
|
|
protocols/connectivity/relay/messages,
|
|
|
|
protocols/connectivity/relay/utils,
|
|
|
|
protocols/connectivity/relay/rtransport,
|
2022-08-01 12:31:22 +00:00
|
|
|
multiaddress,
|
|
|
|
peerinfo,
|
|
|
|
peerid,
|
|
|
|
stream/connection,
|
|
|
|
multistream,
|
|
|
|
switch,
|
|
|
|
builders,
|
|
|
|
upgrademngrs/upgrade,
|
|
|
|
varint,
|
|
|
|
daemon/daemonapi,
|
|
|
|
]
|
|
|
|
import ./helpers
|
|
|
|
|
|
|
|
proc new(T: typedesc[RelayTransport], relay: Relay): T =
|
|
|
|
T.new(relay = relay, upgrader = relay.switch.transports[0].upgrader)
|
|
|
|
|
|
|
|
suite "Circuit Relay":
|
|
|
|
asyncTeardown:
|
|
|
|
await allFutures(src.stop(), dst.stop(), srelay.stop())
|
|
|
|
checkTrackers()
|
|
|
|
|
|
|
|
var
|
|
|
|
protos {.threadvar.}: seq[string]
|
|
|
|
customProto {.threadvar.}: LPProtocol
|
|
|
|
ma {.threadvar.}: MultiAddress
|
|
|
|
src {.threadvar.}: Switch
|
|
|
|
dst {.threadvar.}: Switch
|
|
|
|
srelay {.threadvar.}: Switch
|
|
|
|
clSrc {.threadvar.}: RelayClient
|
|
|
|
clDst {.threadvar.}: RelayClient
|
|
|
|
r {.threadvar.}: Relay
|
|
|
|
conn {.threadvar.}: Connection
|
|
|
|
msg {.threadvar.}: ProtoBuffer
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv {.threadvar.}: Opt[RelayMessage]
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
proc createMsg(
|
2023-06-28 14:44:58 +00:00
|
|
|
msgType: Opt[RelayType] = Opt.none(RelayType),
|
|
|
|
status: Opt[StatusV1] = Opt.none(StatusV1),
|
|
|
|
src: Opt[RelayPeer] = Opt.none(RelayPeer),
|
|
|
|
dst: Opt[RelayPeer] = Opt.none(RelayPeer),
|
|
|
|
): ProtoBuffer =
|
2022-08-01 12:31:22 +00:00
|
|
|
encode(RelayMessage(msgType: msgType, srcPeer: src, dstPeer: dst, status: status))
|
|
|
|
|
2023-06-28 14:44:58 +00:00
|
|
|
proc checkMsg(
|
|
|
|
msg: Opt[RelayMessage],
|
|
|
|
msgType: Opt[RelayType] = Opt.none(RelayType),
|
|
|
|
status: Opt[StatusV1] = Opt.none(StatusV1),
|
|
|
|
src: Opt[RelayPeer] = Opt.none(RelayPeer),
|
|
|
|
dst: Opt[RelayPeer] = Opt.none(RelayPeer),
|
|
|
|
) =
|
2022-08-01 12:31:22 +00:00
|
|
|
check:
|
|
|
|
msg.isSome
|
|
|
|
let m = msg.get()
|
|
|
|
check:
|
|
|
|
m.msgType == msgType
|
|
|
|
check:
|
|
|
|
m.status == status
|
|
|
|
check:
|
|
|
|
m.srcPeer == src
|
|
|
|
check:
|
|
|
|
m.dstPeer == dst
|
|
|
|
|
|
|
|
proc customHandler(conn: Connection, proto: string) {.async.} =
|
|
|
|
check "line1" == string.fromBytes(await conn.readLp(1024))
|
|
|
|
await conn.writeLp("line2")
|
|
|
|
check "line3" == string.fromBytes(await conn.readLp(1024))
|
|
|
|
await conn.writeLp("line4")
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
asyncSetup:
|
|
|
|
# Create a custom prototype
|
|
|
|
protos = @["/customProto", RelayV1Codec]
|
|
|
|
customProto = new LPProtocol
|
|
|
|
customProto.handler = customHandler
|
|
|
|
customProto.codec = protos[0]
|
|
|
|
|
|
|
|
ma = MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
|
|
|
|
clSrc = RelayClient.new()
|
|
|
|
clDst = RelayClient.new()
|
|
|
|
r = Relay.new(circuitRelayV1 = true)
|
|
|
|
src = SwitchBuilder
|
|
|
|
.new()
|
|
|
|
.withRng(newRng())
|
|
|
|
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
|
|
|
.withTcpTransport()
|
|
|
|
.withMplex()
|
|
|
|
.withNoise()
|
|
|
|
.withCircuitRelay(clSrc)
|
|
|
|
.build()
|
|
|
|
dst = SwitchBuilder
|
|
|
|
.new()
|
|
|
|
.withRng(newRng())
|
|
|
|
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
|
|
|
.withTcpTransport()
|
|
|
|
.withMplex()
|
|
|
|
.withNoise()
|
|
|
|
.withCircuitRelay(clDst)
|
|
|
|
.build()
|
|
|
|
srelay = SwitchBuilder
|
|
|
|
.new()
|
|
|
|
.withRng(newRng())
|
|
|
|
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
|
|
|
.withTcpTransport()
|
|
|
|
.withMplex()
|
|
|
|
.withNoise()
|
|
|
|
.withCircuitRelay(r)
|
|
|
|
.build()
|
|
|
|
|
|
|
|
dst.mount(customProto)
|
|
|
|
|
|
|
|
await src.start()
|
|
|
|
await dst.start()
|
|
|
|
await srelay.start()
|
|
|
|
|
|
|
|
asyncTest "Handle CanHop":
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(Opt.some(CanHop))
|
2022-08-01 12:31:22 +00:00
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(StatusV1.Success))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantSpeakRelay))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
asyncTest "Malformed":
|
|
|
|
conn = await srelay.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(Opt.some(RelayType.Status))
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
|
|
|
await conn.close()
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(StatusV1.MalformedMessage))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
asyncTest "Handle Stop Error":
|
|
|
|
conn = await srelay.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Stop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.none(RelayPeer),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(StopSrcMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await srelay.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Stop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.none(RelayPeer),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(StopDstMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await srelay.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Stop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
|
|
|
await conn.close()
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(StopDstMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
asyncTest "Handle Hop Error":
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, dst.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(Opt.some(RelayType.Hop))
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantSpeakRelay))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.none(RelayPeer),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopSrcMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopSrcMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.none(RelayPeer),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopDstMultiaddrInvalid))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: srelay.peerInfo.peerId, addrs: srelay.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantRelayToSelf))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: srelay.peerInfo.peerId, addrs: srelay.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantRelayToSelf))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: dst.peerInfo.peerId, addrs: dst.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopNoConnToDst))
|
2022-08-01 12:31:22 +00:00
|
|
|
|
|
|
|
await srelay.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
|
|
|
|
|
|
|
var tmp = r.maxCircuit
|
|
|
|
r.maxCircuit = 0
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantSpeakRelay))
|
2022-08-01 12:31:22 +00:00
|
|
|
r.maxCircuit = tmp
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
tmp = r.maxCircuitPerPeer
|
|
|
|
r.maxCircuitPerPeer = 0
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantSpeakRelay))
|
2022-08-01 12:31:22 +00:00
|
|
|
r.maxCircuitPerPeer = tmp
|
|
|
|
await conn.close()
|
|
|
|
|
|
|
|
let dst2 = newStandardSwitch()
|
|
|
|
await dst2.start()
|
|
|
|
await srelay.connect(dst2.peerInfo.peerId, dst2.peerInfo.addrs)
|
|
|
|
|
|
|
|
conn = await src.dial(srelay.peerInfo.peerId, srelay.peerInfo.addrs, RelayV1Codec)
|
2023-06-28 14:44:58 +00:00
|
|
|
msg = createMsg(
|
|
|
|
Opt.some(RelayType.Hop),
|
|
|
|
Opt.none(StatusV1),
|
|
|
|
Opt.some(RelayPeer(peerId: src.peerInfo.peerId, addrs: src.peerInfo.addrs)),
|
|
|
|
Opt.some(RelayPeer(peerId: dst2.peerInfo.peerId, addrs: dst2.peerInfo.addrs)),
|
|
|
|
)
|
2022-08-01 12:31:22 +00:00
|
|
|
await conn.writeLp(msg.buffer)
|
|
|
|
rcv = RelayMessage.decode(await conn.readLp(1024))
|
2023-06-28 14:44:58 +00:00
|
|
|
rcv.checkMsg(Opt.some(RelayType.Status), Opt.some(HopCantDialDst))
|
2022-08-01 12:31:22 +00:00
|
|
|
await allFutures(dst2.stop())
|
|
|
|
|
|
|
|
asyncTest "Dial Peer":
|
2023-01-31 11:46:10 +00:00
|
|
|
let maStr =
|
|
|
|
$srelay.peerInfo.addrs[0] & "/p2p/" & $srelay.peerInfo.peerId & "/p2p-circuit"
|
2022-08-01 12:31:22 +00:00
|
|
|
let maddr = MultiAddress.init(maStr).tryGet()
|
|
|
|
await src.connect(srelay.peerInfo.peerId, srelay.peerInfo.addrs)
|
|
|
|
await srelay.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, @[maddr], protos[0])
|
|
|
|
|
|
|
|
await conn.writeLp("line1")
|
|
|
|
check string.fromBytes(await conn.readLp(1024)) == "line2"
|
|
|
|
|
|
|
|
await conn.writeLp("line3")
|
|
|
|
check string.fromBytes(await conn.readLp(1024)) == "line4"
|
|
|
|
|
|
|
|
asyncTest "Bad MultiAddress":
|
|
|
|
await src.connect(srelay.peerInfo.peerId, srelay.peerInfo.addrs)
|
|
|
|
await srelay.connect(dst.peerInfo.peerId, dst.peerInfo.addrs)
|
|
|
|
expect(CatchableError):
|
|
|
|
let maStr =
|
|
|
|
$srelay.peerInfo.addrs[0] & "/p2p/" & $srelay.peerInfo.peerId & "/p2p/" &
|
|
|
|
$dst.peerInfo.peerId
|
|
|
|
let maddr = MultiAddress.init(maStr).tryGet()
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, @[maddr], protos[0])
|
|
|
|
|
|
|
|
expect(CatchableError):
|
|
|
|
let maStr = $srelay.peerInfo.addrs[0] & "/p2p/" & $srelay.peerInfo.peerId
|
|
|
|
let maddr = MultiAddress.init(maStr).tryGet()
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, @[maddr], protos[0])
|
|
|
|
|
|
|
|
expect(CatchableError):
|
|
|
|
let maStr = "/ip4/127.0.0.1"
|
|
|
|
let maddr = MultiAddress.init(maStr).tryGet()
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, @[maddr], protos[0])
|
|
|
|
|
|
|
|
expect(CatchableError):
|
|
|
|
let maStr = $dst.peerInfo.peerId
|
|
|
|
let maddr = MultiAddress.init(maStr).tryGet()
|
|
|
|
conn = await src.dial(dst.peerInfo.peerId, @[maddr], protos[0])
|