import std/[strutils, options], chronicles, stew/shims/net as stewNet, eth/net/nat proc setupNat*(natConf, clientId: string, tcpPort, udpPort: Port): tuple[ip: Option[ValidIpAddress], tcpPort: Option[Port], udpPort: Option[Port]] {.gcsafe.} = var nat: NatStrategy 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 result.ip = some(ValidIpAddress.init(natConf[6..^1])) nat = NatNone except ValueError: error "nor a valid IP address", address = natConf[6..^1] quit QuitFailure else: error "not a valid NAT mechanism", value = natConf quit QuitFailure if nat != NatNone: let extIp = getExternalIP(nat) if extIP.isSome: result.ip = some(ValidIpAddress.init extIp.get) # TODO redirectPorts in considered a gcsafety violation # because it obtains the address of a non-gcsafe proc? let extPorts = ({.gcsafe.}: redirectPorts(tcpPort = tcpPort, udpPort = udpPort, description = clientId)) if extPorts.isSome: let (extTcpPort, extUdpPort) = extPorts.get() result.tcpPort = some(extTcpPort) result.udpPort = some(extUdpPort)