diff --git a/crates/net/dns/src/error.rs b/crates/net/dns/src/error.rs index d7b0a53c0a..a4469801e2 100644 --- a/crates/net/dns/src/error.rs +++ b/crates/net/dns/src/error.rs @@ -19,6 +19,8 @@ pub enum ParseDnsEntryError { Base32DecodeError(String), #[error("{0}")] RlpDecodeError(String), + #[error("Invalid child hash in branch: {0}")] + InvalidChildHash(String), #[error("{0}")] Other(String), } diff --git a/crates/net/dns/src/tree.rs b/crates/net/dns/src/tree.rs index 870060337d..5520f606ad 100644 --- a/crates/net/dns/src/tree.rs +++ b/crates/net/dns/src/tree.rs @@ -179,7 +179,20 @@ impl BranchEntry { /// /// Caution: This assumes the prefix is already removed. fn parse_value(input: &str) -> ParseEntryResult { - let children = input.trim().split(',').map(str::to_string).collect(); + fn ensure_valid_hash(hash: &str) -> ParseEntryResult { + let decoded_len = BASE32_NOPAD.decode_len(hash.as_bytes().len()).map_err(|err| { + ParseDnsEntryError::Base32DecodeError(format!( + "invalid base32 child {hash} in branch: {err}" + )) + })?; + if !(12..=32).contains(&decoded_len) || hash.chars().any(|c| c.is_whitespace()) { + return Err(ParseDnsEntryError::InvalidChildHash(hash.to_string())) + } + Ok(hash.to_string()) + } + + let children = + input.trim().split(',').map(ensure_valid_hash).collect::>>()?; Ok(Self { children }) } } @@ -341,6 +354,24 @@ mod tests { } } + #[test] + fn parse_invalid_branch_entry() { + let s = "enrtree-branch:1,2"; + let res = s.parse::(); + assert!(res.is_err()); + let s = "enrtree-branch:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + let res = s.parse::(); + assert!(res.is_err()); + + let s = "enrtree-branch:,BBBBBBBBBBBBBBBBBBBB"; + let res = s.parse::(); + assert!(res.is_err()); + + let s = "enrtree-branch:CCCCCCCCCCCCCCCCCCCC\n,BBBBBBBBBBBBBBBBBBBB"; + let res = s.parse::(); + assert!(res.is_err()); + } + #[test] fn parse_link_entry() { let s = "enrtree://AM5FCQLWIZX2QFPNJAP7VUERCCRNGRHWZG3YYHIUV7BVDQ5FDPRT2@nodes.example.org";