From d4aff04cbdeff9ea8bee73555184d2524f327d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Wed, 17 Apr 2019 03:56:28 +0200 Subject: [PATCH] NAT port mapping --- .gitmodules | 10 ++++++++++ Makefile | 14 ++++++++++++-- nim.cfg | 2 ++ nimbus/config.nim | 23 ++++++++++++++++++++++- nimbus/nim.cfg | 1 - nimbus/nimbus.nim | 27 +++++++++++++++++++++++---- tests/nim.cfg | 1 - vendor/nim-eth | 2 +- vendor/nim-nat-traversal | 1 + vendor/nim-result | 1 + 10 files changed, 72 insertions(+), 10 deletions(-) create mode 160000 vendor/nim-nat-traversal create mode 160000 vendor/nim-result diff --git a/.gitmodules b/.gitmodules index 1b8a250af..bf918097e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -128,3 +128,13 @@ url = https://github.com/status-im/nim-libp2p.git ignore = dirty branch = master +[submodule "vendor/nim-result"] + path = vendor/nim-result + url = https://github.com/arnetheduck/nim-result.git + ignore = dirty + branch = master +[submodule "vendor/nim-nat-traversal"] + path = vendor/nim-nat-traversal + url = https://github.com/status-im/nim-nat-traversal.git + ignore = dirty + branch = master diff --git a/Makefile b/Makefile index e10f6a49d..51eb22ca8 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ TOOLS_DIRS := premix tests # comma-separated values for the "clean" target TOOLS_CSV := $(subst $(SPACE),$(COMMA),$(TOOLS)) -.PHONY: all $(TOOLS) deps github-ssh build-nim update status ntags ctags nimbus testsuite test clean mrproper fetch-dlls test-libp2p-daemon +.PHONY: all $(TOOLS) deps github-ssh build-nim update status ntags ctags nimbus testsuite test clean mrproper fetch-dlls test-libp2p-daemon nat-libs libminiupnpc.a libnatpmp.a # default target, because it's the first one that doesn't start with '.' all: $(TOOLS) nimbus @@ -100,7 +100,7 @@ $(TOOLS): | build deps $(ENV_SCRIPT) nim c $(NIM_PARAMS) -o:build/$@ "$${TOOL_DIR}/$@.nim" # a phony target, because teaching `make` how to do conditional recompilation of Nim projects is too complicated -nimbus: | build deps +nimbus: | build deps nat-libs echo -e $(BUILD_MSG) "build/$@" && \ $(ENV_SCRIPT) nim nimbus $(NIM_PARAMS) nimbus.nims @@ -114,6 +114,14 @@ build: # and a check for the actual compiler build deps: $(NIM_BINARY) $(NIMBLE_DIR) nimbus.nims +nat-libs: | libminiupnpc.a libnatpmp.a + +libminiupnpc.a: | deps + + $(MAKE) -C vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc $@ $(HANDLE_OUTPUT) + +libnatpmp.a: | deps + + $(MAKE) -C vendor/nim-nat-traversal/vendor/libnatpmp $@ $(HANDLE_OUTPUT) + #- depends on Git submodules being initialised #- fakes a Nimble package repository with the minimum info needed by the Nim compiler # for runtime path (i.e.: the second line in $(NIMBLE_DIR)/pkgs/*/*.nimble-link) @@ -147,6 +155,8 @@ test-reproducibility: clean: rm -rf build/{nimbus,$(TOOLS_CSV),all_tests,test_rpc,*.exe} vendor/go/bin \ $(NIMBLE_DIR) $(NIM_BINARY) $(NIM_DIR)/nimcache nimcache + + $(MAKE) -C vendor/nim-nat-traversal/vendor/miniupnp/miniupnpc clean $(HANDLE_OUTPUT) + + $(MAKE) -C vendor/nim-nat-traversal/vendor/libnatpmp clean $(HANDLE_OUTPUT) # dangerous cleaning, because you may have not-yet-pushed branches and commits in those vendor repos you're about to delete mrproper: clean diff --git a/nim.cfg b/nim.cfg index 10754d256..6589e1a38 100644 --- a/nim.cfg +++ b/nim.cfg @@ -9,3 +9,5 @@ passL = "-Wl,--no-insert-timestamp" @end +--threads:on + diff --git a/nimbus/config.nim b/nimbus/config.nim index 15d298b72..7ddda9307 100644 --- a/nimbus/config.nim +++ b/nimbus/config.nim @@ -9,7 +9,7 @@ import parseopt, strutils, macros, os, times, - chronos, eth/[keys, common, p2p], chronicles, nimcrypto/hash, + chronos, eth/[keys, common, p2p, net/nat], chronicles, nimcrypto/hash, ./db/select_backend, ./vm/interpreter/vm_forks @@ -132,6 +132,8 @@ type networkId*: uint ## Network ID as integer ident*: string ## Server ident name string nodeKey*: PrivateKey ## Server private key + nat*: NatStrategy ## NAT strategy + externalIP*: string ## user-provided external IP DebugConfiguration* = object ## Debug configuration object @@ -474,6 +476,23 @@ proc processNetArguments(key, value: string): ConfigStatus = config.net.nodeKey = res elif skey == "ident": config.net.ident = value + elif skey == "nat": + case value.toLowerAscii: + of "any": + config.net.nat = NatAny + of "upnp": + config.net.nat = NatUpnp + of "pmp": + config.net.nat = NatPmp + of "none": + config.net.nat = NatNone + else: + if isIpAddress(value): + config.net.externalIP = value + config.net.nat = NatNone + else: + error "not a valid NAT mechanism, nor a valid IP address", value + result = ErrorParseOption else: result = EmptyOption @@ -551,6 +570,7 @@ proc initConfiguration(): NimbusConfiguration = result.net.bindPort = 30303'u16 result.net.discPort = 30303'u16 result.net.ident = NimbusIdent + result.net.nat = NatAny const dataDir = getDefaultDataDir() @@ -592,6 +612,7 @@ NETWORKING OPTIONS: --discport: Network listening UDP port (defaults to --port argument) --maxpeers: Maximum number of network peers (default: 25) --maxpendpeers: Maximum number of pending connection attempts (default: 0) + --nat: NAT port mapping mechanism (any|none|upnp|pmp|) (default: "any") --nodiscover Disables the peer discovery mechanism (manual peer addition) --v5discover Enables the experimental RLPx V5 (Topic Discovery) mechanism --nodekey: P2P node private key (as hexadecimal string) diff --git a/nimbus/nim.cfg b/nimbus/nim.cfg index 1f777ff87..ac9563326 100644 --- a/nimbus/nim.cfg +++ b/nimbus/nim.cfg @@ -2,5 +2,4 @@ -d:"chronicles_sinks=textlines[file]" -d:"chronicles_runtime_filtering=on" -d:nimDebugDlOpen ---threads:on diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index 19baef020..2e5282c7c 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -8,11 +8,12 @@ # those terms. import - os, strutils, net, eth/keys, db/[storage_types, db_chain, select_backend], + os, strutils, net, options, + eth/keys, db/[storage_types, db_chain, select_backend], eth/common as eth_common, eth/p2p as eth_p2p, chronos, json_rpc/rpcserver, chronicles, eth/p2p/rlpx_protocols/[eth_protocol, les_protocol], - eth/p2p/blockchain_sync, + eth/p2p/blockchain_sync, eth/net/nat, config, genesis, rpc/[common, p2p, debug, whisper], p2p/chain, eth/trie/db @@ -43,8 +44,6 @@ proc start(): NimbusObject = setLogLevel(conf.debug.logLevel) if len(conf.debug.logFile) != 0: discard defaultChroniclesStream.output.open(conf.debug.logFile, fmAppend) - else: - discard defaultChroniclesStream.output.open(stdout) ## Creating RPC Server if RpcFlags.Enabled in conf.rpc.flags: @@ -63,6 +62,23 @@ proc start(): NimbusObject = address.ip = parseIpAddress("0.0.0.0") address.tcpPort = Port(conf.net.bindPort) address.udpPort = Port(conf.net.discPort) + if conf.net.nat == NatNone: + if conf.net.externalIP != "": + # any required port redirection is assumed to be done by hand + address.ip = parseIpAddress(conf.net.externalIP) + else: + # automated NAT traversal + let extIP = getExternalIP(conf.net.nat) + # TODO: dynamic IPs are common, so our external IP might change while the + # program is running. How can we update our advertised enode address and any + # other place that might use this external IP? + if extIP.isSome: + address.ip = extIP.get() + let extPorts = redirectPorts(tcpPort = address.tcpPort, + udpPort = address.udpPort, + description = NIMBUS_NAME & " " & NIMBUS_VERSION) + if extPorts.isSome: + (address.tcpPort, address.udpPort) = extPorts.get() createDir(conf.dataDir) let trieDB = trieDB newChainDb(conf.dataDir) @@ -133,6 +149,9 @@ when isMainModule: ## Pring Nimbus header echo NimbusHeader + ## show logs on stdout until we get the user's logging choice + discard defaultChroniclesStream.output.open(stdout) + ## Processing command line arguments if processArguments(message) != ConfigStatus.Success: echo message diff --git a/tests/nim.cfg b/tests/nim.cfg index 58790329b..ee64291c7 100644 --- a/tests/nim.cfg +++ b/tests/nim.cfg @@ -1,4 +1,3 @@ -d:chronicles_line_numbers -d:"chronicles_sinks=textblocks" ---threads:on diff --git a/vendor/nim-eth b/vendor/nim-eth index a6be6426a..3db5f4c5d 160000 --- a/vendor/nim-eth +++ b/vendor/nim-eth @@ -1 +1 @@ -Subproject commit a6be6426ab60b43a1a71c9fc96e0cba9c54154fa +Subproject commit 3db5f4c5dd47fc6a6b8624572935a813d6e3930d diff --git a/vendor/nim-nat-traversal b/vendor/nim-nat-traversal new file mode 160000 index 000000000..0bcb394f5 --- /dev/null +++ b/vendor/nim-nat-traversal @@ -0,0 +1 @@ +Subproject commit 0bcb394f5787bde62e3c275e185498e2de20d637 diff --git a/vendor/nim-result b/vendor/nim-result new file mode 160000 index 000000000..ca56ea36b --- /dev/null +++ b/vendor/nim-result @@ -0,0 +1 @@ +Subproject commit ca56ea36b8dd7f644305c383dbebd28c1e44399b