stamparm/maltrail · error
src ipv4
Error message
src ipv4
What it means
Panic from `.expect("src ipv4")` when `crate::addr::addr_to_int(src)` cannot parse the source IPv4 address string passed to the packet builder `ipv4_opts`. Test helpers are strict: a malformed address means the test packet cannot be constructed.
Solutions
- Validate the src string is a valid dotted-quad IPv4 before calling ipv4_opts
- Use well-formed test literals like "10.0.0.1"
- Match on addr_to_int to panic with the address value for easier diagnosis
- Ensure no IPv6 addresses are passed to the IPv4 builder
Example fix
// before ipv4_opts(proto, "10.0.0.300", dst, &[], payload) // invalid octet // after ipv4_opts(proto, "10.0.0.1", dst, &[], payload)
Defensive patterns
Strategy: validation
Validate before calling
fn is_ipv4(s: &str) -> bool { s.parse::<std::net::Ipv4Addr>().is_ok() }
assert!(is_ipv4(src), "src must be valid IPv4: {src}"); Type guard
fn is_ipv4(s: &str) -> bool { s.parse::<std::net::Ipv4Addr>().is_ok() } Try / catch
let v = crate::addr::addr_to_int(src).unwrap_or_else(|e| panic!("src ipv4 '{src}': {e:?}")); Prevention
- Validate all IP literals at the top of packet-builder helpers
- Never pass IPv6 literals to IPv4 builders
- Use named constants for common test addresses
When it happens
Trigger: `ipv4_opts()` (and wrappers `ipv4`) called with a src string that is not a valid dotted-quad IPv4 address (empty string, hostname, octet >255, missing octets).
Common situations: Typo in a hardcoded test IP; substituting an IPv6 literal where an IPv4 is required; building addresses with format! that produce empty or malformed octets.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- dst ipv4
- src ipv6
- dst ipv6
- invalid USERS entry ' ' [?] (hint: add whitespace at start…
- invalid configuration
AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13).
Data as JSON: /api/errors/a262388ba59cf7c7.
Report an issue: GitHub.
Appendix: source
Thrown at sensor/src/testkit.rs:450
out.extend_from_slice(payload);
out
}
pub fn ipv4(proto: u8, src: &str, dst: &str, payload: &[u8]) -> Vec<u8> {
ipv4_opts(proto, src, dst, payload, 5, 0)
}
pub fn ipv4_opts(proto: u8, src: &str, dst: &str, payload: &[u8], ihl: u8, frag: u16) -> Vec<u8> {
let options = vec![0u8; ((ihl as usize).saturating_sub(5)) * 4];
let total = (ihl as usize * 4 + payload.len()) as u16;
let mut out = vec![0x40 | (ihl & 0x0f), 0];
out.extend_from_slice(&total.to_be_bytes());
out.extend_from_slice(&0x1234u16.to_be_bytes());
out.extend_from_slice(&frag.to_be_bytes());
out.push(64);
out.push(proto);
out.extend_from_slice(&[0, 0]);
out.extend_from_slice(&crate::addr::addr_to_int(src).expect("src ipv4").to_be_bytes());
out.extend_from_slice(&crate::addr::addr_to_int(dst).expect("dst ipv4").to_be_bytes());
out.extend_from_slice(&options);
out.extend_from_slice(payload);
out
}
pub fn ipv6(proto: u8, src: &str, dst: &str, payload: &[u8]) -> Vec<u8> {
let mut out = vec![0x60, 0, 0, 0];
out.extend_from_slice(&(payload.len() as u16).to_be_bytes());
out.push(proto);
out.push(64);
out.extend_from_slice(&crate::addr::parse_ipv6(src).expect("src ipv6").to_be_bytes());
out.extend_from_slice(&crate::addr::parse_ipv6(dst).expect("dst ipv6").to_be_bytes());
out.extend_from_slice(payload);
out
}
/// IPv6 carrying a chain of extension headers before `proto`.View on GitHub (pinned to 77cfb06d76)