stamparm/maltrail · warning

Received unexpected datalink

Error message

Received unexpected datalink ({datalink}); attempting IP-offset heuristic

What it means

The packet capture datalink type reported by the capture device is not one of the known DLT offsets, so the sensor cannot use the standard IP offset resolution. It logs this warning and falls back to an IP-offset heuristic (guess) that inspects the packet bytes to find the IP header start.

Solutions

  1. Identify the interface's datalink type (tcpdump -i <iface> --print / -L) and confirm whether the sensor build should support it.
  2. If safe, capture on a standard Ethernet (DLT_EN10MB) or Linux SLL interface so the known offset path is used.
  3. Verify the heuristic is working: check packets_ignored vs parsed packet metrics; if heuristics misfire, packets may be misparsed.
  4. Upgrade the sensor to a build that maps the DLT in settings::dlt_offset if support for the link type exists upstream.
Defensive patterns

Strategy: fallback

Validate before calling

# identify the datalink of the capture interface beforehand
tcpdump -L -i <iface>   # lists supported datalink types
# prefer standard Ethernet (EN10MB) or Linux SLL interfaces

Prevention

When it happens

Trigger: resolve(datalink, packet) is called with a datalink value for which settings::dlt_offset(datalink) returns None — e.g. an unusual libpcap DLT from an exotic interface, tunnel, or VM virtual NIC.

Common situations: Capturing on unusual interfaces (VPN tunnels, raw/unknown DLTs, unusual virtualization NICs); capture library reporting a DLT this sensor build doesn't map; cross-platform capture files with uncommon link types.

Related errors


AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13). Data as JSON: /api/errors/a8dfe168fd5d229b. Report an issue: GitHub.

Appendix: source

Thrown at sensor/src/packet/dlt.rs:165

        }
        let off = guess_ip_offset(packet, 64)?;
        if self.provisional.get(&datalink) == Some(&off) {
            self.locked.insert(datalink, Some(off));
            crate::cprintln!(
                "[i] datalink {datalink} missing from offset table; inferred IP offset {off} by heuristic"
            );
            return Some(off);
        }
        self.provisional.insert(datalink, off);
        Some(off)
    }

    /// Full `packet_handler` offset resolution, including the unknown-datalink path.
    pub fn resolve(&mut self, datalink: i32, packet: &[u8]) -> Option<usize> {
        match settings::dlt_offset(datalink) {
            Some(base) => ip_offset(datalink, packet, base),
            None => {
                crate::output::log_error(
                    &format!("Received unexpected datalink ({datalink}); attempting IP-offset heuristic"),
                    true,
                );
                self.guess(datalink, packet)
            }
        }
    }
}

#[cfg(test)]
pub(crate) mod tests {
    use super::*;

    fn eth(ethertype: u16) -> Vec<u8> {
        let mut v = vec![0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
        v.extend_from_slice(&ethertype.to_be_bytes());
        v
    }

View on GitHub (pinned to 77cfb06d76)