diff --git a/libp2p/switch.nim b/libp2p/switch.nim index 211ac9808..8a6380df6 100644 --- a/libp2p/switch.nim +++ b/libp2p/switch.nim @@ -321,7 +321,7 @@ proc internalConnect(s: Switch, lock.release() if isNil(conn): # None of the addresses connected - raise newException(CatchableError, "Unable to establish outgoing link") + raise newException(DialFailedError, "Unable to establish outgoing link") if conn.closed() or conn.atEof(): # This can happen when the other ends drops us diff --git a/tests/helpers.nim b/tests/helpers.nim index 7820d9498..cb8d6a73e 100644 --- a/tests/helpers.nim +++ b/tests/helpers.nim @@ -32,6 +32,8 @@ template checkTrackers*() = if tracker.isLeaked(): checkpoint tracker.dump() fail() + # Also test the GC is not fooling with us + GC_fullCollect() type RngWrap = object rng: ref BrHmacDrbgContext diff --git a/tests/testnoise.nim b/tests/testnoise.nim index 155c174a0..15956e0d1 100644 --- a/tests/testnoise.nim +++ b/tests/testnoise.nim @@ -28,6 +28,7 @@ import ../libp2p/[switch, muxers/muxer, muxers/mplex/mplex, protocols/secure/noise, + protocols/secure/secio, protocols/secure/secure] import ./helpers @@ -47,7 +48,7 @@ method init(p: TestProto) {.gcsafe.} = p.codec = TestCodec p.handler = handle -proc createSwitch(ma: MultiAddress; outgoing: bool): (Switch, PeerInfo) = +proc createSwitch(ma: MultiAddress; outgoing: bool, secio: bool = false): (Switch, PeerInfo) = var peerInfo: PeerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) peerInfo.addrs.add(ma) let identify = newIdentify(peerInfo) @@ -58,7 +59,10 @@ proc createSwitch(ma: MultiAddress; outgoing: bool): (Switch, PeerInfo) = let mplexProvider = newMuxerProvider(createMplex, MplexCodec) let transports = @[Transport(TcpTransport.init())] let muxers = [(MplexCodec, mplexProvider)].toTable() - let secureManagers = [Secure(newNoise(rng, peerInfo.privateKey, outgoing = outgoing))] + let secureManagers = if secio: + [Secure(newSecio(rng, peerInfo.privateKey))] + else: + [Secure(newNoise(rng, peerInfo.privateKey, outgoing = outgoing))] let switch = newSwitch(peerInfo, transports, identify, @@ -109,6 +113,43 @@ suite "Noise": check: waitFor(testListenerDialer()) == true + test "e2e: handle write + noise (wrong prologue)": + proc testListenerDialer(): Future[bool] {.async.} = + let + server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() + serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server]) + serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false) + + proc connHandler(conn: Connection) {.async, gcsafe.} = + let sconn = await serverNoise.secure(conn, false) + try: + await sconn.write("Hello!") + finally: + await sconn.close() + await conn.close() + + let + transport1: TcpTransport = TcpTransport.init() + asyncCheck await transport1.listen(server, connHandler) + + let + transport2: TcpTransport = TcpTransport.init() + clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma]) + clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true, commonPrologue = @[1'u8, 2'u8, 3'u8]) + conn = await transport2.dial(transport1.ma) + var sconn: Connection = nil + expect(NoiseDecryptTagError): + sconn = await clientNoise.secure(conn, true) + + await conn.close() + await transport1.close() + await transport2.close() + + result = true + + check: + waitFor(testListenerDialer()) == true + test "e2e: handle read + noise": proc testListenerDialer(): Future[bool] {.async.} = let @@ -228,6 +269,38 @@ suite "Noise": check: waitFor(testSwitch()) == true + test "e2e test wrong secure negotiation": + proc testSwitch(): Future[bool] {.async, gcsafe.} = + let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() + let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() + + var peerInfo1, peerInfo2: PeerInfo + var switch1, switch2: Switch + var awaiters: seq[Future[void]] + + (switch1, peerInfo1) = createSwitch(ma1, false) + + let testProto = new TestProto + testProto.init() + testProto.codec = TestCodec + switch1.mount(testProto) + (switch2, peerInfo2) = createSwitch(ma2, true, true) # secio, we want to fail + awaiters.add(await switch1.start()) + awaiters.add(await switch2.start()) + expect(UpgradeFailedError): + let conn = await switch2.dial(switch1.peerInfo, TestCodec) + + await allFuturesThrowing( + switch1.stop(), + switch2.stop()) + + await allFuturesThrowing(awaiters) + + result = true + + check: + waitFor(testSwitch()) == true + # test "interop with rust noise": # when true: # disable cos in CI we got no interop server/client # proc testListenerDialer(): Future[bool] {.async.} = diff --git a/tests/testswitch.nim b/tests/testswitch.nim index 2d5a1d164..a2015658c 100644 --- a/tests/testswitch.nim +++ b/tests/testswitch.nim @@ -598,3 +598,16 @@ suite "Switch": await allFuturesThrowing(awaiters) waitFor(testSwitch()) + + test "connect to inexistent peer": + proc testSwitch() {.async, gcsafe.} = + let switch2 = newStandardSwitch(secureManagers = [SecureProtocol.Noise]) + let sfut = await switch2.start() + let someAddr = MultiAddress.init("/ip4/127.128.0.99").get() + let seckey = PrivateKey.random(ECDSA, rng[]).get() + let somePeer = PeerInfo.init(secKey, [someAddr]) + expect(DialFailedError): + let conn = await switch2.dial(somePeer, TestCodec) + await switch2.stop() + + waitFor(testSwitch())