我正在编写一些bpftrace
代码,其中我想将IP地址(存储为32位整数)与地址的字符串表示进行比较。也就是说,我想做这样的事情:
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 -> %sn",
func, $name, ntop($ipheader->saddr), ntop($ipheader->daddr))
}
}
在上面,$ipheader
是一个struct iphdr *
,struct iphdr
看起来像这样:
struct iphdr {
...
__struct_group(/* no tag */, addrs, /* no attrs */,
__be32 saddr;
__be32 daddr;
);
};
所以saddr
和daddr
都是32位无符号整数。
我想也许我可以使用pton()
函数,像这样:
if ($ipheader->daddr == pton("8.8.8.8")) {
但不幸的是,pton()
返回int8[4]
数组,而不是单个32位整数,所以这失败了:
traceit.bpf:8:5-41: ERROR: Type mismatch for '==': comparing 'unsigned int32' with 'unsigned int8[4]'
if ($ipheader->daddr == pton("8.8.8.8")) {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
我接下来试着看看我是否可以将两个值归一化为int8[4]
数组,像这样:
$target = pton("8.8.8.8");
$daddr = pton(ntop($ipheader->daddr));
if ($target == $daddr) {
但是这个失败了,因为ntop()
实际上没有返回字符串,所以我们得到:
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));
我意识到我可以把目标指定为一个整数:
if ($ipheader->daddr == 0x08080808) {
但是,虽然对于像8.8.8.8这样的人为地址来说,这很容易解释,但是当地址的十六进制形式是像0xacd9004e
这样的时候,它就不透明了。
是否可以使用bpftrace
比较32位整数表示的地址与字符串表示的地址(如果可以,规范的方法是什么)?
如果$ipheader->daddr为192.168.2.44,只需将这四个数字转换为十六进制字符,即c0 a8 02 2c
。反转字符是2c 02 a8 c0
。所以你可以写:
if ($ipheader->daddr == 0x2c02a8c0) {
...
}