From c03431dc60a9313d959210f61371a9774bb3c052 Mon Sep 17 00:00:00 2001 From: Vaclav Pavlin Date: Tue, 11 Apr 2023 17:05:12 +0200 Subject: [PATCH] feat(wakucanary):config wakucanary to support websockets (#1654) closes #1528 --- tools/wakucanary/README.md | 9 +++++ tools/wakucanary/wakucanary.nim | 71 +++++++++++++++++++++++++-------- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/tools/wakucanary/README.md b/tools/wakucanary/README.md index 57c13a83c..b1ecb6145 100644 --- a/tools/wakucanary/README.md +++ b/tools/wakucanary/README.md @@ -16,6 +16,9 @@ The following options are available: multiple times). -l, --log-level Sets the log level [=LogLevel.DEBUG]. -np, --node-port Listening port for waku node [=60000]. + --websocket-secure-key-path Secure websocket key path: '/path/to/key.txt' . + --websocket-secure-cert-path Secure websocket Certificate path: '/path/to/cert.txt' . + ``` The tool can be built as: @@ -45,3 +48,9 @@ $ ./build/wakucanary --address=/dns4/node-01.do-ams3.status.test.statusim.net/tc $ echo $? 0 ``` + +Websockets are also supported. The websocket port openned by waku canary is calculated as `$(--node-port) + 1000` (e.g. when you set `-np 60000`, the WS port will be `61000`) +```console +$ ./build/wakucanary --address=/ip4/127.0.0.1/tcp/7777/ws/p2p/16Uiu2HAm4ng2DaLPniRoZtMQbLdjYYWnXjrrJkGoXWCoBWAdn1tu --protocol=store --protocol=filter +$ ./build/wakucanary --address=/ip4/127.0.0.1/tcp/7777/wss/p2p/16Uiu2HAmB6JQpewXScGoQ2syqmimbe4GviLxRwfsR8dCpwaGBPSE --protocol=store --websocket-secure-key-path=MyKey.key --websocket-secure-cert-path=MyCertificate.crt +``` \ No newline at end of file diff --git a/tools/wakucanary/wakucanary.nim b/tools/wakucanary/wakucanary.nim index 1d9608cb4..97b97e74a 100644 --- a/tools/wakucanary/wakucanary.nim +++ b/tools/wakucanary/wakucanary.nim @@ -7,7 +7,8 @@ import import libp2p/protocols/ping, libp2p/crypto/[crypto, secp], - libp2p/nameresolving/dnsresolver + libp2p/nameresolving/dnsresolver, + libp2p/multicodec import ../../waku/v2/node/peer_manager, ../../waku/v2/waku_node, @@ -21,6 +22,8 @@ const ProtocolsTable = { "filter": "/vac/waku/filter/", }.toTable +const WebSocketPortOffset = 1000 + # cli flags type WakuCanaryConf* = object @@ -28,35 +31,45 @@ type desc: "Multiaddress of the peer node to attempt to dial", defaultValue: "", name: "address", - abbr: "a" }: string + abbr: "a".}: string timeout* {. desc: "Timeout to consider that the connection failed", defaultValue: chronos.seconds(10), name: "timeout", - abbr: "t" }: chronos.Duration + abbr: "t".}: chronos.Duration protocols* {. desc: "Protocol required to be supported: store,relay,lightpush,filter (can be used multiple times)", name: "protocol", - abbr: "p" }: seq[string] + abbr: "p".}: seq[string] logLevel* {. desc: "Sets the log level", defaultValue: LogLevel.DEBUG, name: "log-level", - abbr: "l" .}: LogLevel + abbr: "l".}: LogLevel nodePort* {. desc: "Listening port for waku node", defaultValue: 60000, name: "node-port", - abbr: "np" }: uint16 + abbr: "np".}: uint16 + ## websocket secure config + websocketSecureKeyPath* {. + desc: "Secure websocket key path: '/path/to/key.txt' ", + defaultValue: "" + name: "websocket-secure-key-path".}: string + + websocketSecureCertPath* {. + desc: "Secure websocket Certificate path: '/path/to/cert.txt' ", + defaultValue: "" + name: "websocket-secure-cert-path".}: string proc parseCmdArg*(T: type chronos.Duration, p: string): T = try: - result = chronos.seconds(parseInt(p)) + result = chronos.seconds(parseInt(p)) except CatchableError: raise newException(ConfigurationError, "Invalid timeout value") @@ -74,7 +87,8 @@ proc areProtocolsSupported( for rawProtocol in rawProtocols: let protocolTag = ProtocolsTable[rawProtocol] if nodeProtocol.startsWith(protocolTag): - info "Supported protocol ok", expected=protocolTag, supported=nodeProtocol + info "Supported protocol ok", expected = protocolTag, + supported = nodeProtocol numOfSupportedProt += 1 break @@ -99,32 +113,54 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} = # ensure input protocols are valid for p in conf.protocols: if p notin ProtocolsTable: - error "invalid protocol", protocol=p, valid=ProtocolsTable + error "invalid protocol", protocol = p, valid = ProtocolsTable raise newException(ConfigurationError, "Invalid cli flag values" & p) info "Cli flags", - address=conf.address, - timeout=conf.timeout, - protocols=conf.protocols, - logLevel=conf.logLevel + address = conf.address, + timeout = conf.timeout, + protocols = conf.protocols, + logLevel = conf.logLevel let peer: RemotePeerInfo = parseRemotePeerInfo(conf.address) nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] bindIp = ValidIpAddress.init("0.0.0.0") + wsBindPort = Port(conf.nodePort + WebSocketPortOffset) nodeTcpPort = Port(conf.nodePort) + isWs = peer.addrs[0].contains(multiCodec("ws")).get() + isWss = peer.addrs[0].contains(multiCodec("wss")).get() var builder = WakuNodeBuilder.init() builder.withNodeKey(nodeKey) - builder.withNetworkConfigurationDetails(bindIp, nodeTcpPort).tryGet() - builder.withSwitchConfiguration(nameResolver=resolver) + + let netConfig = NetConfig.init( + bindIp = bindIp, + bindPort = nodeTcpPort, + wsBindPort = wsBindPort, + wsEnabled = isWs, + wssEnabled = isWss, + ) + + if isWss and (conf.websocketSecureKeyPath.len == 0 or + conf.websocketSecureCertPath.len == 0): + error "WebSocket Secure requires key and certificate, see --help" + return 1 + + builder.withNetworkConfiguration(netConfig.tryGet()) + builder.withSwitchConfiguration( + secureKey = some(conf.websocketSecureKeyPath), + secureCert = some(conf.websocketSecureCertPath), + nameResolver = resolver, + ) + let node = builder.build().tryGet() await node.start() let timedOut = not await node.connectToNodes(@[peer]).withTimeout(conf.timeout) if timedOut: - error "Timedout after", timeout=conf.timeout + error "Timedout after", timeout = conf.timeout let lp2pPeerStore = node.switch.peerStore let conStatus = node.peerManager.peerStore[ConnectionBook][peer.peerId] @@ -132,7 +168,8 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} = if conStatus in [Connected, CanConnect]: let nodeProtocols = lp2pPeerStore[ProtoBook][peer.peerId] if not areProtocolsSupported(conf.protocols, nodeProtocols): - error "Not all protocols are supported", expected=conf.protocols, supported=nodeProtocols + error "Not all protocols are supported", expected = conf.protocols, + supported = nodeProtocols return 1 elif conStatus == CannotConnect: error "Could not connect", peerId = peer.peerId