For now use directly address/id instead of Node to workaround node isNil problem in edge cases

This commit is contained in:
kdeme 2020-03-18 16:24:23 +01:00 committed by zah
parent 55b8e3e23f
commit a9ff761d68
3 changed files with 42 additions and 31 deletions

View File

@ -88,7 +88,7 @@ proc encryptGCM*(key, nonce, pt, authData: openarray[byte]): seq[byte] =
ectx.getTag(result.toOpenArray(pt.len, result.high)) ectx.getTag(result.toOpenArray(pt.len, result.high))
ectx.clear() ectx.clear()
proc makeAuthHeader(c: Codec, toNode: Node, nonce: array[gcmNonceSize, byte], proc makeAuthHeader(c: Codec, toId: NodeID, nonce: array[gcmNonceSize, byte],
handshakeSecrets: var HandshakeSecrets, handshakeSecrets: var HandshakeSecrets,
challenge: Whoareyou): seq[byte] = challenge: Whoareyou): seq[byte] =
var resp = AuthResponse(version: 5) var resp = AuthResponse(version: 5)
@ -102,7 +102,7 @@ proc makeAuthHeader(c: Codec, toNode: Node, nonce: array[gcmNonceSize, byte],
resp.signature = c.signIDNonce(challenge.idNonce, ephPubkey).getRaw resp.signature = c.signIDNonce(challenge.idNonce, ephPubkey).getRaw
deriveKeys(ln.id, toNode.id, ephKey, toNode.node.pubKey, challenge.idNonce, deriveKeys(ln.id, toId, ephKey, challenge.pubKey, challenge.idNonce,
handshakeSecrets) handshakeSecrets)
let respRlp = rlp.encode(resp) let respRlp = rlp.encode(resp)
@ -125,7 +125,8 @@ proc packetTag(destNode, srcNode: NodeID): PacketTag =
result = srcId xor destidHash.data result = srcId xor destidHash.data
proc encodeEncrypted*(c: Codec, proc encodeEncrypted*(c: Codec,
toNode: Node, toId: NodeID,
toAddr: Address,
packetData: seq[byte], packetData: seq[byte],
challenge: Whoareyou): challenge: Whoareyou):
(seq[byte], array[gcmNonceSize, byte]) = (seq[byte], array[gcmNonceSize, byte]) =
@ -141,17 +142,17 @@ proc encodeEncrypted*(c: Codec,
# We might not have the node's keys if the handshake hasn't been performed # We might not have the node's keys if the handshake hasn't been performed
# yet. That's fine, we will be responded with whoareyou. # yet. That's fine, we will be responded with whoareyou.
discard c.db.loadKeys(toNode.id, toNode.address, readKey, writeKey) discard c.db.loadKeys(toId, toAddr, readKey, writeKey)
else: else:
var sec: HandshakeSecrets var sec: HandshakeSecrets
headEnc = c.makeAuthHeader(toNode, nonce, sec, challenge) headEnc = c.makeAuthHeader(toId, nonce, sec, challenge)
writeKey = sec.writeKey writeKey = sec.writeKey
# TODO: is it safe to ignore the error here? # TODO: is it safe to ignore the error here?
discard c.db.storeKeys(toNode.id, toNode.address, sec.readKey, sec.writeKey) discard c.db.storeKeys(toId, toAddr, sec.readKey, sec.writeKey)
var body = packetData var body = packetData
let tag = packetTag(toNode.id, c.localNode.id) let tag = packetTag(toId, c.localNode.id)
var headBuf = newSeqOfCap[byte](tag.len + headEnc.len) var headBuf = newSeqOfCap[byte](tag.len + headEnc.len)
headBuf.add(tag) headBuf.add(tag)

View File

@ -35,7 +35,7 @@ type
db: Database db: Database
routingTable: RoutingTable routingTable: RoutingTable
codec*: Codec codec*: Codec
awaitedPackets: Table[(Node, RequestId), Future[Option[Packet]]] awaitedPackets: Table[(NodeId, RequestId), Future[Option[Packet]]]
lookupLoop: Future[void] lookupLoop: Future[void]
revalidateLoop: Future[void] revalidateLoop: Future[void]
bootstrapNodes: seq[Node] bootstrapNodes: seq[Node]
@ -141,10 +141,13 @@ proc sendWhoareyou(d: Protocol, address: Address, toNode: NodeId, authTag: AuthT
data.add(rlp.encode(challenge[])) data.add(rlp.encode(challenge[]))
d.send(address, data) d.send(address, data)
proc sendNodes(d: Protocol, toNode: Node, reqId: RequestId, nodes: openarray[Node]) = proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address, reqId: RequestId,
proc sendNodes(d: Protocol, toNode: Node, packet: NodesPacket, reqId: RequestId) {.nimcall.} = nodes: openarray[Node]) =
let (data, _) = d.codec.encodeEncrypted(toNode, encodePacket(packet, reqId), challenge = nil) proc sendNodes(d: Protocol, toId: NodeId, toAddr: Address,
d.send(toNode, data) packet: NodesPacket, reqId: RequestId) {.nimcall.} =
let (data, _) = d.codec.encodeEncrypted(toId, toAddr,
encodePacket(packet, reqId), challenge = nil)
d.send(toAddr, data)
var packet: NodesPacket var packet: NodesPacket
packet.total = ceil(nodes.len / maxNodesPerPacket).uint32 packet.total = ceil(nodes.len / maxNodesPerPacket).uint32
@ -152,14 +155,15 @@ proc sendNodes(d: Protocol, toNode: Node, reqId: RequestId, nodes: openarray[Nod
for i in 0 ..< nodes.len: for i in 0 ..< nodes.len:
packet.enrs.add(nodes[i].record) packet.enrs.add(nodes[i].record)
if packet.enrs.len == 3: if packet.enrs.len == 3:
d.sendNodes(toNode, packet, reqId) d.sendNodes(toId, toAddr, packet, reqId)
packet.enrs.setLen(0) packet.enrs.setLen(0)
if packet.enrs.len != 0: if packet.enrs.len != 0:
d.sendNodes(toNode, packet, reqId) d.sendNodes(toId, toAddr, packet, reqId)
proc handlePing(d: Protocol, fromNode: Node, ping: PingPacket, reqId: RequestId) = proc handlePing(d: Protocol, fromId: NodeId, fromAddr: Address,
let a = fromNode.address ping: PingPacket, reqId: RequestId) =
let a = fromAddr
var pong: PongPacket var pong: PongPacket
pong.enrSeq = ping.enrSeq pong.enrSeq = ping.enrSeq
pong.ip = case a.ip.family pong.ip = case a.ip.family
@ -167,15 +171,18 @@ proc handlePing(d: Protocol, fromNode: Node, ping: PingPacket, reqId: RequestId)
of IpAddressFamily.IPv6: @(a.ip.address_v6) of IpAddressFamily.IPv6: @(a.ip.address_v6)
pong.port = a.udpPort.uint16 pong.port = a.udpPort.uint16
let (data, _) = d.codec.encodeEncrypted(fromNode, encodePacket(pong, reqId), challenge = nil) let (data, _) = d.codec.encodeEncrypted(fromId, fromAddr,
d.send(fromNode, data) encodePacket(pong, reqId), challenge = nil)
d.send(fromAddr, data)
proc handleFindNode(d: Protocol, fromNode: Node, fn: FindNodePacket, reqId: RequestId) = proc handleFindNode(d: Protocol, fromId: NodeId, fromAddr: Address,
fn: FindNodePacket, reqId: RequestId) =
if fn.distance == 0: if fn.distance == 0:
d.sendNodes(fromNode, reqId, [d.localNode]) d.sendNodes(fromId, fromAddr, reqId, [d.localNode])
else: else:
let distance = min(fn.distance, 256) let distance = min(fn.distance, 256)
d.sendNodes(fromNode, reqId, d.routingTable.neighboursAtDistance(distance)) d.sendNodes(fromId, fromAddr, reqId,
d.routingTable.neighboursAtDistance(distance))
proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe, proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe,
raises: [ raises: [
@ -200,8 +207,10 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe,
var pr: PendingRequest var pr: PendingRequest
if d.pendingRequests.take(whoareyou.authTag, pr): if d.pendingRequests.take(whoareyou.authTag, pr):
let toNode = pr.node let toNode = pr.node
whoareyou.pubKey = toNode.node.pubkey # TODO: Yeah, rather ugly this.
try: try:
let (data, _) = d.codec.encodeEncrypted(toNode, pr.packet, challenge = whoareyou) let (data, _) = d.codec.encodeEncrypted(toNode.id, toNode.address,
pr.packet, challenge = whoareyou)
d.send(toNode, data) d.send(toNode, data)
except RandomSourceDepleted as err: except RandomSourceDepleted as err:
debug "Failed to respond to a who-you-are msg " & debug "Failed to respond to a who-you-are msg " &
@ -224,16 +233,14 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe,
debug "Adding new node to routing table", node = $node, localNode = $d.localNode debug "Adding new node to routing table", node = $node, localNode = $d.localNode
discard d.routingTable.addNode(node) discard d.routingTable.addNode(node)
doAssert(not node.isNil, "No node in the routing table (internal error?)")
case packet.kind case packet.kind
of ping: of ping:
d.handlePing(node, packet.ping, packet.reqId) d.handlePing(sender, a, packet.ping, packet.reqId)
of findNode: of findNode:
d.handleFindNode(node, packet.findNode, packet.reqId) d.handleFindNode(sender, a, packet.findNode, packet.reqId)
else: else:
var waiter: Future[Option[Packet]] var waiter: Future[Option[Packet]]
if d.awaitedPackets.take((node, packet.reqId), waiter): if d.awaitedPackets.take((sender, packet.reqId), waiter):
waiter.complete(packet.some) waiter.complete(packet.some)
else: else:
debug "TODO: handle packet: ", packet = packet.kind, origin = $node debug "TODO: handle packet: ", packet = packet.kind, origin = $node
@ -252,7 +259,7 @@ proc receive*(d: Protocol, a: Address, msg: Bytes) {.gcsafe,
proc waitPacket(d: Protocol, fromNode: Node, reqId: RequestId): Future[Option[Packet]] = proc waitPacket(d: Protocol, fromNode: Node, reqId: RequestId): Future[Option[Packet]] =
result = newFuture[Option[Packet]]("waitPacket") result = newFuture[Option[Packet]]("waitPacket")
let res = result let res = result
let key = (fromNode, reqId) let key = (fromNode.id, reqId)
sleepAsync(responseTimeout).addCallback() do(data: pointer): sleepAsync(responseTimeout).addCallback() do(data: pointer):
d.awaitedPackets.del(key) d.awaitedPackets.del(key)
if not res.finished: if not res.finished:
@ -277,7 +284,8 @@ proc waitNodes(d: Protocol, fromNode: Node, reqId: RequestId): Future[seq[Node]]
proc findNode(d: Protocol, toNode: Node, distance: uint32): Future[seq[Node]] {.async.} = proc findNode(d: Protocol, toNode: Node, distance: uint32): Future[seq[Node]] {.async.} =
let reqId = newRequestId() let reqId = newRequestId()
let packet = encodePacket(FindNodePacket(distance: distance), reqId) let packet = encodePacket(FindNodePacket(distance: distance), reqId)
let (data, nonce) = d.codec.encodeEncrypted(toNode, packet, challenge = nil) let (data, nonce) = d.codec.encodeEncrypted(toNode.id, toNode.address, packet,
challenge = nil)
d.pendingRequests[nonce] = PendingRequest(node: toNode, packet: packet) d.pendingRequests[nonce] = PendingRequest(node: toNode, packet: packet)
d.send(toNode, data) d.send(toNode, data)
result = await d.waitNodes(toNode, reqId) result = await d.waitNodes(toNode, reqId)
@ -371,7 +379,8 @@ proc ping(p: Protocol, toNode: Node): RequestId =
reqId = newRequestId() reqId = newRequestId()
ping = PingPacket(enrSeq: p.localNode.record.seqNum) ping = PingPacket(enrSeq: p.localNode.record.seqNum)
packet = encodePacket(ping, reqId) packet = encodePacket(ping, reqId)
(data, nonce) = p.codec.encodeEncrypted(toNode, packet, challenge = nil) (data, nonce) = p.codec.encodeEncrypted(toNode.id, toNode.address, packet,
challenge = nil)
p.pendingRequests[nonce] = PendingRequest(node: toNode, packet: packet) p.pendingRequests[nonce] = PendingRequest(node: toNode, packet: packet)
p.send(toNode, data) p.send(toNode, data)
return reqId return reqId

View File

@ -1,6 +1,6 @@
import import
hashes, stint, hashes, stint,
../enode, enr eth/[keys, rlp], ../enode, enr
const const
authTagSize* = 12 authTagSize* = 12
@ -21,6 +21,7 @@ type
authTag*: AuthTag authTag*: AuthTag
idNonce*: IdNonce idNonce*: IdNonce
recordSeq*: uint64 recordSeq*: uint64
pubKey* {.rlpIgnore.}: PublicKey
Whoareyou* = ref WhoareyouObj Whoareyou* = ref WhoareyouObj