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

时间:2015-04-10 07:39:32

标签: c linux linux-kernel

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

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

封装:

  1. 创建应用程序数据(A_Data)。
  2. TLH(传输层标头)添加在A_Data中。
  3. 在步骤2中添加了NLH(网络层标头)。
  4. 在步骤3中添加了Eth(Ethrenet Layer Header)。
  5. 我认为内核模块的每一步都是专用的(我不确定)。如果是这样我想知道哪个模块正在执行第3步,哪个模块正在将该数据包传输到第4步,即以太网层。

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

    我想获取NAT防火墙代码。

1 个答案:

答案 0 :(得分:0)

分析源代码有两种方法。

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

    • 使用Kernel Documentation和描述内核内部的好书。我最喜欢的是Robert Love的“Linux内核开发”,但是“了解Linux网络内部”,如@ user2699113所示。
    • 您可以阅读代码,并使用http://lxr.linux.no/+trees等交叉引用系统。它们允许通过单击超链接快速浏览函数和定义。
  • 动态代码分析中,您可以向运行的内核添加一些探针和跟踪器,例如LTTng。我最喜欢的是SystemTap


我知道函数dev_queue_xmit(struct sk_buff*)负责通过网络发送数据包。让我们说通过我提出的两种方法收集它的初步知识。让我们深入研究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层函数,{{1 } br_dev_queue_push_xmit是设备级函数。

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

另请注意,大多数函数都有sk_buff后缀,这意味着没有单独的模块负责它们。这是因为Linux中的模块术语相当广泛:如果将CONFIG选项作为值[kernel]进行相关而不是大多数Linux子系统可能与vmlinux(“主模块”)静态链接y