Skip to content

Commit

Permalink
refactor: proper use of setupNat
Browse files Browse the repository at this point in the history
Notice that I had to adapt to use 'rlpx_connected_peers' instead
of 'connected_peers' in 'wakunode1.nim' because due to the update
of the 'vendor/nim-eth', which adds the dependency-break with
'confutils' but also includes another changes.

Aside note: we cannot have 'confutils' dependency in 'nim-eth' because
that will prevent the generation of any waku dynamic library.
  • Loading branch information
Ivansete-status committed May 17, 2023
1 parent e1e4ff3 commit aabfc4c
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 167 deletions.
8 changes: 6 additions & 2 deletions apps/chat2/chat2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -404,11 +404,15 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
if conf.logLevel != LogLevel.NONE:
setLogLevel(conf.logLevel)

let
(extIp, extTcpPort, extUdpPort) = setupNat(conf.nat, clientId,
let natRes = setupNat(conf.nat, clientId,
Port(uint16(conf.tcpPort) + conf.portsShift),
Port(uint16(conf.udpPort) + conf.portsShift))

if natRes.isErr():
raise newException(ValueError, "setupNat error " & natRes.error)

let (extIp, extTcpPort, extUdpPort) = natRes.get()

let node = block:
var builder = WakuNodeBuilder.init()
builder.withNodeKey(nodeKey)
Expand Down
10 changes: 7 additions & 3 deletions apps/chat2bridge/chat2bridge.nim
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,15 @@ when isMainModule:
if conf.logLevel != LogLevel.NONE:
setLogLevel(conf.logLevel)

let natRes = setupNat(conf.nat, clientId,
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
Port(uint16(conf.udpPort) + conf.portsShift))
if natRes.isErr():
error "Error in setupNat", error = natRes.error

# Load address configuration
let
(nodev2ExtIp, nodev2ExtPort, _) = setupNat(conf.nat, clientId,
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
Port(uint16(conf.udpPort) + conf.portsShift))
(nodev2ExtIp, nodev2ExtPort, _) = natRes.get()
## The following heuristic assumes that, in absence of manual
## config, the external port is the same as the bind port.
extPort = if nodev2ExtIp.isSome() and nodev2ExtPort.isNone():
Expand Down
22 changes: 16 additions & 6 deletions apps/wakubridge/wakubridge.nim
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,23 @@ when isMainModule:
## actually a supported transport.
let udpPort = conf.devp2pTcpPort

let natRes = setupNat(conf.nat, ClientIdV1,
Port(conf.devp2pTcpPort + conf.portsShift),
Port(udpPort + conf.portsShift))
if natRes.isErr():
error "failed setupNat", error = natRes.error
quit(QuitFailure)

let natRes2 = setupNat(conf.nat, clientId,
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
Port(uint16(udpPort) + conf.portsShift))
if natRes2.isErr():
error "failed setupNat", error = natRes2.error
quit(QuitFailure)

# Load address configuration
let
(nodev1ExtIp, _, _) = setupNat(conf.nat, ClientIdV1,
Port(conf.devp2pTcpPort + conf.portsShift),
Port(udpPort + conf.portsShift))
(nodev1ExtIp, _, _) = natRes.get()
# TODO: EthereumNode should have a better split of binding address and
# external address. Also, can't have different ports as it stands now.
nodev1Address = if nodev1ExtIp.isNone():
Expand All @@ -364,9 +376,7 @@ when isMainModule:
Address(ip: nodev1ExtIp.get(),
tcpPort: Port(conf.devp2pTcpPort + conf.portsShift),
udpPort: Port(udpPort + conf.portsShift))
(nodev2ExtIp, nodev2ExtPort, _) = setupNat(conf.nat, clientId,
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
Port(uint16(udpPort) + conf.portsShift))
(nodev2ExtIp, nodev2ExtPort, _) = natRes2.get()

# Topic interest and bloom
var topicInterest: Option[seq[waku_protocol.Topic]]
Expand Down
48 changes: 1 addition & 47 deletions apps/wakunode2/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import
libp2p/protocols/pubsub/gossipsub,
libp2p/peerid,
eth/keys,
eth/net/nat,
json_rpc/rpcserver,
presto,
metrics,
metrics/chronos_httpserver
import
../../waku/common/utils/nat,
../../waku/common/sqlite,
../../waku/v2/waku_core,
../../waku/v2/waku_node,
Expand Down Expand Up @@ -317,51 +317,6 @@ proc setupDyamicBootstrapNodes*(app: var App): AppResult[void] =

## Init waku node instance

proc setupNat(natConf, clientId: string, tcpPort, udpPort: Port):
AppResult[tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]]] {.gcsafe.} =

let strategy = case natConf.toLowerAscii():
of "any": NatAny
of "none": NatNone
of "upnp": NatUpnp
of "pmp": NatPmp
else: NatNone

var endpoint: tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]]

if strategy != NatNone:
let extIp = getExternalIP(strategy)
if extIP.isSome():
endpoint.ip = some(ValidIpAddress.init(extIp.get()))
# RedirectPorts in considered a gcsafety violation
# because it obtains the address of a non-gcsafe proc?
var extPorts: Option[(Port, Port)]
try:
extPorts = ({.gcsafe.}: redirectPorts(tcpPort = tcpPort,
udpPort = udpPort,
description = clientId))
except CatchableError:
# TODO: nat.nim Error: can raise an unlisted exception: Exception. Isolate here for now.
error "unable to determine external ports"
extPorts = none((Port, Port))

if extPorts.isSome():
let (extTcpPort, extUdpPort) = extPorts.get()
endpoint.tcpPort = some(extTcpPort)
endpoint.udpPort = some(extUdpPort)

else: # NatNone
if not natConf.startsWith("extip:"):
return err("not a valid NAT mechanism: " & $natConf)

try:
# any required port redirection is assumed to be done by hand
endpoint.ip = some(ValidIpAddress.init(natConf[6..^1]))
except ValueError:
return err("not a valid IP address: " & $natConf[6..^1])

return ok(endpoint)

proc initNode(conf: WakuNodeConf,
rng: ref HmacDrbgContext,
peerStore: Option[WakuPeerStorage],
Expand Down Expand Up @@ -401,7 +356,6 @@ proc initNode(conf: WakuNodeConf,

let (extIp, extTcpPort, _) = natRes.get()


let
dns4DomainName = if conf.dns4DomainName != "": some(conf.dns4DomainName)
else: none(string)
Expand Down
12 changes: 9 additions & 3 deletions examples/v1/example.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import
const clientId = "Waku example v1"

proc run(config: WakuNodeConf, rng: ref HmacDrbgContext) =

let natRes = setupNat(config.nat, clientId,
Port(config.tcpPort + config.portsShift),
Port(config.udpPort + config.portsShift))
if natRes.isErr():
fatal "setupNat failed", error = natRes.error
quit(1)

# Set up the address according to NAT information.
let (ipExt, tcpPortExt, udpPortExt) = setupNat(config.nat, clientId,
Port(config.tcpPort + config.portsShift),
Port(config.udpPort + config.portsShift))
let (ipExt, tcpPortExt, udpPortExt) = natRes.get()
# TODO: EthereumNode should have a better split of binding address and
# external address. Also, can't have different ports as it stands now.
let address = if ipExt.isNone():
Expand Down
49 changes: 1 addition & 48 deletions library/libwaku.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ import
chronicles,
chronos,
libp2p/crypto/secp,
stew/shims/net,
eth/net/nat as todo_delete_this_module
stew/shims/net
import
../vendor/nim-libp2p/libp2p/crypto/crypto,
../../waku/common/utils/nat,
Expand Down Expand Up @@ -81,52 +80,6 @@ proc errResp(message: string): string =
# }
return $(%* { "error": message })

proc setupNat(natConf, clientId: string, tcpPort, udpPort: Port):
Result[tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]], string] {.gcsafe.} =
# TODO reorganize all setupNat calls and use only one commom proc

let strategy = case natConf.toLowerAscii():
of "any": NatAny
of "none": NatNone
of "upnp": NatUpnp
of "pmp": NatPmp
else: NatNone

var endpoint: tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]]

if strategy != NatNone:
let extIp = getExternalIP(strategy)
if extIP.isSome():
endpoint.ip = some(ValidIpAddress.init(extIp.get()))
# RedirectPorts in considered a gcsafety violation
# because it obtains the address of a non-gcsafe proc?
var extPorts: Option[(Port, Port)]
try:
extPorts = ({.gcsafe.}: redirectPorts(tcpPort = tcpPort,
udpPort = udpPort,
description = clientId))
except CatchableError:
# TODO: nat.nim Error: can raise an unlisted exception: Exception. Isolate here for now.
error "unable to determine external ports"
extPorts = none((Port, Port))

if extPorts.isSome():
let (extTcpPort, extUdpPort) = extPorts.get()
endpoint.tcpPort = some(extTcpPort)
endpoint.udpPort = some(extUdpPort)

else: # NatNone
if not natConf.startsWith("extip:"):
return err("not a valid NAT mechanism: " & $natConf)

try:
# any required port redirection is assumed to be done by hand
endpoint.ip = some(ValidIpAddress.init(natConf[6..^1]))
except ValueError:
return err("not a valid IP address: " & $natConf[6..^1])

return ok(endpoint)

proc parseConfig(config: ConfigNode,
privateKey: var PrivateKey,
netConfig: var NetConfig,
Expand Down
8 changes: 4 additions & 4 deletions tests/v1/test_waku_connect.nim
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ procSuite "Waku connections":
p2 = await n2.rlpxConnect(newNode(n3.toENode()))
p3 = await n4.rlpxConnect(newNode(n3.toENode()))
check:
p1.isNil
p2.isNil == false
p3.isNil == false
p1.isErr()
p2.isErr() == false
p3.isErr() == false

asyncTest "Filters with encryption and signing":
var node1 = setupTestNode(rng, Waku)
Expand Down Expand Up @@ -386,7 +386,7 @@ procSuite "Waku connections":

ln2.startListening()
let peer = await ln1.rlpxConnect(newNode(ln2.toENode()))
check peer.isNil == true
check peer.isErr() == true

asyncTest "Waku set-topic-interest":
var
Expand Down
2 changes: 1 addition & 1 deletion tests/whisper/test_shh_connect.nim
Original file line number Diff line number Diff line change
Expand Up @@ -326,4 +326,4 @@ procSuite "Whisper connections":

ln2.startListening()
let peer = await ln1.rlpxConnect(newNode(ln2.toENode()))
check peer.isNil == true
check peer.isErr() == true
2 changes: 1 addition & 1 deletion vendor/nim-eth
Submodule nim-eth updated 67 files
+0 −82 .appveyor.yml
+5 −5 .github/workflows/ci.yml
+0 −49 .travis.yml
+3 −9 eth.nimble
+2 −5 eth/common/eth_hash.nim
+5 −8 eth/common/eth_types.nim
+7 −1 eth/common/eth_types_json_serialization.nim
+9 −4 eth/common/eth_types_rlp.nim
+3 −7 eth/db/kvstore.nim
+2 −6 eth/db/kvstore_sqlite3.nim
+3 −2 eth/keyfile/keyfile.nim
+1 −1 eth/keyfile/uuid.nim
+59 −15 eth/keys.nim
+7 −9 eth/net/nat.nim
+2 −2 eth/net/utils.nim
+5 −5 eth/p2p.nim
+7 −7 eth/p2p/auth.nim
+14 −14 eth/p2p/discovery.nim
+3 −3 eth/p2p/discoveryv5/encoding.nim
+5 −5 eth/p2p/discoveryv5/enr.nim
+12 −1 eth/p2p/discoveryv5/hkdf.nim
+2 −2 eth/p2p/discoveryv5/ip_vote.nim
+10 −2 eth/p2p/discoveryv5/lru.nim
+2 −2 eth/p2p/discoveryv5/messages.nim
+5 −5 eth/p2p/discoveryv5/messages_encoding.nim
+2 −2 eth/p2p/discoveryv5/node.nim
+1 −1 eth/p2p/discoveryv5/nodes_verification.nim
+4 −4 eth/p2p/discoveryv5/protocol.nim
+10 −0 eth/p2p/discoveryv5/random2.nim
+8 −5 eth/p2p/discoveryv5/routing_table.nim
+2 −2 eth/p2p/discoveryv5/sessions.nim
+7 −7 eth/p2p/ecies.nim
+6 −2 eth/p2p/enode.nim
+25 −17 eth/p2p/kademlia.nim
+2 −2 eth/p2p/p2p_backends_helpers.nim
+1 −1 eth/p2p/p2p_protocol_dsl.nim
+65 −21 eth/p2p/peer_pool.nim
+18 −11 eth/p2p/private/p2p_types.nim
+191 −90 eth/p2p/rlpx.nim
+2 −2 eth/p2p/rlpxcrypt.nim
+1 −1 eth/trie/binaries.nim
+23 −6 eth/trie/db.nim
+260 −104 eth/trie/hexary.nim
+2 −2 eth/trie/hexary_proof_verification.nim
+2 −2 eth/utp/clock_drift_calculator.nim
+2 −2 eth/utp/delay_histogram.nim
+17 −12 eth/utp/growable_buffer.nim
+2 −2 eth/utp/ledbat_congestion_control.nim
+54 −53 eth/utp/packets.nim
+8 −5 eth/utp/utp.nim
+2 −2 eth/utp/utp_discv5_protocol.nim
+7 −5 eth/utp/utp_protocol.nim
+25 −20 eth/utp/utp_router.nim
+121 −100 eth/utp/utp_socket.nim
+2 −2 eth/utp/utp_utils.nim
+5 −1 tests/fuzzing/rlpx/thunk.nim
+5 −5 tests/keys/test_keys.nim
+4 −4 tests/p2p/test_discoveryv5.nim
+1 −1 tests/p2p/test_discoveryv5_encoding.nim
+6 −4 tests/p2p/test_protocol_handlers.nim
+4 −1 tests/p2p/test_rlpx_thunk.nim
+28 −3 tests/rlp/test_api_usage.nim
+1 −1 tests/trie/test_branches_utils.nim
+2 −2 tests/trie/test_hexary_proof.nim
+5 −5 tests/utp/test_buffer.nim
+56 −64 tests/utp/test_packets.nim
+1 −1 tests/utp/test_utils.nim
91 changes: 44 additions & 47 deletions waku/common/utils/nat.nim
Original file line number Diff line number Diff line change
@@ -1,70 +1,67 @@

when (NimMajor, NimMinor) < (1, 4):
{.push raises: [Defect].}
else:
{.push raises: [].}

import
std/[strutils, options],
chronicles, stew/shims/net as stewNet,
eth/net/nat
std/[options, strutils]
import
chronicles,
eth/net/nat,
stew/results,
stew/shims/net,
nativesockets

logScope:
topics = "nat"

proc setupNat*(natConf, clientId: string, tcpPort, udpPort: Port):
tuple[ip: Option[ValidIpAddress],
tcpPort: Option[Port],
udpPort: Option[Port]] {.gcsafe, deprecated:
"Unsafe: this proc quits the app if something is not ok".} =
proc setupNat*(natConf, clientId: string,
tcpPort, udpPort: Port):
Result[tuple[ip: Option[ValidIpAddress],
tcpPort: Option[Port],
udpPort: Option[Port]], string]
{.gcsafe.} =

var
endpoint: tuple[ip: Option[ValidIpAddress],
tcpPort: Option[Port],
udpPort: Option[Port]]
nat: NatStrategy
let strategy = case natConf.toLowerAscii():
of "any": NatAny
of "none": NatNone
of "upnp": NatUpnp
of "pmp": NatPmp
else: NatNone

case natConf.toLowerAscii:
of "any":
nat = NatAny
of "none":
nat = NatNone
of "upnp":
nat = NatUpnp
of "pmp":
nat = NatPmp
else:
if natConf.startsWith("extip:"):
try:
# any required port redirection is assumed to be done by hand
endpoint.ip = some(ValidIpAddress.init(natConf[6..^1]))
nat = NatNone
except ValueError:
error "not a valid IP address", address = natConf[6..^1]
quit QuitFailure
else:
error "not a valid NAT mechanism", value = natConf
quit QuitFailure
var endpoint: tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]]

if nat != NatNone:
let extIp = getExternalIP(nat)
if extIP.isSome:
endpoint.ip = some(ValidIpAddress.init extIp.get)
# TODO redirectPorts in considered a gcsafety violation
if strategy != NatNone:
let extIp = getExternalIP(strategy)
if extIP.isSome():
endpoint.ip = some(ValidIpAddress.init(extIp.get()))
# RedirectPorts in considered a gcsafety violation
# because it obtains the address of a non-gcsafe proc?
var extPorts: Option[(Port, Port)]
try:
extPorts = ({.gcsafe.}:
redirectPorts(tcpPort = tcpPort,
udpPort = udpPort,
description = clientId))
except Exception:
# @TODO: nat.nim Error: can raise an unlisted exception: Exception. Isolate here for now.
extPorts = ({.gcsafe.}: redirectPorts(tcpPort = tcpPort,
udpPort = udpPort,
description = clientId))
except CatchableError:
# TODO: nat.nim Error: can raise an unlisted exception: Exception. Isolate here for now.
error "unable to determine external ports"
extPorts = none((Port, Port))

if extPorts.isSome:
if extPorts.isSome():
let (extTcpPort, extUdpPort) = extPorts.get()
endpoint.tcpPort = some(extTcpPort)
endpoint.udpPort = some(extUdpPort)

return endpoint
else: # NatNone
if not natConf.startsWith("extip:"):
return err("not a valid NAT mechanism: " & $natConf)

try:
# any required port redirection is assumed to be done by hand
endpoint.ip = some(ValidIpAddress.init(natConf[6..^1]))
except ValueError:
return err("not a valid IP address: " & $natConf[6..^1])

return ok(endpoint)

Loading

0 comments on commit aabfc4c

Please sign in to comment.