The information has to be available. If not available, it won't be logged.
As IPv4 relies on ARP to resolve the MAC address of the destination, it's not known yet where iptables is concerned: such resolution happens later and never known in any of iptables' hooks, even once the destination IP address is known and even if such information usually remains cached in the neighbor ARP table.
So here's what happens as observed (using kernel 6.1) and inferred when involved interfaces are all Ethernet:
PREROUTING/INPUT/FORWARD
- The source and destination MAC addresses are always available in PREROUTING, INPUT or FORWARD.
- for the FORWARD case the destination MAC address represents the local system's destination MAC address of the interface receiving the frame, not the future target system or gateway.
OUTPUT
- the source MAC address is not known: embedding the packet into a frame has not happened yet so such MAC address is not known.
- the destination MAC address is not known either as explained
POSTROUTING
- if the packet is locally emitted (came through OUTPUT) then as in the OUTPUT case: no information is available
- if the packet was routed (came through FORWARD): then the unchanged information from FORWARD is still available and logged even if "obsolete".
In short:
- PREROUTING, INPUT will always have the information
- FORWARD will always have the information from before routing
- OUTPUT will never have a MAC address in logs
- POSTROUTING will have it only if the packet was routed, and in this case, this will be the same information as logged in FORWARD.
Other cases when the information is not available is when it never exists:
- when the egress interface is not Ethernet (eg: lo, a layer 3 interface like WireGuard or OpenVPN in tun mode): then POSTROUTING won't display the "obsolete" MAC address it would have displayed otherwise when the packet was routed.
- when the ingress interface is not Ethernet: then no MAC address will appear in any hook.
I didn't consider how the behavior for bridged frames (at layer 2) traversing iptables (normally handling layer 3 packets) when the br_netfilter
module is loaded (typically by Docker) with the sysconf property bridge-nf-call-iptables=1
can differ. These "packets" will also be logged with additional properties: PHYSIN=
and PHYSOUT=
.