From 95a017b28c8212e790d25728e0ded570920c99c2 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 8 Sep 2022 17:00:31 +0200 Subject: [PATCH 01/21] First draft of dial method --- libp2p/transports/socks5transport.nim | 109 ++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 libp2p/transports/socks5transport.nim diff --git a/libp2p/transports/socks5transport.nim b/libp2p/transports/socks5transport.nim new file mode 100644 index 0000000000..4af8056329 --- /dev/null +++ b/libp2p/transports/socks5transport.nim @@ -0,0 +1,109 @@ +import chronos, chronicles, strutils +import stew/byteutils +import ../multicodec +import transport, + ../multiaddress, + ../stream/connection, + ../stream/chronosstream + +type + Socks5Transport* = ref object of Transport + transportAddress: TransportAddress + +proc new*( + T: typedesc[Socks5Transport], + address: string, + port: Port): T {.public.} = + ## Creates a SOCKS5 transport + + T( + transportAddress: initTAddress(address, port)) + +proc connHandler*(self: Socks5Transport, + client: StreamTransport, + dir: Direction): Future[Connection] {.async.} = + var observedAddr: MultiAddress = MultiAddress() + try: + observedAddr = MultiAddress.init(client.remoteAddress).tryGet() + except CatchableError as exc: + trace "Failed to create observedAddr", exc = exc.msg + if not(isNil(client) and client.closed): + await client.closeWait() + raise exc + + trace "Handling tcp connection", address = $observedAddr, + dir = $dir, + clients = self.clients[Direction.In].len + + self.clients[Direction.Out].len + + let conn = Connection( + ChronosStream.init( + client = client, + dir = dir, + observedAddr = observedAddr + )) + + proc onClose() {.async.} = + try: + let futs = @[client.join(), conn.join()] + await futs[0] or futs[1] + for f in futs: + if not f.finished: await f.cancelAndWait() # cancel outstanding join() + + trace "Cleaning up client", addrs = $client.remoteAddress, + conn + + #self.clients[dir].keepItIf( it != client ) + await allFuturesThrowing( + conn.close(), client.closeWait()) + + trace "Cleaned up client", addrs = $client.remoteAddress, + conn + + except CatchableError as exc: + let useExc {.used.} = exc + debug "Error cleaning up client", errMsg = exc.msg, conn + + #self.clients[dir].add(client) + asyncSpawn onClose() + + return conn + +method dial*( + self: Socks5Transport, + hostname: string, + address: MultiAddress): Future[Connection] {.async, gcsafe.} = + ## dial a peer + ## + + trace "Dialing remote peer", address = $address + + let transp = await connect(self.transportAddress) + var bytesWritten = await transp.write(@[05'u8, 01, 00]) + var resp = await transp.read(2) + + let addressArray = ($address).split('/') + let addressStr = addressArray[2].split(':')[0] & ".onion" + + let port = string.fromBytes(address.data.buffer[37..38]) + + bytesWritten = await transp.write("\x05\x01\x00\x03" & addressStr.len.char & addressStr & port) + echo bytesWritten + resp = await transp.read(10) + echo resp + + return await self.connHandler(transp, Direction.Out) + +let s = Socks5Transport.new("127.0.0.1", 9150.Port) +let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") +let conn = waitFor s.dial("", ma.tryGet()) + +let addressStr = "torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd.onion" +waitFor conn.write("GET / HTTP/1.1\nHost: $#\n\n" % [addressStr]) +var resp: array[1000, byte] +waitFor conn.readExactly(addr resp, 1000) +echo string.fromBytes(resp) + + + + From 48b214e0ead3ae16a43fe4e16df660c10b174076 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 15 Sep 2022 10:29:18 +0200 Subject: [PATCH 02/21] First draft of start, stop and accept methods --- libp2p/stream/lpstream.nim | 2 +- libp2p/transports/socks5transport.nim | 88 ++++++++++++++++++--------- libp2p/transports/tcptransport.nim | 2 +- tests/testsocks5transport.nim | 60 ++++++++++++++++++ 4 files changed, 122 insertions(+), 30 deletions(-) create mode 100644 tests/testsocks5transport.nim diff --git a/libp2p/stream/lpstream.nim b/libp2p/stream/lpstream.nim index e2b73278ba..e604baa237 100644 --- a/libp2p/stream/lpstream.nim +++ b/libp2p/stream/lpstream.nim @@ -80,7 +80,7 @@ type opened*: uint64 closed*: uint64 -proc setupStreamTracker(name: string): StreamTracker = +proc setupStreamTracker*(name: string): StreamTracker = let tracker = new StreamTracker proc dumpTracking(): string {.gcsafe.} = diff --git a/libp2p/transports/socks5transport.nim b/libp2p/transports/socks5transport.nim index 4af8056329..50cd6a259b 100644 --- a/libp2p/transports/socks5transport.nim +++ b/libp2p/transports/socks5transport.nim @@ -1,30 +1,44 @@ + +when (NimMajor, NimMinor) < (1, 4): + {.push raises: [Defect].} +else: + {.push raises: [].} + +import std/[oids, sequtils] import chronos, chronicles, strutils import stew/byteutils import ../multicodec import transport, + tcptransport, + ../wire, + ../stream/[lpstream, connection, chronosstream], ../multiaddress, - ../stream/connection, - ../stream/chronosstream + ../upgrademngrs/upgrade + +const + Socks5TransportTrackerName* = "libp2p.socks5transport" type Socks5Transport* = ref object of Transport transportAddress: TransportAddress + tcpTransport: TcpTransport proc new*( T: typedesc[Socks5Transport], address: string, - port: Port): T {.public.} = + port: Port): T {.public, raises: [Defect, TransportAddressError]} = ## Creates a SOCKS5 transport T( - transportAddress: initTAddress(address, port)) + transportAddress: initTAddress(address, port), + tcpTransport: TcpTransport.new(upgrade = Upgrade())) proc connHandler*(self: Socks5Transport, client: StreamTransport, dir: Direction): Future[Connection] {.async.} = var observedAddr: MultiAddress = MultiAddress() try: - observedAddr = MultiAddress.init(client.remoteAddress).tryGet() + observedAddr = MultiAddress.init("/ip4/0.0.0.0").tryGet() except CatchableError as exc: trace "Failed to create observedAddr", exc = exc.msg if not(isNil(client) and client.closed): @@ -33,8 +47,8 @@ proc connHandler*(self: Socks5Transport, trace "Handling tcp connection", address = $observedAddr, dir = $dir, - clients = self.clients[Direction.In].len + - self.clients[Direction.Out].len + clients = self.tcpTransport.clients[Direction.In].len + + self.tcpTransport.clients[Direction.Out].len let conn = Connection( ChronosStream.init( @@ -53,7 +67,7 @@ proc connHandler*(self: Socks5Transport, trace "Cleaning up client", addrs = $client.remoteAddress, conn - #self.clients[dir].keepItIf( it != client ) + self.tcpTransport.clients[dir].keepItIf( it != client ) await allFuturesThrowing( conn.close(), client.closeWait()) @@ -64,7 +78,7 @@ proc connHandler*(self: Socks5Transport, let useExc {.used.} = exc debug "Error cleaning up client", errMsg = exc.msg, conn - #self.clients[dir].add(client) + self.tcpTransport.clients[dir].add(client) asyncSpawn onClose() return conn @@ -77,32 +91,50 @@ method dial*( ## trace "Dialing remote peer", address = $address + try: + let transp = await connect(self.transportAddress) + var bytesWritten = await transp.write(@[05'u8, 01, 00]) + var resp = await transp.read(2) + + let addressArray = ($address).split('/') + let addressStr = addressArray[2].split(':')[0] & ".onion" + + let port = string.fromBytes(address.data.buffer[37..38]) + + bytesWritten = await transp.write("\x05\x01\x00\x03" & addressStr.len.char & addressStr & port) + resp = await transp.read(10) + echo resp + + return await self.connHandler(transp, Direction.Out) + except CatchableError as err: + await transp.closeWait() + raise err + +method start*( + self: Socks5Transport, + addrs: seq[MultiAddress]) {.async.} = + ## listen on the transport + ## + + await self.tcpTransport.start(addrs) + +method accept*(self: Socks5Transport): Future[Connection] {.async, gcsafe.} = + ## accept a new TCP connection + ## + return await self.tcpTransport.accept() + +method stop*(self: Socks5Transport) {.async, gcsafe.} = + ## stop the transport + ## + await self.tcpTransport.stop() + - let transp = await connect(self.transportAddress) - var bytesWritten = await transp.write(@[05'u8, 01, 00]) - var resp = await transp.read(2) - let addressArray = ($address).split('/') - let addressStr = addressArray[2].split(':')[0] & ".onion" - let port = string.fromBytes(address.data.buffer[37..38]) - bytesWritten = await transp.write("\x05\x01\x00\x03" & addressStr.len.char & addressStr & port) - echo bytesWritten - resp = await transp.read(10) - echo resp - return await self.connHandler(transp, Direction.Out) -let s = Socks5Transport.new("127.0.0.1", 9150.Port) -let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") -let conn = waitFor s.dial("", ma.tryGet()) -let addressStr = "torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd.onion" -waitFor conn.write("GET / HTTP/1.1\nHost: $#\n\n" % [addressStr]) -var resp: array[1000, byte] -waitFor conn.readExactly(addr resp, 1000) -echo string.fromBytes(resp) diff --git a/libp2p/transports/tcptransport.nim b/libp2p/transports/tcptransport.nim index 6d0d321820..ad7b2f3921 100644 --- a/libp2p/transports/tcptransport.nim +++ b/libp2p/transports/tcptransport.nim @@ -40,7 +40,7 @@ const type TcpTransport* = ref object of Transport servers*: seq[StreamServer] - clients: array[Direction, seq[StreamTransport]] + clients*: array[Direction, seq[StreamTransport]] flags: set[ServerFlags] acceptFuts: seq[Future[StreamTransport]] diff --git a/tests/testsocks5transport.nim b/tests/testsocks5transport.nim new file mode 100644 index 0000000000..ed1d49d7ce --- /dev/null +++ b/tests/testsocks5transport.nim @@ -0,0 +1,60 @@ +{.used.} + +import std/strformat +import sequtils +import chronos, stew/byteutils +import ../libp2p/[stream/connection, + transports/transport, + transports/socks5transport, + upgrademngrs/upgrade, + multiaddress, + errors, + wire] + +import ./helpers, ./commontransport + +suite "SOCKS5 transport": + teardown: + checkTrackers() + + asyncTest "test dial": + let s = Socks5Transport.new("127.0.0.1", 9050.Port) + let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") + let conn = await s.dial("", ma.tryGet()) + + let addressStr = "torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd.onion" + await conn.write(fmt("GET / HTTP/1.1\nHost: {addressStr}\n\n")) + var resp: array[1000, byte] + await conn.readExactly(addr resp, 1000) + await conn.close() + echo string.fromBytes(resp) + + asyncTest "test start": + proc a() {.async, raises:[].} = + let s = Socks5Transport.new("127.0.0.1", 9050.Port) + let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") + let conn = await s.dial("", ma.tryGet()) + + let addressStr = "a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion" + await conn.write(fmt("GET / HTTP/1.1\nHost: {addressStr}\n\n")) + var resp: array[5, byte] + await conn.readExactly(addr resp, 5) + await conn.close() + #await s.stop() + echo string.fromBytes(resp) + + let server = Socks5Transport.new("127.0.0.1", 9150.Port) + let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080").tryGet()] + asyncSpawn server.start(ma) + + proc acceptHandler() {.async, gcsafe.} = + let conn = await server.accept() + await conn.write("Hello!") + await conn.close() + + let handlerWait = acceptHandler() + + await a() + + await handlerWait.wait(1.seconds) # when no issues will not wait that long! + await server.stop() From 55e8fa4a9c91c3f40f4c08980d63a1f270d02924 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 15 Sep 2022 11:23:36 +0200 Subject: [PATCH 03/21] Renaming to Tor Transport --- .../{socks5transport.nim => tortransport.nim} | 20 +++++++++---------- ...cks5transport.nim => testtortransport.nim} | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) rename libp2p/transports/{socks5transport.nim => tortransport.nim} (88%) rename tests/{testsocks5transport.nim => testtortransport.nim} (87%) diff --git a/libp2p/transports/socks5transport.nim b/libp2p/transports/tortransport.nim similarity index 88% rename from libp2p/transports/socks5transport.nim rename to libp2p/transports/tortransport.nim index 50cd6a259b..64ad5db16a 100644 --- a/libp2p/transports/socks5transport.nim +++ b/libp2p/transports/tortransport.nim @@ -16,24 +16,24 @@ import transport, ../upgrademngrs/upgrade const - Socks5TransportTrackerName* = "libp2p.socks5transport" + Socks5TransportTrackerName* = "libp2p.tortransport" type - Socks5Transport* = ref object of Transport + TorTransport* = ref object of Transport transportAddress: TransportAddress tcpTransport: TcpTransport proc new*( - T: typedesc[Socks5Transport], + T: typedesc[TorTransport], address: string, port: Port): T {.public, raises: [Defect, TransportAddressError]} = - ## Creates a SOCKS5 transport + ## Creates a Tor transport T( transportAddress: initTAddress(address, port), tcpTransport: TcpTransport.new(upgrade = Upgrade())) -proc connHandler*(self: Socks5Transport, +proc connHandler*(self: TorTransport, client: StreamTransport, dir: Direction): Future[Connection] {.async.} = var observedAddr: MultiAddress = MultiAddress() @@ -84,15 +84,15 @@ proc connHandler*(self: Socks5Transport, return conn method dial*( - self: Socks5Transport, + self: TorTransport, hostname: string, address: MultiAddress): Future[Connection] {.async, gcsafe.} = ## dial a peer ## trace "Dialing remote peer", address = $address + let transp = await connect(self.transportAddress) try: - let transp = await connect(self.transportAddress) var bytesWritten = await transp.write(@[05'u8, 01, 00]) var resp = await transp.read(2) @@ -111,19 +111,19 @@ method dial*( raise err method start*( - self: Socks5Transport, + self: TorTransport, addrs: seq[MultiAddress]) {.async.} = ## listen on the transport ## await self.tcpTransport.start(addrs) -method accept*(self: Socks5Transport): Future[Connection] {.async, gcsafe.} = +method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = ## accept a new TCP connection ## return await self.tcpTransport.accept() -method stop*(self: Socks5Transport) {.async, gcsafe.} = +method stop*(self: TorTransport) {.async, gcsafe.} = ## stop the transport ## await self.tcpTransport.stop() diff --git a/tests/testsocks5transport.nim b/tests/testtortransport.nim similarity index 87% rename from tests/testsocks5transport.nim rename to tests/testtortransport.nim index ed1d49d7ce..dbcb4cc4e9 100644 --- a/tests/testsocks5transport.nim +++ b/tests/testtortransport.nim @@ -5,7 +5,7 @@ import sequtils import chronos, stew/byteutils import ../libp2p/[stream/connection, transports/transport, - transports/socks5transport, + transports/tortransport, upgrademngrs/upgrade, multiaddress, errors, @@ -13,12 +13,12 @@ import ../libp2p/[stream/connection, import ./helpers, ./commontransport -suite "SOCKS5 transport": +suite "Tor transport": teardown: checkTrackers() asyncTest "test dial": - let s = Socks5Transport.new("127.0.0.1", 9050.Port) + let s = TorTransport.new("127.0.0.1", 9050.Port) let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") let conn = await s.dial("", ma.tryGet()) @@ -31,7 +31,7 @@ suite "SOCKS5 transport": asyncTest "test start": proc a() {.async, raises:[].} = - let s = Socks5Transport.new("127.0.0.1", 9050.Port) + let s = TorTransport.new("127.0.0.1", 9050.Port) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") let conn = await s.dial("", ma.tryGet()) @@ -43,7 +43,7 @@ suite "SOCKS5 transport": #await s.stop() echo string.fromBytes(resp) - let server = Socks5Transport.new("127.0.0.1", 9150.Port) + let server = TorTransport.new("127.0.0.1", 9150.Port) let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080").tryGet()] asyncSpawn server.start(ma) From f02368ba69ed2ef50594e979f87504d0713a8dab Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 19 Sep 2022 14:30:19 +0200 Subject: [PATCH 04/21] Improvements and addressing code review comments --- libp2p/transports/tortransport.nim | 81 +++++++++++++++++++----------- tests/testtortransport.nim | 10 ++-- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 64ad5db16a..9f4bf4ed8a 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -7,6 +7,7 @@ else: import std/[oids, sequtils] import chronos, chronicles, strutils import stew/byteutils +import stew/endians2 import ../multicodec import transport, tcptransport, @@ -18,6 +19,8 @@ import transport, const Socks5TransportTrackerName* = "libp2p.tortransport" + ONIO3_MATCHER = mapAnd(TCP, mapEq("onion3")) + type TorTransport* = ref object of Transport transportAddress: TransportAddress @@ -25,12 +28,11 @@ type proc new*( T: typedesc[TorTransport], - address: string, - port: Port): T {.public, raises: [Defect, TransportAddressError]} = + transportAddress: TransportAddress): T {.public.} = ## Creates a Tor transport T( - transportAddress: initTAddress(address, port), + transportAddress: transportAddress, tcpTransport: TcpTransport.new(upgrade = Upgrade())) proc connHandler*(self: TorTransport, @@ -83,6 +85,31 @@ proc connHandler*(self: TorTransport, return conn +proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = + let transp = await connect(transportAddress) + try: + var bytesWritten = await transp.write(@[05'u8, 01, 00]) + var resp = await transp.read(2) + return transp + except CatchableError as err: + await transp.closeWait() + raise err + +proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = + + let addressArray = ($address).split('/') + let addressStr = addressArray[2].split(':')[0] & ".onion" + + # The address field contains a fully-qualified domain name. + # The first octet of the address field contains the number of octets of name that + # follow, there is no terminating NUL octet. + let dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() + let dstPort = address.data.buffer[37..38] + let b = @[05'u8, 01, 00, 03] & dstAddr & dstPort + + discard await transp.write(b) + discard await transp.read(10) + method dial*( self: TorTransport, hostname: string, @@ -91,20 +118,10 @@ method dial*( ## trace "Dialing remote peer", address = $address - let transp = await connect(self.transportAddress) - try: - var bytesWritten = await transp.write(@[05'u8, 01, 00]) - var resp = await transp.read(2) - - let addressArray = ($address).split('/') - let addressStr = addressArray[2].split(':')[0] & ".onion" - - let port = string.fromBytes(address.data.buffer[37..38]) - - bytesWritten = await transp.write("\x05\x01\x00\x03" & addressStr.len.char & addressStr & port) - resp = await transp.read(10) - echo resp + let transp = await connectToTorServer(self.transportAddress) + try: + await dialPeer(transp, address) return await self.connHandler(transp, Direction.Out) except CatchableError as err: await transp.closeWait() @@ -116,7 +133,22 @@ method start*( ## listen on the transport ## - await self.tcpTransport.start(addrs) + #await procCall Transport(self).start(addrs) + var ipTcpAddrs: seq[MultiAddress] + var onion3Addrs: seq[MultiAddress] + for i, ma in addrs: + if not self.handles(ma): + trace "Invalid address detected, skipping!", address = ma + continue + + let ipTcp = ma[0..1].get() + ipTcpAddrs.add(ipTcp) + let onion3 = ma[multiCodec("onion3")].get() + onion3Addrs.add(onion3) + + if len(ipTcpAddrs) != 0 and len(onion3Addrs) != 0: + await self.tcpTransport.start(ipTcpAddrs) + self.addrs = onion3Addrs method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = ## accept a new TCP connection @@ -128,14 +160,7 @@ method stop*(self: TorTransport) {.async, gcsafe.} = ## await self.tcpTransport.stop() - - - - - - - - - - - +method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = + if procCall Transport(t).handles(address): + if address.protocols.isOk: + return ONIO3_MATCHER.match(address) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index dbcb4cc4e9..badd2de3b3 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -13,12 +13,14 @@ import ../libp2p/[stream/connection, import ./helpers, ./commontransport +let torServer = initTAddress("127.0.0.1", 9050.Port) + suite "Tor transport": teardown: checkTrackers() asyncTest "test dial": - let s = TorTransport.new("127.0.0.1", 9050.Port) + let s = TorTransport.new(torServer) let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") let conn = await s.dial("", ma.tryGet()) @@ -31,7 +33,7 @@ suite "Tor transport": asyncTest "test start": proc a() {.async, raises:[].} = - let s = TorTransport.new("127.0.0.1", 9050.Port) + let s = TorTransport.new(initTAddress("127.0.0.1", 9050.Port)) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") let conn = await s.dial("", ma.tryGet()) @@ -43,8 +45,8 @@ suite "Tor transport": #await s.stop() echo string.fromBytes(resp) - let server = TorTransport.new("127.0.0.1", 9150.Port) - let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080").tryGet()] + let server = TorTransport.new(initTAddress("127.0.0.1", 9050.Port)) + let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] asyncSpawn server.start(ma) proc acceptHandler() {.async, gcsafe.} = From 6dd27fef5f7a0b8887074c7cf1f7547d89a42610 Mon Sep 17 00:00:00 2001 From: Diego Date: Tue, 20 Sep 2022 13:00:36 +0200 Subject: [PATCH 05/21] More improvements after code review comments --- libp2p/transports/tortransport.nim | 17 ++++++++++------- tests/testtortransport.nim | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 9f4bf4ed8a..bf2ea48920 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -24,16 +24,20 @@ const type TorTransport* = ref object of Transport transportAddress: TransportAddress + flags: set[ServerFlags] tcpTransport: TcpTransport proc new*( T: typedesc[TorTransport], - transportAddress: TransportAddress): T {.public.} = + transportAddress: TransportAddress, + flags: set[ServerFlags] = {}, + upgrade: Upgrade): T {.public.} = ## Creates a Tor transport T( transportAddress: transportAddress, - tcpTransport: TcpTransport.new(upgrade = Upgrade())) + flags: flags, + tcpTransport: TcpTransport.new(upgrade = upgrade)) proc connHandler*(self: TorTransport, client: StreamTransport, @@ -88,8 +92,8 @@ proc connHandler*(self: TorTransport, proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) try: - var bytesWritten = await transp.write(@[05'u8, 01, 00]) - var resp = await transp.read(2) + discard await transp.write(@[05'u8, 01, 00]) + discard await transp.read(2) return transp except CatchableError as err: await transp.closeWait() @@ -108,7 +112,7 @@ proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} let b = @[05'u8, 01, 00, 03] & dstAddr & dstPort discard await transp.write(b) - discard await transp.read(10) + echo await transp.read(5) method dial*( self: TorTransport, @@ -133,7 +137,6 @@ method start*( ## listen on the transport ## - #await procCall Transport(self).start(addrs) var ipTcpAddrs: seq[MultiAddress] var onion3Addrs: seq[MultiAddress] for i, ma in addrs: @@ -147,8 +150,8 @@ method start*( onion3Addrs.add(onion3) if len(ipTcpAddrs) != 0 and len(onion3Addrs) != 0: + await procCall Transport(self).start(onion3Addrs) await self.tcpTransport.start(ipTcpAddrs) - self.addrs = onion3Addrs method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = ## accept a new TCP connection diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index badd2de3b3..1d2739bb85 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -20,7 +20,7 @@ suite "Tor transport": checkTrackers() asyncTest "test dial": - let s = TorTransport.new(torServer) + let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") let conn = await s.dial("", ma.tryGet()) @@ -33,7 +33,7 @@ suite "Tor transport": asyncTest "test start": proc a() {.async, raises:[].} = - let s = TorTransport.new(initTAddress("127.0.0.1", 9050.Port)) + let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") let conn = await s.dial("", ma.tryGet()) @@ -45,7 +45,7 @@ suite "Tor transport": #await s.stop() echo string.fromBytes(resp) - let server = TorTransport.new(initTAddress("127.0.0.1", 9050.Port)) + let server = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] asyncSpawn server.start(ma) From 2cb68d2fa6fdc3e49a0ecb7faa7485eac08dcfed Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 22 Sep 2022 14:04:38 +0200 Subject: [PATCH 06/21] Use tcp transport connHandler --- libp2p/transports/tortransport.nim | 61 +++--------------------------- tests/testnative.nim | 1 + 2 files changed, 6 insertions(+), 56 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index bf2ea48920..0b92ca563a 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -6,8 +6,7 @@ else: import std/[oids, sequtils] import chronos, chronicles, strutils -import stew/byteutils -import stew/endians2 +import stew/[byteutils, endians2, results] import ../multicodec import transport, tcptransport, @@ -39,56 +38,6 @@ proc new*( flags: flags, tcpTransport: TcpTransport.new(upgrade = upgrade)) -proc connHandler*(self: TorTransport, - client: StreamTransport, - dir: Direction): Future[Connection] {.async.} = - var observedAddr: MultiAddress = MultiAddress() - try: - observedAddr = MultiAddress.init("/ip4/0.0.0.0").tryGet() - except CatchableError as exc: - trace "Failed to create observedAddr", exc = exc.msg - if not(isNil(client) and client.closed): - await client.closeWait() - raise exc - - trace "Handling tcp connection", address = $observedAddr, - dir = $dir, - clients = self.tcpTransport.clients[Direction.In].len + - self.tcpTransport.clients[Direction.Out].len - - let conn = Connection( - ChronosStream.init( - client = client, - dir = dir, - observedAddr = observedAddr - )) - - proc onClose() {.async.} = - try: - let futs = @[client.join(), conn.join()] - await futs[0] or futs[1] - for f in futs: - if not f.finished: await f.cancelAndWait() # cancel outstanding join() - - trace "Cleaning up client", addrs = $client.remoteAddress, - conn - - self.tcpTransport.clients[dir].keepItIf( it != client ) - await allFuturesThrowing( - conn.close(), client.closeWait()) - - trace "Cleaned up client", addrs = $client.remoteAddress, - conn - - except CatchableError as exc: - let useExc {.used.} = exc - debug "Error cleaning up client", errMsg = exc.msg, conn - - self.tcpTransport.clients[dir].add(client) - asyncSpawn onClose() - - return conn - proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) try: @@ -126,7 +75,7 @@ method dial*( try: await dialPeer(transp, address) - return await self.connHandler(transp, Direction.Out) + return await self.tcpTransport.connHandler(transp, Opt.none(MultiAddress), Direction.Out) except CatchableError as err: await transp.closeWait() raise err @@ -143,11 +92,11 @@ method start*( if not self.handles(ma): trace "Invalid address detected, skipping!", address = ma continue - + let ipTcp = ma[0..1].get() ipTcpAddrs.add(ipTcp) let onion3 = ma[multiCodec("onion3")].get() - onion3Addrs.add(onion3) + onion3Addrs.add(onion3) if len(ipTcpAddrs) != 0 and len(onion3Addrs) != 0: await procCall Transport(self).start(onion3Addrs) @@ -163,7 +112,7 @@ method stop*(self: TorTransport) {.async, gcsafe.} = ## await self.tcpTransport.stop() -method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = +method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): if address.protocols.isOk: return ONIO3_MATCHER.match(address) diff --git a/tests/testnative.nim b/tests/testnative.nim index f35971b4b2..cc04fab66c 100644 --- a/tests/testnative.nim +++ b/tests/testnative.nim @@ -23,6 +23,7 @@ import testmultibase, testrouting_record import testtcptransport, + testtortransport, testnameresolve, testwstransport, testmultistream, From 34bfda0878951689a504d46f308a5145fad6fc2a Mon Sep 17 00:00:00 2001 From: Diego Date: Tue, 27 Sep 2022 13:29:39 +0200 Subject: [PATCH 07/21] Using builder and more code improvements --- libp2p/builders.nim | 5 +- libp2p/transports/tortransport.nim | 39 ++++++++++++---- tests/testtortransport.nim | 75 ++++++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 14 deletions(-) diff --git a/libp2p/builders.nim b/libp2p/builders.nim index fdff75ba0a..611e057c87 100644 --- a/libp2p/builders.nim +++ b/libp2p/builders.nim @@ -24,7 +24,7 @@ else: import options, tables, chronos, chronicles, sequtils, switch, peerid, peerinfo, stream/connection, multiaddress, - crypto/crypto, transports/[transport, tcptransport], + crypto/crypto, transports/[transport, tcptransport, tortransport], muxers/[muxer, mplex/mplex, yamux/yamux], protocols/[identify, secure/secure, secure/noise, rendezvous], protocols/connectivity/[autonat, relay/relay, relay/client, relay/rtransport], @@ -147,6 +147,9 @@ proc withTransport*(b: SwitchBuilder, prov: TransportProvider): SwitchBuilder {. proc withTcpTransport*(b: SwitchBuilder, flags: set[ServerFlags] = {}): SwitchBuilder {.public.} = b.withTransport(proc(upgr: Upgrade): Transport = TcpTransport.new(flags, upgr)) +proc withTorTransport*(b: SwitchBuilder, torServerForDialing: TransportAddress, flags: set[ServerFlags] = {}): SwitchBuilder {.public} = + b.withTransport(proc(upgr: Upgrade): Transport = TorTransport.new(torServerForDialing, flags, upgr)) + proc withRng*(b: SwitchBuilder, rng: ref HmacDrbgContext): SwitchBuilder {.public.} = b.rng = rng b diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 0b92ca563a..c130309a66 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -18,12 +18,14 @@ import transport, const Socks5TransportTrackerName* = "libp2p.tortransport" - ONIO3_MATCHER = mapAnd(TCP, mapEq("onion3")) + ONIO3_MATCHER = mapEq("onion3") + TCP_ONIO3_MATCHER = mapAnd(TCP, ONIO3_MATCHER) type + TransportStartError* = object of transport.TransportError + TorTransport* = ref object of Transport transportAddress: TransportAddress - flags: set[ServerFlags] tcpTransport: TcpTransport proc new*( @@ -35,8 +37,8 @@ proc new*( T( transportAddress: transportAddress, - flags: flags, - tcpTransport: TcpTransport.new(upgrade = upgrade)) + upgrader: upgrade, + tcpTransport: TcpTransport.new(flags, upgrade)) proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) @@ -48,6 +50,23 @@ proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransp await transp.closeWait() raise err +proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = + ## The specification for this code is defined on [link text](https://www.rfc-editor.org/rfc/rfc1928#section-5) + ## and [link text](https://www.rfc-editor.org/rfc/rfc1928#section-6). + let portNumOctets = 2 + let ipV4NumOctets = 4 + let ipV6NumOctets = 16 + let firstFourOctets = await transp.read(4) + let atyp = firstFourOctets[3] + case atyp: + of 0x01: + discard await transp.read(ipV4NumOctets + portNumOctets) + of 0x03: + let fqdnNumOctets = await transp.read(1) + discard await transp.read(int(uint8.fromBytes(fqdnNumOctets)) + portNumOctets) + else: + discard await transp.read(ipV6NumOctets + portNumOctets) + proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = let addressArray = ($address).split('/') @@ -59,9 +78,8 @@ proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} let dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() let dstPort = address.data.buffer[37..38] let b = @[05'u8, 01, 00, 03] & dstAddr & dstPort - discard await transp.write(b) - echo await transp.read(5) + await readServerReply(transp) method dial*( self: TorTransport, @@ -89,8 +107,8 @@ method start*( var ipTcpAddrs: seq[MultiAddress] var onion3Addrs: seq[MultiAddress] for i, ma in addrs: - if not self.handles(ma): - trace "Invalid address detected, skipping!", address = ma + if not TCP_ONIO3_MATCHER.match(ma): + warn "Invalid address detected, skipping!", address = ma continue let ipTcp = ma[0..1].get() @@ -101,6 +119,8 @@ method start*( if len(ipTcpAddrs) != 0 and len(onion3Addrs) != 0: await procCall Transport(self).start(onion3Addrs) await self.tcpTransport.start(ipTcpAddrs) + else: + raise newException(TransportStartError, "Tor Transport couldn't start, no supported addr was provided.") method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = ## accept a new TCP connection @@ -110,9 +130,10 @@ method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = method stop*(self: TorTransport) {.async, gcsafe.} = ## stop the transport ## + await procCall Transport(self).stop() # call base await self.tcpTransport.stop() method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): if address.protocols.isOk: - return ONIO3_MATCHER.match(address) + return ONIO3_MATCHER.match(address) or TCP_ONIO3_MATCHER.match(address) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 1d2739bb85..fe84bdfd56 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -9,7 +9,8 @@ import ../libp2p/[stream/connection, upgrademngrs/upgrade, multiaddress, errors, - wire] + wire, + builders] import ./helpers, ./commontransport @@ -31,7 +32,7 @@ suite "Tor transport": await conn.close() echo string.fromBytes(resp) - asyncTest "test start": + asyncTest "test dial and start": proc a() {.async, raises:[].} = let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") @@ -45,9 +46,9 @@ suite "Tor transport": #await s.stop() echo string.fromBytes(resp) - let server = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) + let server = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] - asyncSpawn server.start(ma) + await server.start(ma) proc acceptHandler() {.async, gcsafe.} = let conn = await server.accept() @@ -60,3 +61,69 @@ suite "Tor transport": await handlerWait.wait(1.seconds) # when no issues will not wait that long! await server.stop() + + asyncTest "test dial and start with builder": + + ## + # Create our custom protocol + ## + const TestCodec = "/test/proto/1.0.0" # custom protocol string identifier + + type + TestProto = ref object of LPProtocol # declare a custom protocol + + proc new(T: typedesc[TestProto]): T = + + # every incoming connections will be in handled in this closure + proc handle(conn: Connection, proto: string) {.async, gcsafe.} = + echo "Got from remote - ", string.fromBytes(await conn.readLp(1024)) + await conn.writeLp("Roger p2p!") + + # We must close the connections ourselves when we're done with it + await conn.close() + + return T(codecs: @[TestCodec], handler: handle) + + + let rng = newRng() + + let ma = MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet() + + let serverSwitch = SwitchBuilder.new() + .withRng(rng) + .withTorTransport(torServer, {ReuseAddr}) + .withAddress(ma) + .withMplex() + .withNoise() + .build() + + # setup the custom proto + let testProto = TestProto.new() + + serverSwitch.mount(testProto) + await serverSwitch.start() + + let serverPeerId = serverSwitch.peerInfo.peerId + let serverAddress = serverSwitch.peerInfo.addrs + + proc a(): Future[Switch] {.async, raises:[].} = + let clientSwitch = SwitchBuilder.new() + .withRng(rng) + .withTorTransport(torServer) + .withMplex() + .withNoise() + .build() + + let conn = await clientSwitch.dial(serverPeerId, serverAddress, TestCodec) + + await conn.writeLp("Hello p2p!") + + echo "Remote responded with - ", string.fromBytes(await conn.readLp(1024)) + await conn.close() + return clientSwitch + + let client = await a() + + await allFutures(serverSwitch.stop(), client.stop()) + + From 716b468598a817bb9eeee6f2a6b707802a5ac69c Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 28 Sep 2022 17:55:53 +0200 Subject: [PATCH 08/21] Implementing tor server stub and improving tests --- tests/testtortransport.nim | 118 +++++++++++++++++++++++++------------ 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index fe84bdfd56..0a0c538ba2 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -1,66 +1,101 @@ {.used.} -import std/strformat -import sequtils -import chronos, stew/byteutils +import chronos, stew/[byteutils, endians2] import ../libp2p/[stream/connection, + protocols/connectivity/relay/utils, transports/transport, + transports/tcptransport, transports/tortransport, upgrademngrs/upgrade, multiaddress, errors, - wire, builders] import ./helpers, ./commontransport let torServer = initTAddress("127.0.0.1", 9050.Port) + +type + TorServerStub = ref object of RootObj + tcpTransport: TcpTransport + +proc new( + T: typedesc[TorServerStub]): T {.public.} = + + T( + tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade())) + +proc start(self: TorServerStub) {.async, raises: [].} = + let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/9050").tryGet()] + + await self.tcpTransport.start(ma) + + var msg = newSeq[byte](3) + + let connSrc = await self.tcpTransport.accept() + await connSrc.readExactly(addr msg[0], 3) + + await connSrc.write(@[05'u8, 00]) + + msg = newSeq[byte](5) + await connSrc.readExactly(addr msg[0], 5) + let n = int(uint8.fromBytes(msg[4..4])) + msg = newSeq[byte](n) + await connSrc.readExactly(addr msg[0], n + 2) # +2 bytes for the port + + await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) + + let connDst = await self.tcpTransport.dial("", MultiAddress.init("/ip4/127.0.0.1/tcp/8080").tryGet()) + + await bridge(connSrc, connDst) + + + +proc stop(self: TorServerStub) {.async, raises: [].} = + await self.tcpTransport.stop() + suite "Tor transport": teardown: checkTrackers() - asyncTest "test dial": - let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) - let ma = MultiAddress.init("/onion3/torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd:80") - let conn = await s.dial("", ma.tryGet()) - - let addressStr = "torchdeedp3i2jigzjdmfpn5ttjhthh5wbmda2rr3jvqjg5p77c54dqd.onion" - await conn.write(fmt("GET / HTTP/1.1\nHost: {addressStr}\n\n")) - var resp: array[1000, byte] - await conn.readExactly(addr resp, 1000) - await conn.close() - echo string.fromBytes(resp) - asyncTest "test dial and start": - proc a() {.async, raises:[].} = + + proc startClient() {.async, raises:[].} = let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") let conn = await s.dial("", ma.tryGet()) - let addressStr = "a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion" - await conn.write(fmt("GET / HTTP/1.1\nHost: {addressStr}\n\n")) - var resp: array[5, byte] - await conn.readExactly(addr resp, 5) + await conn.write("client") + var resp: array[6, byte] + discard await conn.readOnce(addr resp, 6) await conn.close() - #await s.stop() - echo string.fromBytes(resp) + + check string.fromBytes(resp) == "server" let server = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) - let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] - await server.start(ma) + let ma2 = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] + await server.start(ma2) proc acceptHandler() {.async, gcsafe.} = let conn = await server.accept() - await conn.write("Hello!") + + var resp: array[6, byte] + discard await conn.readOnce(addr resp, 6) + check string.fromBytes(resp) == "client" + + await conn.write("server") await conn.close() - let handlerWait = acceptHandler() + let stub = TorServerStub.new() + asyncSpawn stub.start() + + asyncSpawn acceptHandler() - await a() + await startClient() + + await allFutures(server.stop(), stub.stop()) - await handlerWait.wait(1.seconds) # when no issues will not wait that long! - await server.stop() asyncTest "test dial and start with builder": @@ -76,8 +111,11 @@ suite "Tor transport": # every incoming connections will be in handled in this closure proc handle(conn: Connection, proto: string) {.async, gcsafe.} = - echo "Got from remote - ", string.fromBytes(await conn.readLp(1024)) - await conn.writeLp("Roger p2p!") + + var resp: array[6, byte] + discard await conn.readOnce(addr resp, 6) + check string.fromBytes(resp) == "client" + await conn.write("server") # We must close the connections ourselves when we're done with it await conn.close() @@ -106,7 +144,7 @@ suite "Tor transport": let serverPeerId = serverSwitch.peerInfo.peerId let serverAddress = serverSwitch.peerInfo.addrs - proc a(): Future[Switch] {.async, raises:[].} = + proc startClient() {.async, raises:[].} = let clientSwitch = SwitchBuilder.new() .withRng(rng) .withTorTransport(torServer) @@ -116,14 +154,18 @@ suite "Tor transport": let conn = await clientSwitch.dial(serverPeerId, serverAddress, TestCodec) - await conn.writeLp("Hello p2p!") + await conn.write("client") - echo "Remote responded with - ", string.fromBytes(await conn.readLp(1024)) + var resp: array[6, byte] + await conn.readExactly(addr resp, 6) + check string.fromBytes(resp) == "server" await conn.close() - return clientSwitch - let client = await a() + let stub = TorServerStub.new() + asyncSpawn stub.start() + + await startClient() - await allFutures(serverSwitch.stop(), client.stop()) + await allFutures(serverSwitch.stop(), stub.stop()) From b8dec6abbb160fd325a964ff00b150d1ed5d5c7a Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 28 Sep 2022 22:59:32 +0200 Subject: [PATCH 09/21] More tests improvements --- tests/testtortransport.nim | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 0a0c538ba2..73e592f436 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -1,9 +1,9 @@ {.used.} +import tables import chronos, stew/[byteutils, endians2] import ../libp2p/[stream/connection, protocols/connectivity/relay/utils, - transports/transport, transports/tcptransport, transports/tortransport, upgrademngrs/upgrade, @@ -13,21 +13,25 @@ import ../libp2p/[stream/connection, import ./helpers, ./commontransport -let torServer = initTAddress("127.0.0.1", 9050.Port) - +const torServer = initTAddress("127.0.0.1", 9050.Port) type TorServerStub = ref object of RootObj tcpTransport: TcpTransport + addrTable: Table[string, string] proc new( T: typedesc[TorServerStub]): T {.public.} = T( - tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade())) + tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade()), + addrTable: initTable[string, string]()) + +proc registerOnionAddr(self: TorServerStub, key: string, val: string) = + self.addrTable[key] = val proc start(self: TorServerStub) {.async, raises: [].} = - let ma = @[MultiAddress.init("/ip4/127.0.0.1/tcp/9050").tryGet()] + let ma = @[MultiAddress.init(torServer).tryGet()] await self.tcpTransport.start(ma) @@ -40,17 +44,19 @@ proc start(self: TorServerStub) {.async, raises: [].} = msg = newSeq[byte](5) await connSrc.readExactly(addr msg[0], 5) - let n = int(uint8.fromBytes(msg[4..4])) + let n = int(uint8.fromBytes(msg[4..4])) + 2 # +2 bytes for the port msg = newSeq[byte](n) - await connSrc.readExactly(addr msg[0], n + 2) # +2 bytes for the port + await connSrc.readExactly(addr msg[0], n) - await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) + let onionAddr = string.fromBytes(msg[0..^3]) # ignore the port - let connDst = await self.tcpTransport.dial("", MultiAddress.init("/ip4/127.0.0.1/tcp/8080").tryGet()) + let tcpIpAddr = self.addrTable[$(onionAddr)] - await bridge(connSrc, connDst) + await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) + let connDst = await self.tcpTransport.dial("", MultiAddress.init(tcpIpAddr).tryGet()) + await bridge(connSrc, connDst) proc stop(self: TorServerStub) {.async, raises: [].} = await self.tcpTransport.stop() @@ -88,6 +94,8 @@ suite "Tor transport": await conn.close() let stub = TorServerStub.new() + stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") + asyncSpawn stub.start() asyncSpawn acceptHandler() @@ -162,6 +170,7 @@ suite "Tor transport": await conn.close() let stub = TorServerStub.new() + stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") asyncSpawn stub.start() await startClient() From ca185da478e1274fc4a406cd2d2bcf7663acf95b Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 28 Sep 2022 23:57:05 +0200 Subject: [PATCH 10/21] Try to fix CI --- tests/testtortransport.nim | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 73e592f436..a8bb16010d 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -1,5 +1,10 @@ {.used.} +when (NimMajor, NimMinor) < (1, 4): + {.push raises: [Defect].} +else: + {.push raises: [].} + import tables import chronos, stew/[byteutils, endians2] import ../libp2p/[stream/connection, @@ -30,7 +35,7 @@ proc new( proc registerOnionAddr(self: TorServerStub, key: string, val: string) = self.addrTable[key] = val -proc start(self: TorServerStub) {.async, raises: [].} = +proc start(self: TorServerStub) {.async.} = let ma = @[MultiAddress.init(torServer).tryGet()] await self.tcpTransport.start(ma) @@ -58,7 +63,7 @@ proc start(self: TorServerStub) {.async, raises: [].} = await bridge(connSrc, connDst) -proc stop(self: TorServerStub) {.async, raises: [].} = +proc stop(self: TorServerStub) {.async.} = await self.tcpTransport.stop() suite "Tor transport": @@ -67,7 +72,7 @@ suite "Tor transport": asyncTest "test dial and start": - proc startClient() {.async, raises:[].} = + proc startClient() {.async.} = let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") let conn = await s.dial("", ma.tryGet()) @@ -152,7 +157,7 @@ suite "Tor transport": let serverPeerId = serverSwitch.peerInfo.peerId let serverAddress = serverSwitch.peerInfo.addrs - proc startClient() {.async, raises:[].} = + proc startClient() {.async.} = let clientSwitch = SwitchBuilder.new() .withRng(rng) .withTorTransport(torServer) From a0cf7107bfaba23156d87235fee8e2b2fd40a94a Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 5 Oct 2022 23:38:01 -0500 Subject: [PATCH 11/21] Code improvements --- libp2p/transports/tortransport.nim | 76 +++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index c130309a66..0d021a85b7 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -1,33 +1,58 @@ +# Nim-LibP2P +# Copyright (c) 2022 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. + +## Tor transport implementation when (NimMajor, NimMinor) < (1, 4): {.push raises: [Defect].} else: {.push raises: [].} -import std/[oids, sequtils] import chronos, chronicles, strutils import stew/[byteutils, endians2, results] import ../multicodec import transport, tcptransport, - ../wire, ../stream/[lpstream, connection, chronosstream], ../multiaddress, ../upgrademngrs/upgrade const - Socks5TransportTrackerName* = "libp2p.tortransport" + Socks5ProtocolVersion = byte(5) + NMethods = byte(1) - ONIO3_MATCHER = mapEq("onion3") - TCP_ONIO3_MATCHER = mapAnd(TCP, ONIO3_MATCHER) + Onion3Matcher = mapEq("onion3") + TcpOnion3Matcher = mapAnd(TCP, Onion3Matcher) type - TransportStartError* = object of transport.TransportError - TorTransport* = ref object of Transport transportAddress: TransportAddress tcpTransport: TcpTransport + Socks5AuthMethod* {.pure.} = enum + NoAuth = 0 + GSSAPI = 1 + UsernamePassword = 2 + NoAcceptableMethod = 0xff + + Socks5RequestCommand* {.pure.} = enum + Connect = 1, Bind = 2, UdpAssoc = 3 + + Socks5AddressType* {.pure.} = enum + IPv4 = 1, FQDN = 3, IPv6 = 4 + + TransportStartError* = object of transport.TransportError + + Socks5Error* = object of CatchableError + Socks5AuthFailedError* = object of Socks5Error + Socks5VersionError* = object of Socks5Error + proc new*( T: typedesc[TorTransport], transportAddress: TransportAddress, @@ -40,18 +65,26 @@ proc new*( upgrader: upgrade, tcpTransport: TcpTransport.new(flags, upgrade)) -proc connectToTorServer(transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = +proc connectToTorServer( + transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) try: - discard await transp.write(@[05'u8, 01, 00]) - discard await transp.read(2) + discard await transp.write(@[Socks5ProtocolVersion, NMethods, Socks5AuthMethod.NoAuth.byte]) + let serverReply = await transp.read(2) + let socks5ProtocolVersion = serverReply[0] + let serverSelectedMethod =serverReply[1] + if socks5ProtocolVersion != Socks5ProtocolVersion: + raise newException(Socks5VersionError, "Unsupported socks version") + if serverSelectedMethod != Socks5AuthMethod.NoAuth.byte: + raise newException(Socks5AuthFailedError, "Unsupported auth method") return transp except CatchableError as err: await transp.closeWait() raise err proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = - ## The specification for this code is defined on [link text](https://www.rfc-editor.org/rfc/rfc1928#section-5) + ## The specification for this code is defined on + ## [link text](https://www.rfc-editor.org/rfc/rfc1928#section-5) ## and [link text](https://www.rfc-editor.org/rfc/rfc1928#section-6). let portNumOctets = 2 let ipV4NumOctets = 4 @@ -59,15 +92,16 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = let firstFourOctets = await transp.read(4) let atyp = firstFourOctets[3] case atyp: - of 0x01: + of Socks5AddressType.IPv4.byte: discard await transp.read(ipV4NumOctets + portNumOctets) - of 0x03: + of Socks5AddressType.FQDN.byte: let fqdnNumOctets = await transp.read(1) discard await transp.read(int(uint8.fromBytes(fqdnNumOctets)) + portNumOctets) else: discard await transp.read(ipV6NumOctets + portNumOctets) -proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = +proc dialPeer( + transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = let addressArray = ($address).split('/') let addressStr = addressArray[2].split(':')[0] & ".onion" @@ -77,7 +111,13 @@ proc dialPeer(transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} # follow, there is no terminating NUL octet. let dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() let dstPort = address.data.buffer[37..38] - let b = @[05'u8, 01, 00, 03] & dstAddr & dstPort + let reserved = byte(0) + let b = @[ + Socks5ProtocolVersion, + Socks5RequestCommand.Connect.byte, + reserved, + Socks5AddressType.FQDN.byte] & dstAddr & dstPort + discard await transp.write(b) await readServerReply(transp) @@ -107,7 +147,7 @@ method start*( var ipTcpAddrs: seq[MultiAddress] var onion3Addrs: seq[MultiAddress] for i, ma in addrs: - if not TCP_ONIO3_MATCHER.match(ma): + if not TcpOnion3Matcher.match(ma): warn "Invalid address detected, skipping!", address = ma continue @@ -123,7 +163,7 @@ method start*( raise newException(TransportStartError, "Tor Transport couldn't start, no supported addr was provided.") method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = - ## accept a new TCP connection + ## accept a new Tor connection ## return await self.tcpTransport.accept() @@ -136,4 +176,4 @@ method stop*(self: TorTransport) {.async, gcsafe.} = method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): if address.protocols.isOk: - return ONIO3_MATCHER.match(address) or TCP_ONIO3_MATCHER.match(address) + return Onion3Matcher.match(address) or TcpOnion3Matcher.match(address) From e430d8f129cb03e1cc390a0b3b6236967b070375 Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 24 Oct 2022 15:31:06 +0200 Subject: [PATCH 12/21] Add common transport test --- libp2p/transports/tortransport.nim | 24 ++++++--- tests/commontransport.nim | 55 ++++++++++--------- tests/stubs.nim | 67 ++++++++++++++++++++++++ tests/testtcptransport.nim | 1 - tests/testtortransport.nim | 84 +++++++----------------------- tests/testwstransport.nim | 2 - 6 files changed, 128 insertions(+), 105 deletions(-) create mode 100644 tests/stubs.nim diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 0d021a85b7..492246f8c2 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -65,6 +65,12 @@ proc new*( upgrader: upgrade, tcpTransport: TcpTransport.new(flags, upgrade)) +proc handlesDial(address: MultiAddress): bool {.gcsafe.} = + return Onion3Matcher.match(address) + +proc handlesStart(address: MultiAddress): bool {.gcsafe.} = + return TcpOnion3Matcher.match(address) + proc connectToTorServer( transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) @@ -144,28 +150,30 @@ method start*( ## listen on the transport ## - var ipTcpAddrs: seq[MultiAddress] + var listenAddrs: seq[MultiAddress] var onion3Addrs: seq[MultiAddress] for i, ma in addrs: - if not TcpOnion3Matcher.match(ma): + if not handlesStart(ma): warn "Invalid address detected, skipping!", address = ma continue - let ipTcp = ma[0..1].get() - ipTcpAddrs.add(ipTcp) + let listenAddress = ma[0..1].get() + listenAddrs.add(listenAddress) let onion3 = ma[multiCodec("onion3")].get() onion3Addrs.add(onion3) - if len(ipTcpAddrs) != 0 and len(onion3Addrs) != 0: + if len(listenAddrs) != 0 and len(onion3Addrs) != 0: await procCall Transport(self).start(onion3Addrs) - await self.tcpTransport.start(ipTcpAddrs) + await self.tcpTransport.start(listenAddrs) else: raise newException(TransportStartError, "Tor Transport couldn't start, no supported addr was provided.") method accept*(self: TorTransport): Future[Connection] {.async, gcsafe.} = ## accept a new Tor connection ## - return await self.tcpTransport.accept() + let conn = await self.tcpTransport.accept() + conn.observedAddr = Opt.none(MultiAddress) + return conn method stop*(self: TorTransport) {.async, gcsafe.} = ## stop the transport @@ -176,4 +184,4 @@ method stop*(self: TorTransport) {.async, gcsafe.} = method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): if address.protocols.isOk: - return Onion3Matcher.match(address) or TcpOnion3Matcher.match(address) + return handlesDial(address) or handlesStart(address) diff --git a/tests/commontransport.nim b/tests/commontransport.nim index af29add613..b46479b541 100644 --- a/tests/commontransport.nim +++ b/tests/commontransport.nim @@ -13,25 +13,24 @@ import ./helpers type TransportProvider* = proc(): Transport {.gcsafe, raises: [Defect].} -proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = - suite name & " common tests": - teardown: - checkTrackers() +template commonTransportTest*(prov: TransportProvider, ma1: string, ma2: string = "") = + block: + let transpProvider = prov asyncTest "can handle local address": - let ma = @[MultiAddress.init(ma).tryGet()] - let transport1 = prov() + let ma = @[MultiAddress.init(ma1).tryGet()] + let transport1 = transpProvider() await transport1.start(ma) check transport1.handles(transport1.addrs[0]) await transport1.stop() asyncTest "e2e: handle observedAddr": - let ma = @[MultiAddress.init(ma).tryGet()] + let ma = @[MultiAddress.init(ma1).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(ma) - let transport2 = prov() + let transport2 = transpProvider() proc acceptHandler() {.async, gcsafe.} = let conn = await transport1.accept() @@ -56,9 +55,9 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = await handlerWait.wait(1.seconds) # when no issues will not wait that long! asyncTest "e2e: handle write": - let ma = @[MultiAddress.init(ma).tryGet()] + let ma = @[MultiAddress.init(ma1).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(ma) proc acceptHandler() {.async, gcsafe.} = @@ -68,7 +67,7 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = let handlerWait = acceptHandler() - let transport2 = prov() + let transport2 = transpProvider() let conn = await transport2.dial(transport1.addrs[0]) var msg = newSeq[byte](6) await conn.readExactly(addr msg[0], 6) @@ -84,8 +83,8 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = await handlerWait.wait(1.seconds) # when no issues will not wait that long! asyncTest "e2e: handle read": - let ma = @[MultiAddress.init(ma).tryGet()] - let transport1 = prov() + let ma = @[MultiAddress.init(ma1).tryGet()] + let transport1 = transpProvider() await transport1.start(ma) proc acceptHandler() {.async, gcsafe.} = @@ -97,7 +96,7 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = let handlerWait = acceptHandler() - let transport2 = prov() + let transport2 = transpProvider() let conn = await transport2.dial(transport1.addrs[0]) await conn.write("Hello!") @@ -110,12 +109,12 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = transport2.stop())) asyncTest "e2e: handle dial cancellation": - let ma = @[MultiAddress.init(ma).tryGet()] + let ma = @[MultiAddress.init(ma1).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(ma) - let transport2 = prov() + let transport2 = transpProvider() let cancellation = transport2.dial(transport1.addrs[0]) await cancellation.cancelAndWait() @@ -127,9 +126,9 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = transport2.stop())) asyncTest "e2e: handle accept cancellation": - let ma = @[MultiAddress.init(ma).tryGet()] + let ma = @[MultiAddress.init(ma1).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(ma) let acceptHandler = transport1.accept() @@ -143,11 +142,11 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = # this randomly locks the Windows CI job skip() return - let addrs = @[MultiAddress.init(ma).tryGet(), - MultiAddress.init(ma).tryGet()] + let addrs = @[MultiAddress.init(ma1).tryGet(), + MultiAddress.init(if ma2 == "": ma1 else: ma2).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(addrs) proc acceptHandler() {.async, gcsafe.} = @@ -192,12 +191,12 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = await transport1.stop() asyncTest "e2e: stopping transport kills connections": - let ma = @[MultiAddress.init(ma).tryGet()] + let ma = @[MultiAddress.init(ma1).tryGet()] - let transport1 = prov() + let transport1 = transpProvider() await transport1.start(ma) - let transport2 = prov() + let transport2 = transpProvider() let acceptHandler = transport1.accept() let conn = await transport2.dial(transport1.addrs[0]) @@ -212,8 +211,8 @@ proc commonTransportTest*(name: string, prov: TransportProvider, ma: string) = check conn.closed() asyncTest "read or write on closed connection": - let ma = @[MultiAddress.init(ma).tryGet()] - let transport1 = prov() + let ma = @[MultiAddress.init(ma1).tryGet()] + let transport1 = transpProvider() await transport1.start(ma) proc acceptHandler() {.async, gcsafe.} = diff --git a/tests/stubs.nim b/tests/stubs.nim new file mode 100644 index 0000000000..2978d8e5ad --- /dev/null +++ b/tests/stubs.nim @@ -0,0 +1,67 @@ +{.used.} + +when (NimMajor, NimMinor) < (1, 4): + {.push raises: [Defect].} +else: + {.push raises: [].} + +import tables +import chronos, stew/[byteutils, endians2] +import ../libp2p/[stream/connection, + protocols/connectivity/relay/utils, + transports/tcptransport, + transports/tortransport, + upgrademngrs/upgrade, + multiaddress, + errors, + builders] + +const torServer = initTAddress("127.0.0.1", 9050.Port) + +type + TorServerStub* = ref object of RootObj + tcpTransport: TcpTransport + addrTable: Table[string, string] + +proc new*( + T: typedesc[TorServerStub]): T {.public.} = + + T( + tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade()), + addrTable: initTable[string, string]()) + +proc registerOnionAddr*(self: TorServerStub, key: string, val: string) = + self.addrTable[key] = val + +proc start*(self: TorServerStub) {.async.} = + let ma = @[MultiAddress.init(torServer).tryGet()] + + await self.tcpTransport.start(ma) + + var msg = newSeq[byte](3) + while self.tcpTransport.running: + let connSrc = await self.tcpTransport.accept() + await connSrc.readExactly(addr msg[0], 3) + + await connSrc.write(@[05'u8, 00]) + + msg = newSeq[byte](5) + await connSrc.readExactly(addr msg[0], 5) + let n = int(uint8.fromBytes(msg[4..4])) + 2 # +2 bytes for the port + msg = newSeq[byte](n) + await connSrc.readExactly(addr msg[0], n) + + let onionAddr = string.fromBytes(msg[0..^3]) # ignore the port + + let tcpIpAddr = self.addrTable[$(onionAddr)] + + await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) + + let connDst = await self.tcpTransport.dial("", MultiAddress.init(tcpIpAddr).tryGet()) + + await bridge(connSrc, connDst) + await allFutures(connSrc.close(), connDst.close()) + + +proc stop*(self: TorServerStub) {.async.} = + await self.tcpTransport.stop() \ No newline at end of file diff --git a/tests/testtcptransport.nim b/tests/testtcptransport.nim index 64d5d8f6b4..522c737174 100644 --- a/tests/testtcptransport.nim +++ b/tests/testtcptransport.nim @@ -126,6 +126,5 @@ suite "TCP transport": await server.join() commonTransportTest( - "TcpTransport", proc (): Transport = TcpTransport.new(upgrade = Upgrade()), "/ip4/0.0.0.0/tcp/0") diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index a8bb16010d..09830cc55c 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -16,62 +16,23 @@ import ../libp2p/[stream/connection, errors, builders] -import ./helpers, ./commontransport +import ./helpers, ./stubs, ./commontransport const torServer = initTAddress("127.0.0.1", 9050.Port) - -type - TorServerStub = ref object of RootObj - tcpTransport: TcpTransport - addrTable: Table[string, string] - -proc new( - T: typedesc[TorServerStub]): T {.public.} = - - T( - tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade()), - addrTable: initTable[string, string]()) - -proc registerOnionAddr(self: TorServerStub, key: string, val: string) = - self.addrTable[key] = val - -proc start(self: TorServerStub) {.async.} = - let ma = @[MultiAddress.init(torServer).tryGet()] - - await self.tcpTransport.start(ma) - - var msg = newSeq[byte](3) - - let connSrc = await self.tcpTransport.accept() - await connSrc.readExactly(addr msg[0], 3) - - await connSrc.write(@[05'u8, 00]) - - msg = newSeq[byte](5) - await connSrc.readExactly(addr msg[0], 5) - let n = int(uint8.fromBytes(msg[4..4])) + 2 # +2 bytes for the port - msg = newSeq[byte](n) - await connSrc.readExactly(addr msg[0], n) - - let onionAddr = string.fromBytes(msg[0..^3]) # ignore the port - - let tcpIpAddr = self.addrTable[$(onionAddr)] - - await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) - - let connDst = await self.tcpTransport.dial("", MultiAddress.init(tcpIpAddr).tryGet()) - - await bridge(connSrc, connDst) - -proc stop(self: TorServerStub) {.async.} = - await self.tcpTransport.stop() - +var stub: TorServerStub +var startFut: Future[void] suite "Tor transport": + setup: + stub = TorServerStub.new() + stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") + stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae.onion", "/ip4/127.0.0.1/tcp/8081") + startFut = stub.start() teardown: + waitFor startFut.cancelAndWait() + waitFor stub.stop() checkTrackers() asyncTest "test dial and start": - proc startClient() {.async.} = let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") @@ -98,23 +59,13 @@ suite "Tor transport": await conn.write("server") await conn.close() - let stub = TorServerStub.new() - stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") - - asyncSpawn stub.start() - asyncSpawn acceptHandler() await startClient() - await allFutures(server.stop(), stub.stop()) - + await server.stop() asyncTest "test dial and start with builder": - - ## - # Create our custom protocol - ## const TestCodec = "/test/proto/1.0.0" # custom protocol string identifier type @@ -135,7 +86,6 @@ suite "Tor transport": return T(codecs: @[TestCodec], handler: handle) - let rng = newRng() let ma = MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet() @@ -174,12 +124,14 @@ suite "Tor transport": check string.fromBytes(resp) == "server" await conn.close() - let stub = TorServerStub.new() - stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") - asyncSpawn stub.start() - await startClient() - await allFutures(serverSwitch.stop(), stub.stop()) + await serverSwitch.stop() + + commonTransportTest( + proc (): Transport = TorTransport.new(transportAddress = torServer, flags = {ReuseAddr}, upgrade = Upgrade()), + "/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80", + "/ip4/127.0.0.1/tcp/8081/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae:80") + diff --git a/tests/testwstransport.nim b/tests/testwstransport.nim index 0e46b009e8..39a1269e74 100644 --- a/tests/testwstransport.nim +++ b/tests/testwstransport.nim @@ -56,12 +56,10 @@ suite "WebSocket transport": checkTrackers() commonTransportTest( - "WebSocket", proc (): Transport = WsTransport.new(Upgrade()), "/ip4/0.0.0.0/tcp/0/ws") commonTransportTest( - "WebSocket Secure", (proc (): Transport {.gcsafe.} = try: return WsTransport.new( From c5c3e0b8963b86c4d7d3c2e7352a7e1c3fabaf0d Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 24 Oct 2022 17:37:37 +0200 Subject: [PATCH 13/21] Keeping compatibility with nim 1.2 --- tests/testtcptransport.nim | 4 +++- tests/testtortransport.nim | 5 +++-- tests/testwstransport.nim | 11 +++++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/testtcptransport.nim b/tests/testtcptransport.nim index 522c737174..9c2ee264fc 100644 --- a/tests/testtcptransport.nim +++ b/tests/testtcptransport.nim @@ -125,6 +125,8 @@ suite "TCP transport": server.close() await server.join() + proc transProvider(): Transport = TcpTransport.new(upgrade = Upgrade()) + commonTransportTest( - proc (): Transport = TcpTransport.new(upgrade = Upgrade()), + transProvider, "/ip4/0.0.0.0/tcp/0") diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 09830cc55c..dadf9bb0cc 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -128,10 +128,11 @@ suite "Tor transport": await serverSwitch.stop() + proc transProvider(): Transport = TorTransport.new(transportAddress = torServer, flags = {ReuseAddr}, upgrade = Upgrade()) + commonTransportTest( - proc (): Transport = TorTransport.new(transportAddress = torServer, flags = {ReuseAddr}, upgrade = Upgrade()), + transProvider, "/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80", "/ip4/127.0.0.1/tcp/8081/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae:80") - diff --git a/tests/testwstransport.nim b/tests/testwstransport.nim index 39a1269e74..c2ac887511 100644 --- a/tests/testwstransport.nim +++ b/tests/testwstransport.nim @@ -55,12 +55,13 @@ suite "WebSocket transport": teardown: checkTrackers() + proc wsTraspProvider(): Transport = WsTransport.new(Upgrade()) + commonTransportTest( - proc (): Transport = WsTransport.new(Upgrade()), + wsTraspProvider, "/ip4/0.0.0.0/tcp/0/ws") - commonTransportTest( - (proc (): Transport {.gcsafe.} = + proc wsSecureTranspProvider(): Transport {.gcsafe.} = try: return WsTransport.new( Upgrade(), @@ -68,7 +69,9 @@ suite "WebSocket transport": TLSCertificate.init(SecureCert), {TLSFlags.NoVerifyHost, TLSFlags.NoVerifyServerName}) except Exception: check(false) - ), + + commonTransportTest( + wsSecureTranspProvider, "/ip4/0.0.0.0/tcp/0/wss") asyncTest "Hostname verification": From 6e9528a85a0974cf6d03a2c54c55c26894e08a5b Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 26 Oct 2022 16:57:11 +0200 Subject: [PATCH 14/21] Changes after code review --- libp2p/multiaddress.nim | 2 + libp2p/transports/tortransport.nim | 59 ++++++++++++++++++++---------- tests/testtortransport.nim | 33 ++++++++--------- 3 files changed, 57 insertions(+), 37 deletions(-) diff --git a/libp2p/multiaddress.nim b/libp2p/multiaddress.nim index 055d8b138d..211954d95c 100644 --- a/libp2p/multiaddress.nim +++ b/libp2p/multiaddress.nim @@ -470,6 +470,8 @@ const WS* = mapAnd(TCP, mapEq("ws")) WSS* = mapAnd(TCP, mapEq("wss")) WebSockets* = mapOr(WS, WSS) + Onion3* = mapEq("onion3") + TcpOnion3* = mapAnd(TCP, Onion3) Unreliable* = mapOr(UDP) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 492246f8c2..4adc42a67e 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -14,8 +14,9 @@ when (NimMajor, NimMinor) < (1, 4): else: {.push raises: [].} +import std/strformat import chronos, chronicles, strutils -import stew/[byteutils, endians2, results] +import stew/[byteutils, endians2, results, objects] import ../multicodec import transport, tcptransport, @@ -27,9 +28,6 @@ const Socks5ProtocolVersion = byte(5) NMethods = byte(1) - Onion3Matcher = mapEq("onion3") - TcpOnion3Matcher = mapAnd(TCP, Onion3Matcher) - type TorTransport* = ref object of Transport transportAddress: TransportAddress @@ -47,11 +45,19 @@ type Socks5AddressType* {.pure.} = enum IPv4 = 1, FQDN = 3, IPv6 = 4 + Socks5ReplyType* {.pure.} = enum + Succeeded = (0, "Succeeded"), ServerFailure = (1, "Server Failure"), + ConnectionNotAllowed = (2, "Connection Not Allowed"), NetworkUnreachable = (3, "Network Unreachable"), + HostUnreachable = (4, "Host Unreachable"), ConnectionRefused = (5, "Connection Refused"), + TtlExpired = (6, "Ttl Expired"), CommandNotSupported = (7, "Command Not Supported"), + AddressTypeNotSupported = (8, "Address Type Not Supported") + TransportStartError* = object of transport.TransportError Socks5Error* = object of CatchableError Socks5AuthFailedError* = object of Socks5Error Socks5VersionError* = object of Socks5Error + Socks5ServerReplyError* = object of Socks5Error proc new*( T: typedesc[TorTransport], @@ -66,19 +72,20 @@ proc new*( tcpTransport: TcpTransport.new(flags, upgrade)) proc handlesDial(address: MultiAddress): bool {.gcsafe.} = - return Onion3Matcher.match(address) + return Onion3.match(address) proc handlesStart(address: MultiAddress): bool {.gcsafe.} = - return TcpOnion3Matcher.match(address) + return TcpOnion3.match(address) proc connectToTorServer( transportAddress: TransportAddress): Future[StreamTransport] {.async, gcsafe.} = let transp = await connect(transportAddress) try: discard await transp.write(@[Socks5ProtocolVersion, NMethods, Socks5AuthMethod.NoAuth.byte]) - let serverReply = await transp.read(2) - let socks5ProtocolVersion = serverReply[0] - let serverSelectedMethod =serverReply[1] + let + serverReply = await transp.read(2) + socks5ProtocolVersion = serverReply[0] + serverSelectedMethod = serverReply[1] if socks5ProtocolVersion != Socks5ProtocolVersion: raise newException(Socks5VersionError, "Unsupported socks version") if serverSelectedMethod != Socks5AuthMethod.NoAuth.byte: @@ -92,10 +99,21 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = ## The specification for this code is defined on ## [link text](https://www.rfc-editor.org/rfc/rfc1928#section-5) ## and [link text](https://www.rfc-editor.org/rfc/rfc1928#section-6). - let portNumOctets = 2 - let ipV4NumOctets = 4 - let ipV6NumOctets = 16 - let firstFourOctets = await transp.read(4) + let + portNumOctets = 2 + ipV4NumOctets = 4 + ipV6NumOctets = 16 + firstFourOctets = await transp.read(4) + socks5ProtocolVersion = firstFourOctets[0] + serverReply = firstFourOctets[1] + if socks5ProtocolVersion != Socks5ProtocolVersion: + raise newException(Socks5VersionError, "Unsupported socks version") + if serverReply != Socks5ReplyType.Succeeded.byte: + var socks5ReplyType: Socks5ReplyType + if socks5ReplyType.checkedEnumAssign(serverReply): + raise newException(Socks5ServerReplyError, fmt"Server reply error: {Socks5ReplyType(serverReply)}") + else: + raise newException(LPError, fmt"Unexpected server reply: {serverReply}") let atyp = firstFourOctets[3] case atyp: of Socks5AddressType.IPv4.byte: @@ -115,10 +133,11 @@ proc dialPeer( # The address field contains a fully-qualified domain name. # The first octet of the address field contains the number of octets of name that # follow, there is no terminating NUL octet. - let dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() - let dstPort = address.data.buffer[37..38] - let reserved = byte(0) - let b = @[ + let + dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() + dstPort = address.data.buffer[37..38] + reserved = byte(0) + b = @[ Socks5ProtocolVersion, Socks5RequestCommand.Connect.byte, reserved, @@ -133,7 +152,8 @@ method dial*( address: MultiAddress): Future[Connection] {.async, gcsafe.} = ## dial a peer ## - + if not handlesDial(address): + raise newException(LPError, fmt"Invalid onion3 address: {address}") trace "Dialing remote peer", address = $address let transp = await connectToTorServer(self.transportAddress) @@ -183,5 +203,4 @@ method stop*(self: TorTransport) {.async, gcsafe.} = method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): - if address.protocols.isOk: - return handlesDial(address) or handlesStart(address) + return handlesDial(address) or handlesStart(address) diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index dadf9bb0cc..b716b23d11 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -33,37 +33,35 @@ suite "Tor transport": checkTrackers() asyncTest "test dial and start": - proc startClient() {.async.} = - let s = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) - let ma = MultiAddress.init("/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80") - let conn = await s.dial("", ma.tryGet()) + let server = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) + let ma2 = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] + await server.start(ma2) + + proc runClient() {.async.} = + let client = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) + let conn = await client.dial("", server.addrs[0]) await conn.write("client") var resp: array[6, byte] - discard await conn.readOnce(addr resp, 6) + await conn.readExactly(addr resp, 6) await conn.close() check string.fromBytes(resp) == "server" + await client.stop() - let server = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) - let ma2 = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] - await server.start(ma2) - - proc acceptHandler() {.async, gcsafe.} = + proc serverAcceptHandler() {.async, gcsafe.} = let conn = await server.accept() var resp: array[6, byte] - discard await conn.readOnce(addr resp, 6) + await conn.readExactly(addr resp, 6) check string.fromBytes(resp) == "client" await conn.write("server") await conn.close() + await server.stop() - asyncSpawn acceptHandler() - - await startClient() - - await server.stop() + asyncSpawn serverAcceptHandler() + await runClient() asyncTest "test dial and start with builder": const TestCodec = "/test/proto/1.0.0" # custom protocol string identifier @@ -77,7 +75,7 @@ suite "Tor transport": proc handle(conn: Connection, proto: string) {.async, gcsafe.} = var resp: array[6, byte] - discard await conn.readOnce(addr resp, 6) + await conn.readExactly(addr resp, 6) check string.fromBytes(resp) == "client" await conn.write("server") @@ -123,6 +121,7 @@ suite "Tor transport": await conn.readExactly(addr resp, 6) check string.fromBytes(resp) == "server" await conn.close() + await clientSwitch.stop() await startClient() From 808f3791f35f84f7f5ea1ce72507daf5a35faa56 Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 31 Oct 2022 16:30:58 +0100 Subject: [PATCH 15/21] Add TorSwitch --- libp2p/builders.nim | 3 -- libp2p/transports/tortransport.nim | 42 ++++++++++++++++++++- tests/testtortransport.nim | 60 +++++++----------------------- 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/libp2p/builders.nim b/libp2p/builders.nim index 611e057c87..de14a97c6a 100644 --- a/libp2p/builders.nim +++ b/libp2p/builders.nim @@ -147,9 +147,6 @@ proc withTransport*(b: SwitchBuilder, prov: TransportProvider): SwitchBuilder {. proc withTcpTransport*(b: SwitchBuilder, flags: set[ServerFlags] = {}): SwitchBuilder {.public.} = b.withTransport(proc(upgr: Upgrade): Transport = TcpTransport.new(flags, upgr)) -proc withTorTransport*(b: SwitchBuilder, torServerForDialing: TransportAddress, flags: set[ServerFlags] = {}): SwitchBuilder {.public} = - b.withTransport(proc(upgr: Upgrade): Transport = TorTransport.new(torServerForDialing, flags, upgr)) - proc withRng*(b: SwitchBuilder, rng: ref HmacDrbgContext): SwitchBuilder {.public.} = b.rng = rng b diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 4adc42a67e..87c511ca84 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -20,6 +20,8 @@ import stew/[byteutils, endians2, results, objects] import ../multicodec import transport, tcptransport, + ../switch, + ../builders, ../stream/[lpstream, connection, chronosstream], ../multiaddress, ../upgrademngrs/upgrade @@ -29,7 +31,7 @@ const NMethods = byte(1) type - TorTransport* = ref object of Transport + TorTransport = ref object of Transport transportAddress: TransportAddress tcpTransport: TcpTransport @@ -59,7 +61,7 @@ type Socks5VersionError* = object of Socks5Error Socks5ServerReplyError* = object of Socks5Error -proc new*( +proc new( T: typedesc[TorTransport], transportAddress: TransportAddress, flags: set[ServerFlags] = {}, @@ -204,3 +206,39 @@ method stop*(self: TorTransport) {.async, gcsafe.} = method handles*(t: TorTransport, address: MultiAddress): bool {.gcsafe.} = if procCall Transport(t).handles(address): return handlesDial(address) or handlesStart(address) + +type + TorSwitch* = ref object of Switch + +proc new*( + T: typedesc[TorSwitch], + torServer: TransportAddress, + rng: ref HmacDrbgContext, + addresses: seq[MultiAddress] = @[], + flags: set[ServerFlags] = {}): TorSwitch + {.raises: [LPError], public.} = + var builder = SwitchBuilder.new() + .withRng(rng) + .withTransport(proc(upgr: Upgrade): Transport = TorTransport.new(torServer, flags, upgr)) + if addresses.len != 0: + builder = builder.withAddresses(addresses) + let switch = builder.withMplex() + .withNoise() + .build() + let torSwitch = T( + peerInfo: switch.peerInfo, + ms: switch.ms, + transports: switch.transports, + connManager: switch.connManager, + peerStore: switch.peerStore, + dialer: Dialer.new(switch.peerInfo.peerId, switch.connManager, switch.transports, switch.ms, nil), + nameResolver: nil) + + torSwitch.connManager.peerStore = switch.peerStore + return torSwitch + +method addTransport*(s: TorSwitch, t: Transport) = + doAssert(false, "not implemented!") + +method getTorTransport*(s: TorSwitch): Transport {.base.} = + return s.transports[0] diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index b716b23d11..40238fee98 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -33,37 +33,6 @@ suite "Tor transport": checkTrackers() asyncTest "test dial and start": - let server = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) - let ma2 = @[MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet()] - await server.start(ma2) - - proc runClient() {.async.} = - let client = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) - let conn = await client.dial("", server.addrs[0]) - - await conn.write("client") - var resp: array[6, byte] - await conn.readExactly(addr resp, 6) - await conn.close() - - check string.fromBytes(resp) == "server" - await client.stop() - - proc serverAcceptHandler() {.async, gcsafe.} = - let conn = await server.accept() - - var resp: array[6, byte] - await conn.readExactly(addr resp, 6) - check string.fromBytes(resp) == "client" - - await conn.write("server") - await conn.close() - await server.stop() - - asyncSpawn serverAcceptHandler() - await runClient() - - asyncTest "test dial and start with builder": const TestCodec = "/test/proto/1.0.0" # custom protocol string identifier type @@ -88,13 +57,7 @@ suite "Tor transport": let ma = MultiAddress.init("/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80").tryGet() - let serverSwitch = SwitchBuilder.new() - .withRng(rng) - .withTorTransport(torServer, {ReuseAddr}) - .withAddress(ma) - .withMplex() - .withNoise() - .build() + let serverSwitch = TorSwitch.new(torServer, rng, @[ma], {ReuseAddr}) # setup the custom proto let testProto = TestProto.new() @@ -106,12 +69,7 @@ suite "Tor transport": let serverAddress = serverSwitch.peerInfo.addrs proc startClient() {.async.} = - let clientSwitch = SwitchBuilder.new() - .withRng(rng) - .withTorTransport(torServer) - .withMplex() - .withNoise() - .build() + let clientSwitch = TorSwitch.new(torServer = torServer, rng= rng, flags = {ReuseAddr}) let conn = await clientSwitch.dial(serverPeerId, serverAddress, TestCodec) @@ -127,11 +85,19 @@ suite "Tor transport": await serverSwitch.stop() - proc transProvider(): Transport = TorTransport.new(transportAddress = torServer, flags = {ReuseAddr}, upgrade = Upgrade()) + test "It's not possible to add another transport": + let torSwitch = TorSwitch.new(torServer = torServer, rng= rng, flags = {ReuseAddr}) + expect(AssertionDefect): + torSwitch.addTransport(TcpTransport.new(upgrade = Upgrade())) + waitFor torSwitch.stop() + + proc transProvider(): Transport = + try: + TorSwitch.new(torServer = torServer, rng= rng, flags = {ReuseAddr}).getTorTransport() + except: + raise newException(Defect, "Error when creating Tor Transport") commonTransportTest( transProvider, "/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80", "/ip4/127.0.0.1/tcp/8081/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae:80") - - From 9cc4180064ed2ecee27bffc9e3f2c852e26fa2ce Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 31 Oct 2022 17:23:45 +0100 Subject: [PATCH 16/21] Code improvements --- libp2p/builders.nim | 2 +- libp2p/transports/tcptransport.nim | 2 +- libp2p/transports/tortransport.nim | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libp2p/builders.nim b/libp2p/builders.nim index de14a97c6a..fdff75ba0a 100644 --- a/libp2p/builders.nim +++ b/libp2p/builders.nim @@ -24,7 +24,7 @@ else: import options, tables, chronos, chronicles, sequtils, switch, peerid, peerinfo, stream/connection, multiaddress, - crypto/crypto, transports/[transport, tcptransport, tortransport], + crypto/crypto, transports/[transport, tcptransport], muxers/[muxer, mplex/mplex, yamux/yamux], protocols/[identify, secure/secure, secure/noise, rendezvous], protocols/connectivity/[autonat, relay/relay, relay/client, relay/rtransport], diff --git a/libp2p/transports/tcptransport.nim b/libp2p/transports/tcptransport.nim index ad7b2f3921..6d0d321820 100644 --- a/libp2p/transports/tcptransport.nim +++ b/libp2p/transports/tcptransport.nim @@ -40,7 +40,7 @@ const type TcpTransport* = ref object of Transport servers*: seq[StreamServer] - clients*: array[Direction, seq[StreamTransport]] + clients: array[Direction, seq[StreamTransport]] flags: set[ServerFlags] acceptFuts: seq[Future[StreamTransport]] diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 87c511ca84..a228fa3de6 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -139,13 +139,13 @@ proc dialPeer( dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() dstPort = address.data.buffer[37..38] reserved = byte(0) - b = @[ - Socks5ProtocolVersion, - Socks5RequestCommand.Connect.byte, - reserved, - Socks5AddressType.FQDN.byte] & dstAddr & dstPort + request = @[ + Socks5ProtocolVersion, + Socks5RequestCommand.Connect.byte, + reserved, + Socks5AddressType.FQDN.byte] & dstAddr & dstPort - discard await transp.write(b) + discard await transp.write(request) await readServerReply(transp) method dial*( From 06c1f31ca309044dc38277609a57ffd139d3b18a Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 31 Oct 2022 18:35:43 +0100 Subject: [PATCH 17/21] Fix compilation on 1.2 --- libp2p/transports/tortransport.nim | 2 +- tests/testtcptransport.nim | 2 +- tests/testtortransport.nim | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index a228fa3de6..1f554fed01 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -216,7 +216,7 @@ proc new*( rng: ref HmacDrbgContext, addresses: seq[MultiAddress] = @[], flags: set[ServerFlags] = {}): TorSwitch - {.raises: [LPError], public.} = + {.raises: [LPError, Defect], public.} = var builder = SwitchBuilder.new() .withRng(rng) .withTransport(proc(upgr: Upgrade): Transport = TorTransport.new(torServer, flags, upgr)) diff --git a/tests/testtcptransport.nim b/tests/testtcptransport.nim index 9c2ee264fc..d0666e1d30 100644 --- a/tests/testtcptransport.nim +++ b/tests/testtcptransport.nim @@ -126,7 +126,7 @@ suite "TCP transport": await server.join() proc transProvider(): Transport = TcpTransport.new(upgrade = Upgrade()) - + commonTransportTest( transProvider, "/ip4/0.0.0.0/tcp/0") diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 40238fee98..a729c4f1ac 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -86,6 +86,9 @@ suite "Tor transport": await serverSwitch.stop() test "It's not possible to add another transport": + when (NimMajor, NimMinor, NimPatch) < (1, 4, 0): + type AssertionDefect = AssertionError + let torSwitch = TorSwitch.new(torServer = torServer, rng= rng, flags = {ReuseAddr}) expect(AssertionDefect): torSwitch.addTransport(TcpTransport.new(upgrade = Upgrade())) From 43692285ee99b1f8a93a0b319d738fc5026df7cf Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 2 Nov 2022 12:58:38 +0100 Subject: [PATCH 18/21] Make TorTransport public again --- libp2p/transports/tortransport.nim | 4 ++-- tests/testtortransport.nim | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 1f554fed01..72725e6fab 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -31,7 +31,7 @@ const NMethods = byte(1) type - TorTransport = ref object of Transport + TorTransport* = ref object of Transport transportAddress: TransportAddress tcpTransport: TcpTransport @@ -61,7 +61,7 @@ type Socks5VersionError* = object of Socks5Error Socks5ServerReplyError* = object of Socks5Error -proc new( +proc new*( T: typedesc[TorTransport], transportAddress: TransportAddress, flags: set[ServerFlags] = {}, diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index a729c4f1ac..03b390cffe 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -85,7 +85,7 @@ suite "Tor transport": await serverSwitch.stop() - test "It's not possible to add another transport": + test "It's not possible to add another transport in TorSwitch": when (NimMajor, NimMinor, NimPatch) < (1, 4, 0): type AssertionDefect = AssertionError @@ -95,10 +95,8 @@ suite "Tor transport": waitFor torSwitch.stop() proc transProvider(): Transport = - try: - TorSwitch.new(torServer = torServer, rng= rng, flags = {ReuseAddr}).getTorTransport() - except: - raise newException(Defect, "Error when creating Tor Transport") + TorTransport.new(torServer, {ReuseAddr}, Upgrade()) + commonTransportTest( transProvider, From fbf34ed50e6ba5765e8a6588be31f09d1d3d383f Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 3 Nov 2022 15:30:41 +0100 Subject: [PATCH 19/21] Support dialing ip and dns --- libp2p/transports/tortransport.nim | 67 ++++++++++++++++++++++-------- tests/stubs.nim | 51 ++++++++++++++++------- tests/testtortransport.nim | 59 +++++++++++++++++++++----- 3 files changed, 134 insertions(+), 43 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index 72725e6fab..d003dea5f1 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -27,6 +27,11 @@ import transport, ../upgrademngrs/upgrade const + IPTcp = mapAnd(IP, mapEq("tcp")) + IPv4Tcp = mapAnd(IP4, mapEq("tcp")) + IPv6Tcp = mapAnd(IP6, mapEq("tcp")) + DnsTcp = mapAnd(DNSANY, mapEq("tcp")) + Socks5ProtocolVersion = byte(5) NMethods = byte(1) @@ -74,7 +79,7 @@ proc new*( tcpTransport: TcpTransport.new(flags, upgrade)) proc handlesDial(address: MultiAddress): bool {.gcsafe.} = - return Onion3.match(address) + return Onion3.match(address) or TCP.match(address) or DNSANY.match(address) proc handlesStart(address: MultiAddress): bool {.gcsafe.} = return TcpOnion3.match(address) @@ -119,32 +124,60 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = let atyp = firstFourOctets[3] case atyp: of Socks5AddressType.IPv4.byte: - discard await transp.read(ipV4NumOctets + portNumOctets) + discard await transp.read(ipV4NumOctets + portNumOctets) of Socks5AddressType.FQDN.byte: let fqdnNumOctets = await transp.read(1) discard await transp.read(int(uint8.fromBytes(fqdnNumOctets)) + portNumOctets) else: discard await transp.read(ipV6NumOctets + portNumOctets) -proc dialPeer( - transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = +proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) = + let + addressArray = ($address).split('/') + addressStr = addressArray[2].split(':')[0] & ".onion" + dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() + dstPort = address.data.buffer[37..38] + return (Socks5AddressType.FQDN.byte, dstAddr, dstPort) - let addressArray = ($address).split('/') - let addressStr = addressArray[2].split(':')[0] & ".onion" +proc parseIpTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) = + let (codec, atyp) = + if IPv4Tcp.match(address): + (multiCodec("ip4"), Socks5AddressType.IPv4.byte) + else: + (multiCodec("ip6"), Socks5AddressType.IPv6.byte) + let + dstAddr = address[codec].get().protoArgument().get() + dstPort = address[multiCodec("tcp")].get().protoArgument().get() + (atyp, dstAddr, dstPort) +proc parseDnsTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) = + let + dnsAddress = address[multiCodec("dns")].get().protoArgument().get() + dstAddr = @(uint8(dnsAddress.len).toBytes()) & dnsAddress + dstPort = address[multiCodec("tcp")].get().protoArgument().get() + (Socks5AddressType.FQDN.byte, dstAddr, dstPort) + +proc dialPeer( + transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = # The address field contains a fully-qualified domain name. # The first octet of the address field contains the number of octets of name that # follow, there is no terminating NUL octet. - let - dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() - dstPort = address.data.buffer[37..38] - reserved = byte(0) - request = @[ - Socks5ProtocolVersion, - Socks5RequestCommand.Connect.byte, - reserved, - Socks5AddressType.FQDN.byte] & dstAddr & dstPort - + let (atyp, dstAddr, dstPort) = + if Onion3.match(address): + parseOnion3(address) + elif IPTcp.match(address): + parseIpTcp(address) + elif DnsTcp.match(address): + parseDnsTcp(address) + else: + raise newException(LPError, fmt"Address not supported: {address}") + + let reserved = byte(0) + let request = @[ + Socks5ProtocolVersion, + Socks5RequestCommand.Connect.byte, + reserved, + atyp] & dstAddr & dstPort discard await transp.write(request) await readServerReply(transp) @@ -155,7 +188,7 @@ method dial*( ## dial a peer ## if not handlesDial(address): - raise newException(LPError, fmt"Invalid onion3 address: {address}") + raise newException(LPError, fmt"Not supported address: {address}") trace "Dialing remote peer", address = $address let transp = await connectToTorServer(self.transportAddress) diff --git a/tests/stubs.nim b/tests/stubs.nim index 2978d8e5ad..8ece201848 100644 --- a/tests/stubs.nim +++ b/tests/stubs.nim @@ -6,7 +6,7 @@ else: {.push raises: [].} import tables -import chronos, stew/[byteutils, endians2] +import chronos, stew/[byteutils, endians2, shims/net] import ../libp2p/[stream/connection, protocols/connectivity/relay/utils, transports/tcptransport, @@ -16,8 +16,6 @@ import ../libp2p/[stream/connection, errors, builders] -const torServer = initTAddress("127.0.0.1", 9050.Port) - type TorServerStub* = ref object of RootObj tcpTransport: TcpTransport @@ -30,11 +28,11 @@ proc new*( tcpTransport: TcpTransport.new(flags = {ReuseAddr}, upgrade = Upgrade()), addrTable: initTable[string, string]()) -proc registerOnionAddr*(self: TorServerStub, key: string, val: string) = +proc registerAddr*(self: TorServerStub, key: string, val: string) = self.addrTable[key] = val -proc start*(self: TorServerStub) {.async.} = - let ma = @[MultiAddress.init(torServer).tryGet()] +proc start*(self: TorServerStub, address: TransportAddress) {.async.} = + let ma = @[MultiAddress.init(address).tryGet()] await self.tcpTransport.start(ma) @@ -45,15 +43,36 @@ proc start*(self: TorServerStub) {.async.} = await connSrc.write(@[05'u8, 00]) - msg = newSeq[byte](5) - await connSrc.readExactly(addr msg[0], 5) - let n = int(uint8.fromBytes(msg[4..4])) + 2 # +2 bytes for the port - msg = newSeq[byte](n) - await connSrc.readExactly(addr msg[0], n) - - let onionAddr = string.fromBytes(msg[0..^3]) # ignore the port - - let tcpIpAddr = self.addrTable[$(onionAddr)] + msg = newSeq[byte](4) + await connSrc.readExactly(addr msg[0], 4) + let atyp = int(uint8.fromBytes(msg[3..3])) + let address = case atyp: + of Socks5AddressType.IPv4.ord: + let n = 4 + 2 # +2 bytes for the port + msg = newSeq[byte](n) + await connSrc.readExactly(addr msg[0], n) + var ip: array[4, byte] + for i, e in msg[0..^3]: + ip[i] = e + $(ipv4(ip)) & ":" & $(Port(fromBytesBE(uint16, msg[^2..^1]))) + of Socks5AddressType.IPv6.ord: + let n = 16 + 2 # +2 bytes for the port + msg = newSeq[byte](n) # +2 bytes for the port + await connSrc.readExactly(addr msg[0], n) + var ip: array[16, byte] + for i, e in msg[0..^3]: + ip[i] = e + $(ipv6(ip)) & ":" & $(Port(fromBytesBE(uint16, msg[^2..^1]))) + of Socks5AddressType.FQDN.ord: + await connSrc.readExactly(addr msg[0], 1) + let n = int(uint8.fromBytes(msg[0..0])) + 2 # +2 bytes for the port + msg = newSeq[byte](n) + await connSrc.readExactly(addr msg[0], n) + string.fromBytes(msg[0..^3]) & ":" & $(Port(fromBytesBE(uint16, msg[^2..^1]))) + else: + raise newException(LPError, "Address not supported") + + let tcpIpAddr = self.addrTable[$(address)] await connSrc.write(@[05'u8, 00, 00, 01, 00, 00, 00, 00, 00, 00]) @@ -64,4 +83,4 @@ proc start*(self: TorServerStub) {.async.} = proc stop*(self: TorServerStub) {.async.} = - await self.tcpTransport.stop() \ No newline at end of file + await self.tcpTransport.stop() diff --git a/tests/testtortransport.nim b/tests/testtortransport.nim index 03b390cffe..de9050e5a8 100644 --- a/tests/testtortransport.nim +++ b/tests/testtortransport.nim @@ -6,33 +6,73 @@ else: {.push raises: [].} import tables -import chronos, stew/[byteutils, endians2] +import chronos, stew/[byteutils] import ../libp2p/[stream/connection, - protocols/connectivity/relay/utils, transports/tcptransport, transports/tortransport, upgrademngrs/upgrade, multiaddress, - errors, builders] import ./helpers, ./stubs, ./commontransport -const torServer = initTAddress("127.0.0.1", 9050.Port) +const torServer = initTAddress("127.0.0.1", 9050.Port) var stub: TorServerStub var startFut: Future[void] suite "Tor transport": setup: stub = TorServerStub.new() - stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion", "/ip4/127.0.0.1/tcp/8080") - stub.registerOnionAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae.onion", "/ip4/127.0.0.1/tcp/8081") - startFut = stub.start() + stub.registerAddr("127.0.0.1:8080", "/ip4/127.0.0.1/tcp/8080") + stub.registerAddr("libp2p.nim:8080", "/ip4/127.0.0.1/tcp/8080") + stub.registerAddr("::1:8080", "/ip6/::1/tcp/8080") + stub.registerAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad.onion:80", "/ip4/127.0.0.1/tcp/8080") + stub.registerAddr("a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae.onion:81", "/ip4/127.0.0.1/tcp/8081") + startFut = stub.start(torServer) teardown: waitFor startFut.cancelAndWait() waitFor stub.stop() checkTrackers() - asyncTest "test dial and start": + proc test(lintesAddr: string, dialAddr: string) {.async.} = + let server = TcpTransport.new({ReuseAddr}, Upgrade()) + let ma2 = @[MultiAddress.init(lintesAddr).tryGet()] + await server.start(ma2) + + proc runClient() {.async.} = + let client = TorTransport.new(transportAddress = torServer, upgrade = Upgrade()) + let conn = await client.dial("", MultiAddress.init(dialAddr).tryGet()) + + await conn.write("client") + var resp: array[6, byte] + await conn.readExactly(addr resp, 6) + await conn.close() + + check string.fromBytes(resp) == "server" + await client.stop() + + proc serverAcceptHandler() {.async, gcsafe.} = + let conn = await server.accept() + var resp: array[6, byte] + await conn.readExactly(addr resp, 6) + check string.fromBytes(resp) == "client" + + await conn.write("server") + await conn.close() + await server.stop() + + asyncSpawn serverAcceptHandler() + await runClient() + + asyncTest "test start and dial using ipv4": + await test("/ip4/127.0.0.1/tcp/8080", "/ip4/127.0.0.1/tcp/8080") + + asyncTest "test start and dial using ipv6": + await test("/ip6/::1/tcp/8080", "/ip6/::1/tcp/8080") + + asyncTest "test start and dial using dns": + await test("/ip4/127.0.0.1/tcp/8080", "/dns/libp2p.nim/tcp/8080") + + asyncTest "test start and dial usion onion3 and builder": const TestCodec = "/test/proto/1.0.0" # custom protocol string identifier type @@ -97,8 +137,7 @@ suite "Tor transport": proc transProvider(): Transport = TorTransport.new(torServer, {ReuseAddr}, Upgrade()) - commonTransportTest( transProvider, "/ip4/127.0.0.1/tcp/8080/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcad:80", - "/ip4/127.0.0.1/tcp/8081/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae:80") + "/ip4/127.0.0.1/tcp/8081/onion3/a2mncbqsbullu7thgm4e6zxda2xccmcgzmaq44oayhdtm6rav5vovcae:81") From 76187504d4e2693fffba885155fe27298db38894 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 3 Nov 2022 18:01:27 +0100 Subject: [PATCH 20/21] Improvements --- libp2p/transports/tortransport.nim | 28 ++++++++++++++++------------ tests/stubs.nim | 8 ++++---- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index d003dea5f1..e816b2ecc0 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -118,7 +118,7 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = if serverReply != Socks5ReplyType.Succeeded.byte: var socks5ReplyType: Socks5ReplyType if socks5ReplyType.checkedEnumAssign(serverReply): - raise newException(Socks5ServerReplyError, fmt"Server reply error: {Socks5ReplyType(serverReply)}") + raise newException(Socks5ServerReplyError, fmt"Server reply error: {socks5ReplyType}") else: raise newException(LPError, fmt"Unexpected server reply: {serverReply}") let atyp = firstFourOctets[3] @@ -128,23 +128,30 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = of Socks5AddressType.FQDN.byte: let fqdnNumOctets = await transp.read(1) discard await transp.read(int(uint8.fromBytes(fqdnNumOctets)) + portNumOctets) - else: + of Socks5AddressType.IPv6.byte: discard await transp.read(ipV6NumOctets + portNumOctets) + else: + raise newException(LPError, "Address not supported") -proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) = +proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [LPError, ValueError].} = + var addressArray = ($address).split('/') + if addressArray.len < 2: raise newException(LPError, fmt"Onion address not supported {address}") + addressArray = addressArray[2].split(':') + if addressArray.len == 0: raise newException(LPError, fmt"Onion address not supported {address}") let - addressArray = ($address).split('/') - addressStr = addressArray[2].split(':')[0] & ".onion" + addressStr = addressArray[0] & ".onion" dstAddr = @(uint8(addressStr.len).toBytes()) & addressStr.toBytes() dstPort = address.data.buffer[37..38] return (Socks5AddressType.FQDN.byte, dstAddr, dstPort) -proc parseIpTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) = - let (codec, atyp) = +proc parseIpTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [LPError, ValueError].} = + let (codec, atyp) = if IPv4Tcp.match(address): (multiCodec("ip4"), Socks5AddressType.IPv4.byte) - else: + elif IPv6Tcp.match(address): (multiCodec("ip6"), Socks5AddressType.IPv6.byte) + else: + raise newException(LPError, fmt"IP address not supported {address}") let dstAddr = address[codec].get().protoArgument().get() dstPort = address[multiCodec("tcp")].get().protoArgument().get() @@ -159,9 +166,6 @@ proc parseDnsTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) = proc dialPeer( transp: StreamTransport, address: MultiAddress) {.async, gcsafe.} = - # The address field contains a fully-qualified domain name. - # The first octet of the address field contains the number of octets of name that - # follow, there is no terminating NUL octet. let (atyp, dstAddr, dstPort) = if Onion3.match(address): parseOnion3(address) @@ -188,7 +192,7 @@ method dial*( ## dial a peer ## if not handlesDial(address): - raise newException(LPError, fmt"Not supported address: {address}") + raise newException(LPError, fmt"Address not supported: {address}") trace "Dialing remote peer", address = $address let transp = await connectToTorServer(self.transportAddress) diff --git a/tests/stubs.nim b/tests/stubs.nim index 8ece201848..aae661de44 100644 --- a/tests/stubs.nim +++ b/tests/stubs.nim @@ -45,9 +45,9 @@ proc start*(self: TorServerStub, address: TransportAddress) {.async.} = msg = newSeq[byte](4) await connSrc.readExactly(addr msg[0], 4) - let atyp = int(uint8.fromBytes(msg[3..3])) + let atyp = msg[3] let address = case atyp: - of Socks5AddressType.IPv4.ord: + of Socks5AddressType.IPv4.byte: let n = 4 + 2 # +2 bytes for the port msg = newSeq[byte](n) await connSrc.readExactly(addr msg[0], n) @@ -55,7 +55,7 @@ proc start*(self: TorServerStub, address: TransportAddress) {.async.} = for i, e in msg[0..^3]: ip[i] = e $(ipv4(ip)) & ":" & $(Port(fromBytesBE(uint16, msg[^2..^1]))) - of Socks5AddressType.IPv6.ord: + of Socks5AddressType.IPv6.byte: let n = 16 + 2 # +2 bytes for the port msg = newSeq[byte](n) # +2 bytes for the port await connSrc.readExactly(addr msg[0], n) @@ -63,7 +63,7 @@ proc start*(self: TorServerStub, address: TransportAddress) {.async.} = for i, e in msg[0..^3]: ip[i] = e $(ipv6(ip)) & ":" & $(Port(fromBytesBE(uint16, msg[^2..^1]))) - of Socks5AddressType.FQDN.ord: + of Socks5AddressType.FQDN.byte: await connSrc.readExactly(addr msg[0], 1) let n = int(uint8.fromBytes(msg[0..0])) + 2 # +2 bytes for the port msg = newSeq[byte](n) From 60ebdfd09947f5d1731483bbeb8b9b0366ede840 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 3 Nov 2022 20:45:54 +0100 Subject: [PATCH 21/21] Fix compilation on 1.2 --- libp2p/transports/tortransport.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libp2p/transports/tortransport.nim b/libp2p/transports/tortransport.nim index e816b2ecc0..e978be90c0 100644 --- a/libp2p/transports/tortransport.nim +++ b/libp2p/transports/tortransport.nim @@ -133,7 +133,7 @@ proc readServerReply(transp: StreamTransport) {.async, gcsafe.} = else: raise newException(LPError, "Address not supported") -proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [LPError, ValueError].} = +proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [Defect, LPError, ValueError].} = var addressArray = ($address).split('/') if addressArray.len < 2: raise newException(LPError, fmt"Onion address not supported {address}") addressArray = addressArray[2].split(':') @@ -144,7 +144,7 @@ proc parseOnion3(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: dstPort = address.data.buffer[37..38] return (Socks5AddressType.FQDN.byte, dstAddr, dstPort) -proc parseIpTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [LPError, ValueError].} = +proc parseIpTcp(address: MultiAddress): (byte, seq[byte], seq[byte]) {.raises: [Defect, LPError, ValueError].} = let (codec, atyp) = if IPv4Tcp.match(address): (multiCodec("ip4"), Socks5AddressType.IPv4.byte)