I am writing some bpftrace
code in which I would like to compare an IP address (stored as a 32 bit integer) against the string representation of an address. That is, I want to do something like this:
kprobe:netif_receive_skb {
$skb = (struct sk_buff *)arg0;
$dev = $skb->dev;
$name = $dev->name;
$ipheader = ((struct iphdr *) ($skb->head + $skb->network_header));
// This pseudocode conditional is what I am trying to figure out
if ($ipheader->daddr == "8.8.8.8") {
printf("%s %s %s -> %s\n",
func, $name, ntop($ipheader->saddr), ntop($ipheader->daddr))
}
}
In the above, $ipheader
is a struct iphdr *
, and struct iphdr
looks like this:
struct iphdr {
...
__struct_group(/* no tag */, addrs, /* no attrs */,
__be32 saddr;
__be32 daddr;
);
};
So both saddr
and daddr
are unsigned 32-bit integers.
I thought perhaps I could use the pton()
function, like this:
if ($ipheader->daddr == pton("8.8.8.8")) {
But unfortunately pton()
returns an int8[4]
array instead of a single 32 bit integer, so this fails with:
traceit.bpf:8:5-41: ERROR: Type mismatch for '==': comparing 'unsigned int32' with 'unsigned int8[4]'
if ($ipheader->daddr == pton("8.8.8.8")) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I next tried to see if I could normalize both values into int8[4]
arrays, like this:
$target = pton("8.8.8.8");
$daddr = pton(ntop($ipheader->daddr));
if ($target == $daddr) {
But this fails because ntop()
doesn't actually return a string, so we get:
ERROR: Expected string literal, got inet
traceit.bpf:9:10-38: ERROR: pton() expects an string argument of an IPv4/IPv6 address, got
$daddr = pton(ntop($ipheader->daddr));
I realize I could just specify the target as an integer myself:
if ($ipheader->daddr == 0x08080808) {
But while that's easy to interpret for a contrived address like 8.8.8.8, it's opaque when the hex form of the address is something like 0xacd9004e
.
Is it possible to compare a 32-bit integer representation of an address with the string representation of an address using bpftrace
(and if so, what's the canonical way of doing so)?
This has been fixed in version 0.17 and 0.19:
Both of these should allow comparing IP addresses by casting them to a common type.