首页 文章

在linux内核编程中捕获TCP数据包

提问于
浏览
-1

我正在使用Linux(ubuntu 14.04) . 我想要一些关于linux内核编程的典型信息 .

在TCP通信中,当linux内核通过封装头创建数据包时,我希望在从网络层到以太网层(而不是通过wireshark)时捕获数据包 .

封装:

  • 创建了应用程序数据(A_Data) .

  • TLH(传输层标头)添加在A_Data中 .
    在步骤2中添加

  • NLH(网络层标头) .

  • Eth(Ethrenet Layer Header)在步骤3中添加 .

我认为内核模块的每一步都是专用的(我不确定) . 如果是这样我想知道哪个模块正在执行步骤3,哪个模块正在将该数据包传输到步骤4,即以太网层 .

我有一个内核源代码,即linux-3.13.0 .

我想获得NAT防火墙代码 .

1 回答

  • 0

    分析源代码有两种方法 .

    • static 代码分析中,您没有正在运行的系统:

    • 使用Kernel Documentation和描述内核内部的好书 . 我最喜欢的是Robert Love的"Linux Kernel Development",但是"Understanding Linux Network Internals"正如@ user2699113所暗示的那样 .

    • 您可以阅读代码,并使用交叉引用系统,如http://lxr.linux.no/+trees . 它们允许通过单击超链接快速浏览函数和定义 .

    • dynamic 代码分析中,您将一些探针和跟踪器添加到正在运行的内核,如LTTng . 我最喜欢的是SystemTap


    我知道函数 dev_queue_xmit(struct sk_buff*) 负责通过网络发送数据包 . 让's say its preliminary knowledge collected through both of methods I presented. Let'深入 struct sk_buff* 寻找相应的设备级处理程序:

    struct sk_buff {
        ...
        struct sock     *sk;
        struct net_device   *dev;
        ...
    

    因此,让我们使用SystemTap捕获struct net_device背后的一些信息:

    # stap -e 'probe kernel.function("dev_queue_xmit") { 
            printf("symname: %s\n", 
                symname($skb->dev->netdev_ops->ndo_start_xmit)); 
            print_backtrace(); }' --all-modules
    ...
    symname: tg3_start_xmit
    0xffffffff813277b8 : dev_queue_xmit+0x0/0x7 [kernel]
    0xffffffffa02482e2 : br_dev_queue_push_xmit+0x163/0x169 [bridge]
    0xffffffffa024672a : br_dev_xmit+0x1be/0x1db [bridge]
    0xffffffff8132726f : dev_hard_start_xmit+0x23b/0x315 [kernel]
    0xffffffff813276b6 : __dev_queue_xmit+0x36d/0x46a [kernel]
    0xffffffff81353690 : ip_finish_output2+0x226/0x29a [kernel]
    0xffffffff81354dcd : ip_queue_xmit+0x270/0x29b [kernel]
    0xffffffff81366d6c : tcp_transmit_skb+0x6f9/0x72a [kernel]
    0xffffffff81367cd1 : tcp_write_xmit+0x802/0xa20 [kernel]
    0xffffffff81367f3f : __tcp_push_pending_frames+0x24/0x50 [kernel]
    0xffffffff8135de79 : tcp_sendmsg+0x6af/0x7c9 [kernel]
    0xffffffff813121df : sock_write_iter+0x7c/0xa1 [kernel]
    0xffffffff81138510 : new_sync_write+0x6a/0x8e [kernel]
    0xffffffff811392aa : vfs_write+0x9c/0x11e [kernel]
    0xffffffff811394f4 : sys_write+0x51/0x85 [kernel]
    0xffffffff813e6449 : system_call_fastpath+0x12/0x17 [kernel]
    

    现在,您有负责传输数据包的函数名称,如果需要,可以更深入,即 tcp_write_xmit 是TCP层函数, ip_finish_output2 是IP层函数, br_dev_queue_push_xmittg3_start_xmit 是设备级函数 .

    如果您希望捕获数据包的数据,您可以绑定到其中一个函数并从 sk_buff 中提取数据(即请参见此处:Extracting data from struct sk_buff

    另请注意,大多数函数都有 [kernel] 后缀,这意味着没有单独的模块负责它们 . 这是因为Linux中的模块术语相当广泛:如果将CONFIG选项更改为值 y 而不是 m ,则大多数Linux子系统可能与 vmlinux ("main module")静态链接 .

相关问题