2022-11-04 09:52:27 +00:00
|
|
|
when (NimMajor, NimMinor) < (1, 4):
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
else:
|
|
|
|
{.push raises: [].}
|
2021-07-16 15:13:36 +00:00
|
|
|
|
2020-09-01 02:09:54 +00:00
|
|
|
import
|
|
|
|
std/[strutils, options],
|
|
|
|
chronicles, stew/shims/net as stewNet,
|
|
|
|
eth/net/nat
|
|
|
|
|
2021-07-16 15:13:36 +00:00
|
|
|
logScope:
|
|
|
|
topics = "nat"
|
|
|
|
|
2020-09-01 02:09:54 +00:00
|
|
|
proc setupNat*(natConf, clientId: string, tcpPort, udpPort: Port):
|
2021-07-16 15:13:36 +00:00
|
|
|
tuple[ip: Option[ValidIpAddress],
|
|
|
|
tcpPort: Option[Port],
|
|
|
|
udpPort: Option[Port]] {.gcsafe.} =
|
2020-09-01 02:09:54 +00:00
|
|
|
|
2021-07-16 15:13:36 +00:00
|
|
|
var
|
|
|
|
endpoint: tuple[ip: Option[ValidIpAddress],
|
|
|
|
tcpPort: Option[Port],
|
|
|
|
udpPort: Option[Port]]
|
|
|
|
nat: NatStrategy
|
|
|
|
|
2020-09-01 02:09:54 +00:00
|
|
|
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
|
2021-07-16 15:13:36 +00:00
|
|
|
endpoint.ip = some(ValidIpAddress.init(natConf[6..^1]))
|
2020-09-01 02:09:54 +00:00
|
|
|
nat = NatNone
|
|
|
|
except ValueError:
|
2021-07-16 15:13:36 +00:00
|
|
|
error "not a valid IP address", address = natConf[6..^1]
|
2020-09-01 02:09:54 +00:00
|
|
|
quit QuitFailure
|
|
|
|
else:
|
|
|
|
error "not a valid NAT mechanism", value = natConf
|
|
|
|
quit QuitFailure
|
|
|
|
|
|
|
|
if nat != NatNone:
|
|
|
|
let extIp = getExternalIP(nat)
|
|
|
|
if extIP.isSome:
|
2021-07-16 15:13:36 +00:00
|
|
|
endpoint.ip = some(ValidIpAddress.init extIp.get)
|
2020-09-01 02:09:54 +00:00
|
|
|
# TODO redirectPorts in considered a gcsafety violation
|
|
|
|
# because it obtains the address of a non-gcsafe proc?
|
2021-07-16 15:13:36 +00:00
|
|
|
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.
|
|
|
|
error "unable to determine external ports"
|
|
|
|
extPorts = none((Port, Port))
|
|
|
|
|
2020-09-01 02:09:54 +00:00
|
|
|
if extPorts.isSome:
|
|
|
|
let (extTcpPort, extUdpPort) = extPorts.get()
|
2021-07-16 15:13:36 +00:00
|
|
|
endpoint.tcpPort = some(extTcpPort)
|
|
|
|
endpoint.udpPort = some(extUdpPort)
|
|
|
|
|
|
|
|
return endpoint
|