mirror of
https://github.com/status-im/nim-eth.git
synced 2025-01-13 15:54:54 +00:00
2c236f6495
Currently only setting `--styleCheck:hint` as there are some dependency fixes required and the compiler seems to trip over the findnode MessageKind, findnode Message field and the findNode proc. Also over protocol.Protocol usage.
87 lines
3.4 KiB
Nim
87 lines
3.4 KiB
Nim
{.push raises: [Defect].}
|
|
|
|
import
|
|
std/[sets, options],
|
|
stew/results, stew/shims/net, chronicles, chronos,
|
|
"."/[node, enr, routing_table]
|
|
|
|
logScope:
|
|
topics = "nodes-verification"
|
|
|
|
proc validIp(sender, address: IpAddress): bool =
|
|
let
|
|
s = initTAddress(sender, Port(0))
|
|
a = initTAddress(address, Port(0))
|
|
if a.isAnyLocal():
|
|
return false
|
|
if a.isMulticast():
|
|
return false
|
|
if a.isLoopback() and not s.isLoopback():
|
|
return false
|
|
if a.isSiteLocal() and not s.isSiteLocal():
|
|
return false
|
|
# TODO: Also check for special reserved ip addresses:
|
|
# https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
|
|
# https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
|
|
return true
|
|
|
|
proc verifyNodesRecords(enrs: openArray[Record], fromNode: Node, nodesLimit: int,
|
|
distances: Option[seq[uint16]]): seq[Node] =
|
|
## Verify and convert ENRs to a sequence of nodes. Only ENRs that pass
|
|
## verification will be added. ENRs are verified for duplicates, invalid
|
|
## addresses and invalid distances if those are specified.
|
|
var seen: HashSet[Node]
|
|
var count = 0
|
|
for r in enrs:
|
|
# Check and allow for processing of maximum `findNodeResultLimit` ENRs
|
|
# returned. This limitation is required so no huge lists of invalid ENRs
|
|
# are processed for no reason, and for not overwhelming a routing table
|
|
# with nodes from a malicious actor.
|
|
# The discovery v5 specification specifies no limit on the amount of ENRs
|
|
# that can be returned, but clients usually stick with the bucket size limit
|
|
# as in original Kademlia. Because of this it is chosen not to fail
|
|
# immediatly, but still process maximum `findNodeResultLimit`.
|
|
if count >= nodesLimit:
|
|
debug "Too many ENRs", enrs = enrs.len(),
|
|
limit = nodesLimit, sender = fromNode.record.toURI
|
|
break
|
|
|
|
count.inc()
|
|
|
|
let node = newNode(r)
|
|
if node.isOk():
|
|
let n = node.get()
|
|
# Check for duplicates in the nodes reply. Duplicates are checked based
|
|
# on node id.
|
|
if n in seen:
|
|
trace "Duplicate node ids",
|
|
record = n.record.toURI, id = n.id, sender = fromNode.record.toURI
|
|
continue
|
|
# Check if the node has an address and if the address is public or from
|
|
# the same local network or lo network as the sender. The latter allows
|
|
# for local testing.
|
|
if not n.address.isSome() or not
|
|
validIp(fromNode.address.get().ip, n.address.get().ip):
|
|
trace "Invalid ip-address",
|
|
record = n.record.toURI, node = n, sender = fromNode.record.toURI
|
|
continue
|
|
# Check if returned node has one of the requested distances.
|
|
if distances.isSome():
|
|
# TODO: This is incorrect for custom distances
|
|
if (not distances.get().contains(logDistance(n.id, fromNode.id))):
|
|
debug "Incorrect distance",
|
|
record = n.record.toURI, sender = fromNode.record.toURI
|
|
continue
|
|
|
|
# No check on UDP port and thus any port is allowed, also the so called
|
|
# "well-known" ports.
|
|
|
|
seen.incl(n)
|
|
result.add(n)
|
|
|
|
proc verifyNodesRecords*(enrs: openArray[Record], fromNode: Node, nodesLimit: int): seq[Node] =
|
|
verifyNodesRecords(enrs, fromNode, nodesLimit, none[seq[uint16]]())
|
|
|
|
proc verifyNodesRecords*(enrs: openArray[Record], fromNode: Node, nodesLimit: int, distances: seq[uint16]): seq[Node] =
|
|
verifyNodesRecords(enrs, fromNode, nodesLimit, some[seq[uint16]](distances))
|