{"record":{"id":"f007a20f57df3869","repo":"jdx/mise","slug":"firewall-interface-interface-is-invalid","errorCode":null,"errorMessage":"firewall interface '{interface}' is invalid","messagePattern":"firewall interface '(.+?)' is invalid","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/firewall.rs","lineNumber":2045,"sourceCode":"    if name.is_empty()\n        || name.len() > 64\n        || !name\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))\n    {\n        bail!(\"firewall rule name '{name}' must contain only ASCII letters, numbers, '-' or '_'\");\n    }\n    Ok(())\n}\n\nfn validate_interface(interface: &str) -> Result<String> {\n    if interface.is_empty()\n        || interface.len() > 15\n        || !interface\n            .bytes()\n            .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_' | b'.' | b':'))\n    {\n        bail!(\"firewall interface '{interface}' is invalid\");\n    }\n    Ok(interface.to_string())\n}\n\nfn parse_ssh_connection(value: &str) -> Result<SshConnection> {\n    let fields = value.split_ascii_whitespace().collect::<Vec<_>>();\n    if fields.len() != 4 {\n        bail!(\"SSH_CONNECTION must contain client address/port and server address/port\");\n    }\n    Ok(SshConnection {\n        peer: fields[0].parse()?,\n        server: fields[2].parse()?,\n        server_port: fields[3].parse()?,\n    })\n}\n\n/// Detect an sshd ancestor when SSH_CONNECTION was stripped by sudo, env -i,\n/// or a wrapper. `None` fails closed because ancestry could not be inspected.","sourceCodeStart":2027,"sourceCodeEnd":2063,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/firewall.rs#L2027-L2063","documentation":"Interface names must be non-empty, at most 15 bytes (the Linux kernel IFNAMSIZ limit), and composed only of ASCII letters, digits, '-', '_', '.' or ':'. Validation bails with the offending value when any constraint fails. This mirrors kernel interface-name rules so generated backend commands reference real devices.","triggerScenarios":"Passing an interface string that is empty, longer than 15 characters, or contains characters outside [A-Za-z0-9._:-] (e.g. \"eth0 \", \"br lan\", unicode) to interface validation in a firewall rule.","commonSituations":"Typing a descriptive name instead of the device name (\"wan interface\"); 16+ character VLAN or bridge names exceeding IFNAMSIZ; trailing whitespace from YAML/ENV values; path-like names copied from elsewhere containing '/'.","solutions":["Use the exact kernel device name as shown by `ip link` (e.g. eth0, ens5, br0), within 15 bytes.","Trim whitespace and strip invalid characters from configuration inputs before validation.","Shorten interface/bridge names at creation time so they fit within 15 characters.","Pre-validate interface strings with a regex like ^[A-Za-z0-9._:-]{1,15}$ when loading config."],"exampleFix":"// before\nlet interface = \"my-long-bridge-interface-name\"; // 27 chars > 15\n// after\nlet interface = \"br-lan\";","handlingStrategy":"validation","validationCode":"fn is_valid_interface(interface: &str) -> bool {\n    !interface.is_empty()\n        && interface.len() <= 15\n        && interface.bytes().all(|b| b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_' | b'.' | b':'))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy interface names from `ip link` output, never type from memory","Trim whitespace from config-sourced strings","Keep device names within IFNAMSIZ (15 bytes) at creation","Regex-validate interfaces in config loaders: ^[A-Za-z0-9._:-]{1,15}$"],"tags":["firewall","validation","network-interface"],"backgroundTag":"invalid-argument-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}