diff --git a/CHANGELOG.md b/CHANGELOG.md index 3372bb751..346c8fdd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## Next version + + +### Features + +### Changes + +- Waku v1 <> v2 bridge now supports DNS `multiaddrs` +- Waku v1 <> v2 bridge now validates content topics before attempting to bridge a message from Waku v2 to Waku v1 + +### Fixes + +### Docs + ## 2021-03-03 v0.8 Release highlights: @@ -23,6 +37,7 @@ The full list of changes is below. - Metrics: improved default fleet monitoring dashboard - Introduced a `Timestamp` type (currently an alias for int64). - All timestamps changed to nanosecond resolution. +- `timestamp` field number in WakuMessage object changed from `4` to `10` - [`13/WAKU2-STORE`](https://rfc.vac.dev/spec/13/) identifier updated to `/vac/waku/store/2.0.0-beta4` - `toy-chat` application now uses DNS discovery to connect to existing fleets diff --git a/tests/v2/test_waku_bridge.nim b/tests/v2/test_waku_bridge.nim index 9c387f728..73f7fa2e3 100644 --- a/tests/v2/test_waku_bridge.nim +++ b/tests/v2/test_waku_bridge.nim @@ -98,6 +98,19 @@ procSuite "WakuBridge": expect ValueError: # Content topic name not hex discard toV1Topic(ContentTopic("/waku/1/my-content/rfc26")) + + asyncTest "Verify that WakuMessages are on bridgeable content topics": + let + validCT = ContentTopic("/waku/1/my-content/rfc26") + unnamespacedCT = ContentTopic("just_a_bunch_of_words") + invalidAppCT = ContentTopic("/facebook/1/my-content/rfc26") + invalidVersionCT = ContentTopic("/waku/2/my-content/rfc26") + + check: + WakuMessage(contentTopic: validCT).isBridgeable() == true + WakuMessage(contentTopic: unnamespacedCT).isBridgeable() == false + WakuMessage(contentTopic: invalidAppCT).isBridgeable() == false + WakuMessage(contentTopic: invalidVersionCT).isBridgeable() == false asyncTest "Messages are bridged between Waku v1 and Waku v2": # Setup test diff --git a/waku/common/config_bridge.nim b/waku/common/config_bridge.nim index 250d21bd7..8fbde9df8 100644 --- a/waku/common/config_bridge.nim +++ b/waku/common/config_bridge.nim @@ -134,6 +134,16 @@ type defaultValue: "" name: "filternode" }: string + dnsAddrs* {. + desc: "Enable resolution of `dnsaddr`, `dns4` or `dns6` multiaddrs" + defaultValue: true + name: "dns-addrs" }: bool + + dnsAddrsNameServers* {. + desc: "DNS name server IPs to query for DNS multiaddrs resolution. Argument may be repeated." + defaultValue: @[ValidIpAddress.init("1.1.1.1"), ValidIpAddress.init("1.0.0.1")] + name: "dns-addrs-name-server" }: seq[ValidIpAddress] + ### Bridge options bridgePubsubTopic* {. diff --git a/waku/common/wakubridge.nim b/waku/common/wakubridge.nim index d0a54898c..e400495ff 100644 --- a/waku/common/wakubridge.nim +++ b/waku/common/wakubridge.nim @@ -12,6 +12,7 @@ import ../v1/protocol/waku_protocol, # Waku v2 imports libp2p/crypto/crypto, + libp2p/nameresolving/nameresolver, ../v2/utils/namespacing, ../v2/utils/time, ../v2/node/wakunode2, @@ -32,6 +33,9 @@ const ClientIdV1 = "nim-waku v1 node" DefaultTTL = 5'u32 DeduplQSize = 20 # Maximum number of seen messages to keep in deduplication queue + ContentTopicApplication = "waku" + ContentTopicAppVersion = "1" + ######### # Types # @@ -48,6 +52,18 @@ type # Helper funtions # ################### +# Validity + +proc isBridgeable*(msg: WakuMessage): bool = + ## Determines if a Waku v2 msg is on a bridgeable content topic + + let ns = NamespacedTopic.fromString(msg.contentTopic) + if ns.isOk(): + if ns.get().application == ContentTopicApplication and ns.get().version == ContentTopicAppVersion: + return true + + return false + # Deduplication proc containsOrAdd(sequence: var seq[hashes.Hash], hash: hashes.Hash): bool = @@ -72,8 +88,8 @@ proc toV2ContentTopic*(v1Topic: waku_protocol.Topic): ContentTopic = var namespacedTopic = NamespacedTopic() - namespacedTopic.application = "waku" - namespacedTopic.version = "1" + namespacedTopic.application = ContentTopicApplication + namespacedTopic.version = ContentTopicAppVersion namespacedTopic.topicName = "0x" & v1Topic.toHex() namespacedTopic.encoding = "rfc26" @@ -149,6 +165,7 @@ proc new*(T: type WakuBridge, nodev2Key: crypto.PrivateKey, nodev2BindIp: ValidIpAddress, nodev2BindPort: Port, nodev2ExtIp = none[ValidIpAddress](), nodev2ExtPort = none[Port](), + nameResolver: NameResolver = nil, # Bridge configuration nodev2PubsubTopic: wakunode2.Topic): T {.raises: [Defect,IOError, TLSStreamProtocolError, LPError].} = @@ -177,7 +194,8 @@ proc new*(T: type WakuBridge, let nodev2 = WakuNode.new(nodev2Key, nodev2BindIp, nodev2BindPort, - nodev2ExtIp, nodev2ExtPort) + nodev2ExtIp, nodev2ExtPort, + nameResolver = nameResolver) return WakuBridge(nodev1: nodev1, nodev2: nodev2, nodev2PubsubTopic: nodev2PubsubTopic) @@ -215,7 +233,7 @@ proc start*(bridge: WakuBridge) {.async.} = # Handle messages on Waku v2 and bridge to Waku v1 proc relayHandler(pubsubTopic: string, data: seq[byte]) {.async, gcsafe.} = let msg = WakuMessage.init(data) - if msg.isOk(): + if msg.isOk() and msg.get().isBridgeable(): try: trace "Bridging message from V2 to V1", msg=msg.tryGet() bridge.toWakuV1(msg.tryGet()) @@ -232,6 +250,7 @@ proc stop*(bridge: WakuBridge) {.async.} = when isMainModule: import eth/p2p/whispernodes, + libp2p/nameresolving/dnsresolver, ./utils/nat, ../v1/node/rpc/wakusim, ../v1/node/rpc/waku, @@ -299,6 +318,16 @@ when isMainModule: else: bloom = some(fullBloom()) + # DNS resolution + var dnsReslvr: DnsResolver + if conf.dnsAddrs: + # Support for DNS multiaddrs + var nameServers: seq[TransportAddress] + for ip in conf.dnsAddrsNameServers: + nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53 + + dnsReslvr = DnsResolver.new(nameServers) + let bridge = WakuBridge.new(nodev1Key = conf.nodekeyV1, nodev1Address = nodev1Address, @@ -309,6 +338,7 @@ when isMainModule: nodev2Key = conf.nodekeyV2, nodev2BindIp = conf.listenAddress, nodev2BindPort = Port(uint16(conf.libp2pTcpPort) + conf.portsShift), nodev2ExtIp = nodev2ExtIp, nodev2ExtPort = nodev2ExtPort, + nameResolver = dnsReslvr, nodev2PubsubTopic = conf.bridgePubsubTopic) waitFor bridge.start()