Adjust AddrV2 arbitrary to satisfy decode checks
What changed, and why it matters
This commit fixes a mismatch in test-only code between how fake network addresses are randomly generated and how the real decoder validates them. It does not change any production parsing or network logic, so it cannot be exploited by an attacker. The change only makes property-based tests more realistic and avoids false test failures.
No security action required. Treat as a normal code-quality/test-hygiene patch. Reviewers may optionally verify that the new invariants exactly match those in `AddrV2Decoder`.
Security signals we found
Test-only Arbitrary impl aligned with decoder invariants
No change to production decode/encode/network logic
Prevents generation of invalid-but-craftable address variants during fuzz/property tests
Evidence from the diff
The patch updates the Arbitrary implementation for AddrV2 in p2p/src/address.rs so that randomly generated values respect the same invariants enforced by AddrV2Decoder. Specifically: IPv6 addresses are now prevented from accidentally matching the Tor onion (ONION) or IPv4-embedded-IPv6 (IPV4_EMBEDDED_IPV6) prefixes; Cjdns addresses are forced into the fc00::/8 prefix; and Unknown network IDs are constrained to 7..=u8::MAX with payloads truncated to 512 bytes. These constraints mirror decoder-side checks. The change is confined to the arbitrary test-dependency feature and does not alter decoding, serialization, or peer-handling code paths.
Changed components
p2p/src/address.rsAddrV2 Arbitrary implementation (test feature)Inspect captured patch +18 / −21
diff --git a/p2p/src/address.rs b/p2p/src/address.rs
index 2e21cf43..60bc653a 100644
--- a/p2p/src/address.rs
+++ b/p2p/src/address.rs
@@ -1031,29 +1031,26 @@ impl<'a> Arbitrary<'a> for AddrV2 {
u.arbitrary()?,
u.arbitrary()?,
))),
- 1 => Ok(Self::Ipv6(Ipv6Addr::new(
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- ))),
+ 1 => {
+ let mut segments: [u16; 8] = u.arbitrary()?;
+ if segments[0..3] == ONION || segments[0..6] == IPV4_EMBEDDED_IPV6 {
+ segments[0] ^= 1;
+ }
+ Ok(Self::Ipv6(Ipv6Addr::from(segments)))
+ }
2 => Ok(Self::TorV3(u.arbitrary()?)),
3 => Ok(Self::I2p(u.arbitrary()?)),
- 4 => Ok(Self::Cjdns(Ipv6Addr::new(
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- u.arbitrary()?,
- ))),
- _ => Ok(Self::Unknown(u.arbitrary()?, Vec::<u8>::arbitrary(u)?)),
+ 4 => {
+ let mut segments: [u16; 8] = u.arbitrary()?;
+ segments[0] = 0xFC00 | (segments[0] & 0x00FF);
+ Ok(Self::Cjdns(Ipv6Addr::from(segments)))
+ }
+ _ => {
+ let network = u.int_in_range(7..=u8::MAX)?;
+ let mut bytes = Vec::<u8>::arbitrary(u)?;
+ bytes.truncate(512);
+ Ok(Self::Unknown(network, bytes))
+ }
}
}
}
Why this scored 16/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.