Add several checks for currently unhandled errors

This commit is contained in:
kdeme 2019-05-23 12:02:58 +02:00 committed by zah
parent b977996b0a
commit 6b5af745a2
2 changed files with 33 additions and 11 deletions

View File

@ -60,7 +60,10 @@ type
cmdFindNode = 3
cmdNeighbours = 4
DiscProtocolError* = object of CatchableError
const MaxDgramSize = 1280
const MinListLen: array[CommandId, int] = [4, 3, 2, 2]
proc append*(w: var RlpWriter, a: IpAddress) =
case a.family
@ -97,6 +100,11 @@ proc recoverMsgPublicKey(msg: Bytes, pk: var PublicKey): bool =
pk) == EthKeysStatus.Success
proc unpack(msg: Bytes): tuple[cmdId: CommandId, payload: Bytes] =
# Check against possible RangeError
if msg[HEAD_SIZE].int < CommandId.low.ord or
msg[HEAD_SIZE].int > CommandId.high.ord:
raise newException(DiscProtocolError, "Unsupported packet id")
result = (cmdId: msg[HEAD_SIZE].CommandId, payload: msg[HEAD_SIZE + 1 .. ^1])
proc expiration(): uint32 =
@ -211,17 +219,31 @@ proc recvFindNode(d: DiscoveryProtocol, node: Node, payload: Bytes) {.inline, gc
let rlp = rlpFromBytes(payload.toRange)
trace "<<< find_node from ", node
let rng = rlp.listElem(0).toBytes
# Check for pubkey len
if rng.len == 64:
let nodeId = readUIntBE[256](rng[32 .. ^1].toOpenArray())
d.kademlia.recvFindNode(node, nodeId)
else:
trace "Invalid target public key received"
proc expirationValid(rlpEncodedPayload: seq[byte]): bool {.inline.} =
## Can raise RlpTypeMismatch
proc expirationValid(cmdId: CommandId, rlpEncodedPayload: seq[byte]):
bool {.inline, raises:[DiscProtocolError, RlpError].} =
## Can only raise `DiscProtocolError` and all of `RlpError`
# Check if there is a payload, TODO: perhaps this should be an RLP error?
if rlpEncodedPayload.len <= 0:
raise newException(DiscProtocolError, "RLP stream is empty")
let rlp = rlpFromBytes(rlpEncodedPayload.toRange)
let expiration = rlp.listElem(rlp.listLen - 1).toInt(uint32)
# Check payload is an RLP list and if the list has the minimum items required
# for this packet type
if rlp.listLen >= MinListLen[cmdId]:
# Expiration is always the last mandatory item of the list
let expiration = rlp.listElem(MinListLen[cmdId] - 1).toInt(uint32)
result = epochTime() <= expiration.float
else:
raise newException(DiscProtocolError, "Invalid RLP list for this packet id")
proc receive(d: DiscoveryProtocol, a: Address, msg: Bytes) {.gcsafe.} =
## Can raise RlpTypeMismatch
## Can raise `DiscProtocolError` and all of `RlpError`
var msgHash: MDigest[256]
if validateMsgHash(msg, msgHash):
var remotePubkey: PublicKey
@ -229,7 +251,7 @@ proc receive(d: DiscoveryProtocol, a: Address, msg: Bytes) {.gcsafe.} =
let (cmdId, payload) = unpack(msg)
# echo "received cmd: ", cmdId, ", from: ", a
# echo "pubkey: ", remotePubkey.raw_key.toHex()
if expirationValid(payload):
if expirationValid(cmdId, payload):
let node = newNode(remotePubkey, a)
case cmdId
of cmdPing:
@ -258,7 +280,7 @@ proc processClient(transp: DatagramTransport,
var buf = transp.getMessage()
let a = Address(ip: raddr.address, udpPort: raddr.port, tcpPort: raddr.port)
proto.receive(a, buf)
except RlpTypeMismatch:
except RlpError, DiscProtocolError:
debug "Receive failed", err = getCurrentExceptionMsg()
except:
debug "Receive failed", err = getCurrentExceptionMsg()

View File

@ -26,7 +26,7 @@ type
of rlpList:
elems*: seq[RlpNode]
RlpError* = object of Exception
RlpError* = object of CatchableError
MalformedRlpError* = object of RlpError
UnsupportedRlpError* = object of RlpError
RlpTypeMismatch* = object of RlpError
@ -275,7 +275,7 @@ proc listElem*(self: Rlp, i: int): Rlp =
proc listLen*(self: Rlp): int =
if not isList():
return 0
raise newException(RlpTypeMismatch, "List expected, but the source RLP is not a list.")
var rlp = self
for elem in rlp: