2023-06-22 20:58:14 +00:00
|
|
|
import
|
2023-09-27 13:02:24 +00:00
|
|
|
chronicles,
|
|
|
|
chronos,
|
|
|
|
libp2p/crypto/crypto,
|
|
|
|
libp2p/multiaddress,
|
|
|
|
libp2p/nameresolving/dnsresolver,
|
2024-05-16 20:29:11 +00:00
|
|
|
std/[options, sequtils, net],
|
|
|
|
stew/results
|
2023-06-22 20:58:14 +00:00
|
|
|
import
|
2024-03-03 00:59:53 +00:00
|
|
|
./external_config,
|
|
|
|
../common/utils/nat,
|
|
|
|
../node/config,
|
|
|
|
../waku_enr/capabilities,
|
|
|
|
../waku_enr,
|
|
|
|
../waku_core
|
2023-06-22 20:58:14 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc enrConfiguration*(
|
|
|
|
conf: WakuNodeConf, netConfig: NetConfig, key: crypto.PrivateKey
|
|
|
|
): Result[enr.Record, string] =
|
2023-10-27 07:11:47 +00:00
|
|
|
var enrBuilder = EnrBuilder.init(key)
|
|
|
|
|
|
|
|
enrBuilder.withIpAddressAndPorts(
|
2024-03-15 23:08:47 +00:00
|
|
|
netConfig.enrIp, netConfig.enrPort, netConfig.discv5UdpPort
|
2023-10-27 07:11:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
if netConfig.wakuFlags.isSome():
|
|
|
|
enrBuilder.withWakuCapabilities(netConfig.wakuFlags.get())
|
|
|
|
|
|
|
|
enrBuilder.withMultiaddrs(netConfig.enrMultiaddrs)
|
|
|
|
|
2024-05-14 18:17:17 +00:00
|
|
|
var shards = newSeq[uint16]()
|
2024-04-26 12:21:52 +00:00
|
|
|
|
2024-05-14 18:17:17 +00:00
|
|
|
# no shards configured
|
|
|
|
if conf.shards.len == 0:
|
|
|
|
let shardsOpt = topicsToRelayShards(conf.pubsubTopics).valueOr:
|
|
|
|
error "failed to parse pubsub topic, please format according to static shard specification",
|
|
|
|
error = $error
|
|
|
|
return err("failed to parse pubsub topic: " & $error)
|
|
|
|
if shardsOpt.isSome():
|
|
|
|
shards = shardsOpt.get().shardIds
|
2024-03-15 23:08:47 +00:00
|
|
|
else:
|
2024-05-14 18:17:17 +00:00
|
|
|
info "no pubsub topics specified or pubsubtopic is of type Named sharding "
|
|
|
|
# some shards configured
|
|
|
|
else:
|
|
|
|
shards = toSeq(conf.shards.mapIt(uint16(it)))
|
2024-03-13 09:58:13 +00:00
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
enrBuilder.withWakuRelaySharding(
|
2024-06-05 13:32:35 +00:00
|
|
|
RelayShards(clusterId: conf.clusterId, shardIds: shards)
|
2024-03-15 23:08:47 +00:00
|
|
|
).isOkOr:
|
|
|
|
return err("could not initialize ENR with shards")
|
2023-10-27 07:11:47 +00:00
|
|
|
|
|
|
|
let recordRes = enrBuilder.build()
|
|
|
|
let record =
|
|
|
|
if recordRes.isErr():
|
2024-03-15 23:08:47 +00:00
|
|
|
error "failed to create record", error = recordRes.error
|
2023-10-27 07:11:47 +00:00
|
|
|
return err($recordRes.error)
|
2024-03-15 23:08:47 +00:00
|
|
|
else:
|
|
|
|
recordRes.get()
|
2023-10-27 07:11:47 +00:00
|
|
|
|
|
|
|
return ok(record)
|
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc validateExtMultiAddrs*(vals: seq[string]): Result[seq[MultiAddress], string] =
|
2023-06-29 19:59:53 +00:00
|
|
|
var multiaddrs: seq[MultiAddress]
|
|
|
|
for val in vals:
|
2024-03-15 23:08:47 +00:00
|
|
|
let multiaddr = ?MultiAddress.init(val)
|
2023-06-29 19:59:53 +00:00
|
|
|
multiaddrs.add(multiaddr)
|
|
|
|
return ok(multiaddrs)
|
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc dnsResolve*(
|
|
|
|
domain: string, conf: WakuNodeConf
|
|
|
|
): Future[Result[string, string]] {.async.} =
|
2023-09-27 13:02:24 +00:00
|
|
|
# Use conf's DNS servers
|
|
|
|
var nameServers: seq[TransportAddress]
|
|
|
|
for ip in conf.dnsAddrsNameServers:
|
|
|
|
nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53
|
2023-10-11 06:58:45 +00:00
|
|
|
|
2023-09-27 13:02:24 +00:00
|
|
|
let dnsResolver = DnsResolver.new(nameServers)
|
|
|
|
|
|
|
|
# Resolve domain IP
|
|
|
|
let resolved = await dnsResolver.resolveIp(domain, 0.Port, Domain.AF_UNSPEC)
|
|
|
|
|
|
|
|
if resolved.len > 0:
|
|
|
|
return ok(resolved[0].host) # Use only first answer
|
|
|
|
else:
|
|
|
|
return err("Could not resolve IP from DNS: empty response")
|
|
|
|
|
2024-03-15 23:08:47 +00:00
|
|
|
proc networkConfiguration*(conf: WakuNodeConf, clientId: string): NetConfigResult =
|
2023-06-22 20:58:14 +00:00
|
|
|
## `udpPort` is only supplied to satisfy underlying APIs but is not
|
|
|
|
## actually a supported transport for libp2p traffic.
|
2024-03-15 23:08:47 +00:00
|
|
|
let natRes = setupNat(
|
|
|
|
conf.nat,
|
|
|
|
clientId,
|
|
|
|
Port(uint16(conf.tcpPort) + conf.portsShift),
|
|
|
|
Port(uint16(conf.tcpPort) + conf.portsShift),
|
|
|
|
)
|
2023-06-22 20:58:14 +00:00
|
|
|
if natRes.isErr():
|
|
|
|
return err("failed to setup NAT: " & $natRes.error)
|
|
|
|
|
2023-09-27 13:02:24 +00:00
|
|
|
var (extIp, extTcpPort, _) = natRes.get()
|
2023-06-22 20:58:14 +00:00
|
|
|
|
|
|
|
let
|
2024-03-15 23:08:47 +00:00
|
|
|
dns4DomainName =
|
|
|
|
if conf.dns4DomainName != "":
|
|
|
|
some(conf.dns4DomainName)
|
|
|
|
else:
|
|
|
|
none(string)
|
|
|
|
|
|
|
|
discv5UdpPort =
|
|
|
|
if conf.discv5Discovery:
|
|
|
|
some(Port(uint16(conf.discv5UdpPort) + conf.portsShift))
|
|
|
|
else:
|
|
|
|
none(Port)
|
2023-06-22 20:58:14 +00:00
|
|
|
|
2023-06-29 19:59:53 +00:00
|
|
|
## TODO: the NAT setup assumes a manual port mapping configuration if extIp
|
|
|
|
## config is set. This probably implies adding manual config item for
|
|
|
|
## extPort as well. The following heuristic assumes that, in absence of
|
|
|
|
## manual config, the external port is the same as the bind port.
|
2024-03-15 23:08:47 +00:00
|
|
|
extPort =
|
|
|
|
if (extIp.isSome() or dns4DomainName.isSome()) and extTcpPort.isNone():
|
|
|
|
some(Port(uint16(conf.tcpPort) + conf.portsShift))
|
|
|
|
else:
|
|
|
|
extTcpPort
|
|
|
|
|
|
|
|
extMultiAddrs =
|
|
|
|
if (conf.extMultiAddrs.len > 0):
|
|
|
|
let extMultiAddrsValidationRes = validateExtMultiAddrs(conf.extMultiAddrs)
|
|
|
|
if extMultiAddrsValidationRes.isErr():
|
|
|
|
return
|
|
|
|
err("invalid external multiaddress: " & $extMultiAddrsValidationRes.error)
|
|
|
|
else:
|
|
|
|
extMultiAddrsValidationRes.get()
|
|
|
|
else:
|
|
|
|
@[]
|
2023-06-22 20:58:14 +00:00
|
|
|
|
|
|
|
wakuFlags = CapabilitiesBitfield.init(
|
2024-03-15 23:08:47 +00:00
|
|
|
lightpush = conf.lightpush,
|
|
|
|
filter = conf.filter,
|
|
|
|
store = conf.store,
|
|
|
|
relay = conf.relay,
|
|
|
|
)
|
2023-06-22 20:58:14 +00:00
|
|
|
|
2023-09-27 13:02:24 +00:00
|
|
|
# Resolve and use DNS domain IP
|
|
|
|
if dns4DomainName.isSome() and extIp.isNone():
|
|
|
|
try:
|
|
|
|
let dnsRes = waitFor dnsResolve(conf.dns4DomainName, conf)
|
2023-10-11 06:58:45 +00:00
|
|
|
|
2023-09-27 13:02:24 +00:00
|
|
|
if dnsRes.isErr():
|
|
|
|
return err($dnsRes.error) # Pass error down the stack
|
2023-10-11 06:58:45 +00:00
|
|
|
|
2023-12-14 06:16:39 +00:00
|
|
|
extIp = some(parseIpAddress(dnsRes.get()))
|
2023-09-27 13:02:24 +00:00
|
|
|
except CatchableError:
|
2024-03-15 23:08:47 +00:00
|
|
|
return
|
|
|
|
err("Could not update extIp to resolved DNS IP: " & getCurrentExceptionMsg())
|
2023-10-11 06:58:45 +00:00
|
|
|
|
2023-06-22 20:58:14 +00:00
|
|
|
# Wrap in none because NetConfig does not have a default constructor
|
2023-06-29 19:59:53 +00:00
|
|
|
# TODO: We could change bindIp in NetConfig to be something less restrictive
|
2023-12-14 06:16:39 +00:00
|
|
|
# than IpAddress, which doesn't allow default construction
|
2023-06-22 20:58:14 +00:00
|
|
|
let netConfigRes = NetConfig.init(
|
2024-03-15 23:08:47 +00:00
|
|
|
clusterId = conf.clusterId,
|
|
|
|
bindIp = conf.listenAddress,
|
|
|
|
bindPort = Port(uint16(conf.tcpPort) + conf.portsShift),
|
|
|
|
extIp = extIp,
|
|
|
|
extPort = extPort,
|
|
|
|
extMultiAddrs = extMultiAddrs,
|
|
|
|
extMultiAddrsOnly = conf.extMultiAddrsOnly,
|
|
|
|
wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift),
|
|
|
|
wsEnabled = conf.websocketSupport,
|
|
|
|
wssEnabled = conf.websocketSecureSupport,
|
|
|
|
dns4DomainName = dns4DomainName,
|
|
|
|
discv5UdpPort = discv5UdpPort,
|
|
|
|
wakuFlags = some(wakuFlags),
|
|
|
|
)
|
2023-06-22 20:58:14 +00:00
|
|
|
|
2023-06-29 19:59:53 +00:00
|
|
|
return netConfigRes
|