mirror of https://github.com/status-im/nim-eth.git
Add several checks for currently unhandled errors
This commit is contained in:
parent
b977996b0a
commit
6b5af745a2
|
@ -60,7 +60,10 @@ type
|
||||||
cmdFindNode = 3
|
cmdFindNode = 3
|
||||||
cmdNeighbours = 4
|
cmdNeighbours = 4
|
||||||
|
|
||||||
|
DiscProtocolError* = object of CatchableError
|
||||||
|
|
||||||
const MaxDgramSize = 1280
|
const MaxDgramSize = 1280
|
||||||
|
const MinListLen: array[CommandId, int] = [4, 3, 2, 2]
|
||||||
|
|
||||||
proc append*(w: var RlpWriter, a: IpAddress) =
|
proc append*(w: var RlpWriter, a: IpAddress) =
|
||||||
case a.family
|
case a.family
|
||||||
|
@ -97,6 +100,11 @@ proc recoverMsgPublicKey(msg: Bytes, pk: var PublicKey): bool =
|
||||||
pk) == EthKeysStatus.Success
|
pk) == EthKeysStatus.Success
|
||||||
|
|
||||||
proc unpack(msg: Bytes): tuple[cmdId: CommandId, payload: Bytes] =
|
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])
|
result = (cmdId: msg[HEAD_SIZE].CommandId, payload: msg[HEAD_SIZE + 1 .. ^1])
|
||||||
|
|
||||||
proc expiration(): uint32 =
|
proc expiration(): uint32 =
|
||||||
|
@ -211,17 +219,31 @@ proc recvFindNode(d: DiscoveryProtocol, node: Node, payload: Bytes) {.inline, gc
|
||||||
let rlp = rlpFromBytes(payload.toRange)
|
let rlp = rlpFromBytes(payload.toRange)
|
||||||
trace "<<< find_node from ", node
|
trace "<<< find_node from ", node
|
||||||
let rng = rlp.listElem(0).toBytes
|
let rng = rlp.listElem(0).toBytes
|
||||||
let nodeId = readUIntBE[256](rng[32 .. ^1].toOpenArray())
|
# Check for pubkey len
|
||||||
d.kademlia.recvFindNode(node, nodeId)
|
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.} =
|
proc expirationValid(cmdId: CommandId, rlpEncodedPayload: seq[byte]):
|
||||||
## Can raise RlpTypeMismatch
|
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 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
|
||||||
result = epochTime() <= expiration.float
|
# 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.} =
|
proc receive(d: DiscoveryProtocol, a: Address, msg: Bytes) {.gcsafe.} =
|
||||||
## Can raise RlpTypeMismatch
|
## Can raise `DiscProtocolError` and all of `RlpError`
|
||||||
var msgHash: MDigest[256]
|
var msgHash: MDigest[256]
|
||||||
if validateMsgHash(msg, msgHash):
|
if validateMsgHash(msg, msgHash):
|
||||||
var remotePubkey: PublicKey
|
var remotePubkey: PublicKey
|
||||||
|
@ -229,7 +251,7 @@ proc receive(d: DiscoveryProtocol, a: Address, msg: Bytes) {.gcsafe.} =
|
||||||
let (cmdId, payload) = unpack(msg)
|
let (cmdId, payload) = unpack(msg)
|
||||||
# echo "received cmd: ", cmdId, ", from: ", a
|
# echo "received cmd: ", cmdId, ", from: ", a
|
||||||
# echo "pubkey: ", remotePubkey.raw_key.toHex()
|
# echo "pubkey: ", remotePubkey.raw_key.toHex()
|
||||||
if expirationValid(payload):
|
if expirationValid(cmdId, payload):
|
||||||
let node = newNode(remotePubkey, a)
|
let node = newNode(remotePubkey, a)
|
||||||
case cmdId
|
case cmdId
|
||||||
of cmdPing:
|
of cmdPing:
|
||||||
|
@ -258,7 +280,7 @@ proc processClient(transp: DatagramTransport,
|
||||||
var buf = transp.getMessage()
|
var buf = transp.getMessage()
|
||||||
let a = Address(ip: raddr.address, udpPort: raddr.port, tcpPort: raddr.port)
|
let a = Address(ip: raddr.address, udpPort: raddr.port, tcpPort: raddr.port)
|
||||||
proto.receive(a, buf)
|
proto.receive(a, buf)
|
||||||
except RlpTypeMismatch:
|
except RlpError, DiscProtocolError:
|
||||||
debug "Receive failed", err = getCurrentExceptionMsg()
|
debug "Receive failed", err = getCurrentExceptionMsg()
|
||||||
except:
|
except:
|
||||||
debug "Receive failed", err = getCurrentExceptionMsg()
|
debug "Receive failed", err = getCurrentExceptionMsg()
|
||||||
|
|
|
@ -26,7 +26,7 @@ type
|
||||||
of rlpList:
|
of rlpList:
|
||||||
elems*: seq[RlpNode]
|
elems*: seq[RlpNode]
|
||||||
|
|
||||||
RlpError* = object of Exception
|
RlpError* = object of CatchableError
|
||||||
MalformedRlpError* = object of RlpError
|
MalformedRlpError* = object of RlpError
|
||||||
UnsupportedRlpError* = object of RlpError
|
UnsupportedRlpError* = object of RlpError
|
||||||
RlpTypeMismatch* = object of RlpError
|
RlpTypeMismatch* = object of RlpError
|
||||||
|
@ -275,7 +275,7 @@ proc listElem*(self: Rlp, i: int): Rlp =
|
||||||
|
|
||||||
proc listLen*(self: Rlp): int =
|
proc listLen*(self: Rlp): int =
|
||||||
if not isList():
|
if not isList():
|
||||||
return 0
|
raise newException(RlpTypeMismatch, "List expected, but the source RLP is not a list.")
|
||||||
|
|
||||||
var rlp = self
|
var rlp = self
|
||||||
for elem in rlp:
|
for elem in rlp:
|
||||||
|
|
Loading…
Reference in New Issue