0

我对 c++ 还是有点陌生​​,我无法理解这段代码在做什么:

    #include <net/sock.h>

BEGIN
{
    printf("%-8s %-6s %-16s %-2s %-16s %-5s\n", "TIME", "PID", "COMM",
        "IP", "RADDR", "RPORT");
}

kprobe:ip4_datagram_connect,
kprobe:ip6_datagram_connect
{
    $sk = (struct sock *)arg0;
    $sa = (struct sockaddr *)arg1;
    if (($sa->sa_family == AF_INET || $sa->sa_family == AF_INET6) &&
        $sk->sk_protocol == IPPROTO_UDP) {
        time("%H:%M:%S ");
        if ($sa->sa_family == AF_INET) {
            $s = (struct sockaddr_in *)arg1;
            $port = ($s->sin_port >> 8) |
                (($s->sin_port << 8) & 0xff00);
            printf("%-6d %-16s 4  %-16s %-5d\n", pid, comm,
                ntop(AF_INET, $s->sin_addr.s_addr), $port);
        } else {
            $s6 = (struct sockaddr_in6 *)arg1;
            $port = ($s6->sin6_port >> 8) |
                (($s6->sin6_port << 8) & 0xff00);
            printf("%-6d %-16s 6  %-16s %-5d\n", pid, comm,
                ntop(AF_INET6, $s6->sin6_addr.in6_u.u6_addr8),
                $port);
        }
    }
}

我认为其中的“BEGIN”部分是定义一个宏,但我不完全确定。我真正感到困惑的是

kprobe:ip4_datagram_connect,
kprobe:ip6_datagram_connect
{

这是在做什么?这似乎是一个函数声明,但在这种情况下,单冒号是什么意思?这是某种初始化列表,但对于函数?是否将 ip4 和 ip6 都设置为该功能?

另外,美元符号变量名有什么意义吗?还是它们只是声明变量的有效方式?

这是密件抄送工具中 udpconnect.bt 的代码。我正在尝试将其转换为 python。

4

1 回答 1

0

正如评论中提到的,这是 bpftrace 的脚本。您可能想查看此工具的参考指南

BEGIN块在您的程序开始时运行(就像awk脚本一样,如果您熟悉它的话)。在这种情况下,它用于将数组的标题行打印到控制台输出。

然后是块:

kprobe:ip4_datagram_connect,
kprobe:ip6_datagram_connect
{

... 定义将被转换为eBPF 程序的指令(中间步骤作为 LLVM 中间表示),并附加到 Linux 内核中的一个或多个钩子。在当前情况下,kprobe:...定义钩子:程序将作为 kprobe 函数运行,用于ip4_datagram_connect内核中的函数及其 IPv6 对应项。换句话说,它会在内核每次进入这些函数时运行。

快速浏览一下,我认为程序应该打印,每次 UDP 流启动时,打开套接字的进程的时间、PID 和名称、IP 地址、远程地址和远程端口。第一个if检查数据包是否为(IPv4 or IPv6) and UDPif/else下面将 IPv4/IPv6 两种情况分开。

于 2021-08-10T19:35:20.463 回答