1

sock_sendmsg()で定義されているカーネルの関数にハンドラーをフックすることにより、Linux 上の特定のプロセスによって送信されたすべてのデータをダンプしようとしましたlinux/socket.cprobe kernel.function("sock_sendmsg@net/socket.c")2 番目の引数で渡されたすべてのデータ ブロックをダンプするための systemtap プローブ ハンドラーを作成することで、これを行うことができますstruct msghdr *msg

からの抜粋は次のnet/socket.cとおりです。

int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
{
    struct kiocb iocb;
    struct sock_iocb siocb;
    int ret;

    init_sync_kiocb(&iocb, NULL);
    iocb.private = &siocb;
    ret = __sock_sendmsg(&iocb, sock, msg, size);
    if (-EIOCBQUEUED == ret)
            ret = wait_on_sync_kiocb(&iocb);
    return ret;
}

systemtap スクリプトをテストしましたhook_sendmsg.stp。まずhook_sendmsg.stp、1 つのターミナルで実行しました。次に、別のターミナルを開き、telnetコマンドを呼び出して接続し、ターミナルstackoverflow.comに入力HEAD / HTTP/1.0<Enter twice>しました。hook_sendmsg.stpから次の出力を得ました。

root@debian:~# stap -g hook_sendmsg.stp
message block [0]; type=3(raw); state=1(unconnected)
14 00 00 00 16 00 01 03 ec 95 f4 52 00 00 00 00 |...........R....|
00 00 00 00                                     |................|
message block [0]; type=3(raw); state=1(unconnected)
14 00 00 00 16 00 01 03 ec 95 f4 52 00 00 00 00 |...........R....|
00 00 00 00                                     |................|
message block [0]; type=2(udp); state=1(unconnected)
4d 0d 01 00 00 01 00 00 00 00 00 00 0d 73 74 61 |M............sta|
63 6b 6f 76 65 72 66 6c 6f 77 03 63 6f 6d 00 00 |ckoverflow.com..|
01 00 01                                        |................|
message block [0]; type=2(udp); state=1(unconnected)
0f 1e 01 00 00 01 00 00 00 00 00 00 0d 73 74 61 |.............sta|
63 6b 6f 76 65 72 66 6c 6f 77 03 63 6f 6d 00 00 |ckoverflow.com..|
1c 00 01                                        |................|
message block [0]; type=1(tcp); state=3(connected)
48 45 41 44 20 2f 20 48 54 54 50 2f 31 2e 30 0d |HEAD / HTTP/1.0.|
0a                                              |................|
message block [0]; type=1(tcp); state=3(connected)
0d 0a                                           |................|

これはsock_sendmsg()、 のコンテキストで合計 6 回呼び出されたことを示していますtelnet。明らかに 3 番目と 4 番目は、Google のパブリック DNS サーバー8.8.8.88.8.4.4. 5行目と6行目は、 から送信されたHTTPリクエストの2行ですtelnet。しかし、1 番目と 2 番目は何のために呼び出されたのでしょうか。それらはカーネルによって内部的に呼び出されましたか?

前もって感謝します。

4

1 に答える 1

1

strace を使用してユーザー空間から telnet コマンドを監視するとわかるように、これらは NETLINK メッセージです (ソケット ファミリーを確認してください)。

sendto(3, "\24\0\0\0\26\0\1\3?\254\364R\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK,  pid=0, groups=00000000}, 12) = 20
sendto(3, "\24\0\0\0\26\0\1\3?\254\364R\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
send(3, "\212\355\1\0\0\1\0\0\0\0\0\0\rstackoverflow\3com\0\0"..., 35, MSG_NOSIGNAL) = 35
send(3, "\241\353\1\0\0\1\0\0\0\0\0\0\rstackoverflow\3com\10i"..., 50, MSG_NOSIGNAL) = 50
send(3, "|\341\1\0\0\1\0\0\0\0\0\0\rstackoverflow\3com\0\0"..., 35, MSG_NOSIGNAL) = 35
send(3, "HEAD / HTTP/1.0\r\n", 17, 0)   = 17
send(3, "\r\n", 2, 0)                   = 2

Netlink は、ユーザー空間プロセスがカーネルと通信するために使用するインターフェースです (したがって、それらは telnet によって送信されます)。一部の通常のネットワーク C 関数 (getsockname など) は、この種の NETLINK メッセージを内部的に処理します。

もう少し調査したい場合は、send_message のペイロードを netlink ヘッダー構造に変換し、メッセージのタイプを確認する必要があります。

       struct nlmsghdr {
           __u32 nlmsg_len;    /* Length of message including header. */
           __u16 nlmsg_type;   /* Type of message content. */
           __u16 nlmsg_flags;  /* Additional flags. */
           __u32 nlmsg_seq;    /* Sequence number. */
           __u32 nlmsg_pid;    /* Sender port ID. */
       };

[1] http://man7.org/linux/man-pages/man7/netlink.7.html

于 2014-02-07T10:35:09.853 に答える