wz2b
wz2b

Reputation: 1025

Getting the MAC address from nftables nflog in go

I want to push my netfilter logs into Grafana Loki but I could not get a format I liked, between ulogd and promtail, so I decided to write my own little utility to do the job for me. It works pretty well except for one thing: I would like to be able to get MAC (hardware) addresses in the output.

I tried a few things, and made some observations. The first is that if I try to parse the log messages for the entire packet stack at the same time, it doesn't work. In this example, 'protocols' contained Ethernet, IPV4, TCP4, and UDP4. When I parsed it like this:

p.decoder = gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, protocols...)

I got a result with only one layer - Ethernet - and it was bogus. It didn't show an error, but the addresses it was reporting did not agree with reality. If I started at IP:

p.decoder = gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, protocols...)

then IP gets decoded, and whatever else is above that (usually TCP, UDP, or ICMP).

The Attributes that come back include something called HwAddr. This is a string of bytes that does indeed look like the source MAC address, so that's great - but I want both, separately.

If you use ulogd directly, it can see these things. It actually reports three things:

ulogd is pretty complicated, I had a hard time following where it was getting those. But, the fact that it got them makes me think that the ethernet layer is passed through by netfilter, even though my rules are specifically for ipv4 or ipv6. At least, that's how I interpret this.

So my question really is about how to hook these two things together to get the link layer header: I think gopacket should be able to interpret these things, but that the 'Ethernet' message coming out of nflog is not compatible with whatever gopacket expects to see. Has anybody had success hooking these two things together?

Update: to see whether or not I was even remotely on the correct track, I followed a suggestion in a comment to this question. What I did was dumped the raw payload being sent back to me over the netlink socket. Here is an example:

[ 69 0 0 52 197 128 64 0 127 6 65 221 192 168 1 134 129 21 x y

This is the 'attribute.Payload' field that comes back over the netlink socket, and by doing this I can see clearly now that it's the IP header. In other words, I am trying to decode a header that isn't there. Decoding the above:

version=69
tos=0
length=52,1
id=97,128
offset+flags=64,0
ttl=127
proto=6
hdr_checksum=65,221
src=192 168 1 134
dst=129 21 x y

So I guess it just isn't there, which would explain why I can't decode it.

Upvotes: 2

Views: 268

Answers (0)

Related Questions