Linux 中的网络数据包捕获

Linux 中的网络数据包捕获
Ashish Chaurasia, 工程师

简介:  本教程介绍了捕获和操纵数据包的不同机制。安全应用程序,如 VPN、防火墙和嗅探器,以及网络应用程序,如路由程序,都依赖类似于本文描述的方 法来完成工作。一旦接触到它们,您将会离不开它们。
标记本文!

发布日期:  2004 5 31 日
级别: 初级

访问情况 8870 次浏览
建议: 2 (查看或添加评论)
1 star2 stars3 stars4 stars5 stars 平均分 (共 9 个评分)

开始之前

关于本教程

目前,信息要通过管道(也就是网络)传输,需要花很多时间封装在数据包中。在本教程中,我们将在这些数据包传输过程中捕获它们,捕获数据包所采用的平台是 Linux。

大多数网络应用程序――从虚拟专用网(VPN)到路由程序,再到嗅探器――都具有某种数据包捕获机制。因此,编写此类软件的任何人都可以从本教程中受益。

由于我们将要研究的几种数据包过滤机制都是内核模块,所以还将简要地介绍这些模块以 及内核编译。

我们还将回顾一些我没有成功使用的机制:我只能获得数据包的一个副本而无法截获最初的数据包。这里的讨论不仅能省去您重复我所做工作的麻烦,而且还对编写网络应用程序(如嗅探器) 很有用。

除大致熟悉不同的数据包捕获机制(如防火墙钩子、divert socket netfilter)外; 读者还应具备有关 Linux 网络和 TCP/IP 协议栈方面的知识。开始之前最好了解一些源代 码的知识。

回页首

前提条件

本教程最适合那些以前在系统编程、Linux 网络和 Linux 内核模块方面至少有一些经验的读者。但是,本教程尽可能简单地给出一些概念,并在适当的时候给予详细解释,因此,即使读者缺少一种或多种这方面的知识,也能从本文的讨论中获益。

简介

数据包捕获

TCP/IP 协议栈是 Linux 网络的重要支柱,其体系结构设计得非常优美。数据包 是 TCP/IP 协议栈中信息流的载体。在 Linux 网络编程中,许多有意义的工作都包括了捕获这些信息丰富的数据包、提取或操作这些数据包所包含的信息。

数据包捕获 对我们而言意味着某种机制,即获取一个数据包,直到达到所要求的目的后才将其释放,以便该数据包能够按照常规路径通过其余的任何处理。其他相同或相似 操作的术语有 数据包过滤、数据包嗅探、网络嗅探 以及 数据包 或 网络监视。

数据包过滤是许多网络软件的基础,这些软件有网络监视工具、VPN、网络分析程序、路由 程序、入侵监测系统(Intrusion Detection SystemsIDS)和嗅探器。

Linux 提供了多处可以捕获数据包的位置,既包括用户空间,又包括内核空间。下图展示了网络数据包流过 TCP/IP 协议栈的路径:

图 1. 网络数据包通过协议栈的路径
网络数据包通过协议栈的路径

如上图所示,流入的数据包通过以太网层、网络层、TCP 协议栈并穿过套接字层,然后才能被复制到用户空间中。在所有这些断点处,数据包都很容易被捕获到。本教程讨 论的方法大多在网络层和用户空间中有效。

然而,由于 Linux Linux 内核在不断发展,这里讨论的某些数据包捕获方法仅在特定 的内核中有效。例如,divert socket 对打过补丁的 2.2.12 内核有效,而 netfilter 对 内核 2.4.x 2.6.x 有效。在讨论各种方法时始终要注意这些细节。

Linux 可加载的内核模块(LKM)概述

捕获数据包的模块

本教程探讨的大多数数据包捕获机制都是以 Linux 内核模块的方式工作的,因此我们现在简 要讨论一下这些模块。如果您有很强的 LKM 背景,则可以跳至下一节 编译内核 。

回页首

什么是 LKM?

可加载内核模块 是内核的扩展,可以在需要时附加到内核中,或从内核中删除。LKM 基本上是设备驱动程序的软件实现,它与真实的或者虚拟的硬件设备协同工作。当 LKM 加载到内核中时,它们监听和处理对设备的任何请求。由于只加载所需的 LKM,因此使 用 LKM 可使内核变得轻便、模块化、灵活和可伸缩。

回页首

LKM 体系结构

编写 Linux 内核模块的体系结构如下:

    init_module
    这个 LKM 初始化函数是强制执行的。当 LKM 加载到内核时触发该函数,因此 所有初始化工作都是在这个函数中完成的。
    处理特定的函数
    这些函数执行实际的工作,如读、写、打开、关闭设备,等等。
    cleanup_module
    当从内核中删除 LKM 时,调用 LKM 的这个强制执行函数。因此,所有清除工作 如释放内存等都应在这个函数中执行。

回页首

编译 LKM

编写 LKM 后,可以采用下列命令编译它:

   gcc -c -g  <module_name>.c -I/usr/src/linux/include


该命令产生一个名为 <module_name>.o 的文件,它就是 LKM,可以使用下列命令将它加载到 内核中:

   insmod -f <module_name>.o-f 选项意味着强制加载。)

如果在加载模块时遇到任何内核版本问题,可以通过在加载 LKM 时包含这个特定内核 的头文件来解决问题。因此,在编译内核时,请使用 -I/usr/src/linux/include。

还可以使用 Makefile 来解决此类版本问题,但这超出了本教程的范围。在本教程的末 尾,您还可以在 参考资源 中找到有关 LKM 编程的更多信息。

回页首

卸载 LKM

一旦模块加载到内核中,它将开始执行预定的功能。使用命令 lsmod 可 以看到当前所有加载的 LKM 的列表。

可以使用 rmmod <module_name> 从内核中加载或删除模块。

编译内核

回顾

本教程讨论的许多机制都要求设置某些内核选项,然后重新编译内核。因此在开始前,我们将复习内核编译的步骤。如果您已经了解内核编译,则可以跳至下一 节 数据包截获:防火墙钩子 ,在那里开始复习数据包捕获机制。

回页首

步骤

重新编译内核:

    make xconfig
    允许设置不同的内核选项。(也可以使用 make menuconfig make config;这只是个人偏好问题。)
    make dep
    解决内核编译的文件依赖性。
    make bzImage
    编译(make)内核映像并将其存储在 vmlinuz 中。
    make installvmlinuz 复制到 /boot 目录中,并将二进制文件复制到正确的位置。
    make modules
    编译所有内核模块。
    make modules_install
    在正确的位置安装模块(通常位于 /lib/modules/<kernel-version> )。

接着,您应将关于最近编译内核的信息添加到 /etc/lilo.conf(如果不在该位置的话),然后重新启动机器。您会在重新启动过程的开始看到列出的新内核选项。


数据包截获:防火墙钩子

概述

防火墙钩子(Firewall hook) 已引入到 2.2.16 内核中,它是 2.2.x 内核运行的数据包截获方法。防火墙钩子在 TCP/IP 协议栈的 IP 层截获数据包。

防火墙钩子在功能上充当 Linux 可加载内核模块(LKM)或伪设备驱动程序,可以根据 需要从内核中加载或卸载。

要使用防火墙钩子,请在内核编译期间启用 firewalling 选项 (在 Networking 选项下列出)。

您可以使用该数据包截获机制来开发路由程序、VPN、数据包嗅探器或位于网络边缘且要求实时捕获数据包的任何其他网络应用程序。

回页首

填充结构

内核定义的 firewall_ops 结构是防火墙钩子的基础。可以用这些结构来指定各种数据包策略,这些策略可以是非常特殊的,也可以是很普通的。

firewall_ops 结构位于 /usr/src/linux/include/linux/firewall.h 中,类似如下:

   struct firewall_ops

   {

              struct firewall_ops next;

              int (*fw_forward)(struct firewall_ops *this, int pf,

                                struct device *dev, void *phdr, void
   *arg, struct

                               sk_buff **pskb);

              int (*fw_input)(struct firewall_ops *this, int pf,

                                       struct device *dev, void *phdr,
   void *arg, struct sk_buff

                                       **pskb);

              int (*fw_output)(struct firewall_ops *this, int pf,

                                       struct device *dev, void *phdr,
   void *arg, struct sk_buff

                                       **pskb);

              int fw_pf;

              int fw_priority;

   };


这种机制是作为 LKM 来实现的。同样,它需要 init_module(用于初始化模块)、cleanup_module 和某些特定处理的函数:
next 	指向下一个钩子的指针
fw_forward 	转发数据包的函数指针
fw_input 	流入数据包的函数指针
fw_output 	流出数据包的函数指针
fw_pf 	协议簇
fw_priority 	所选防火墙的优先权

这些都是实际的函数指针;相应的函数在下一个屏中定义。

回页首

函数

为了处理数据包,需要定义三个函数:

流入的数据包处理:

   static int fw_input(struct firewall_ops *this,int pf,struct device
   *dev,void

                                   *phdr,void *arg,struct sk_buff **pskb)


对所有流入的数据包都要调用该函数。如果需要对流入的数据包进行任何处理(也称为 "mangling"),如添加额外的字段,可以在此进行处理。

流出的数据包处理:

   static int fw_output(struct firewall_ops *this,int pf,struct device
   *dev,void

                                   *phdr,void *arg,struct sk_buff **pskb)


对所有流出的数据包(源自主机)调用该函数。可以在这里对此类数据包进行任何额外处理。

转发数据包处理:

   static int fw_forward(struct firewall_ops *this,int pf,struct device
   *dev,void

                                   *phdr,void *arg,struct sk_buff **pskb)


对所有转发的数据包调用该函数。

下面是在上述函数中传递参数的详细信息。
*this 	指向防火墙钩子结构的指针
pf 	代表协议簇
*dev 	指向以太网卡设备结构的指针 card
*phdr 	指向 IP 地址缓冲区的指针
*arg 	额外的参数,在需要时传递给函数 function
**pskb 	指向 TCP_IP 协议栈的 sk_buff 层的指针

对于上述每个函数,数据包的返回值(或对数据包的操作)可以是:

    Accept
    该操作由 FW_ACCEPT 宏完成。它接受数据包并且数据包遵循正常的 TCP/IP 协议栈路径。
    Reject
    该操作由 FW_REJECT 宏完成。它拒绝所有数据包,既没有网络流量流出, 又没有网络流量流入。
    Redirect
    该操作由 FW_REDIRECT 宏完成。它将数据包重定向到特定的主机。

回页首

函数(续)

现在,我们将把上一屏中定义的函数赋值给 firewall_ops 结构中的指针。一旦赋值 完成,firewall_ops 结构将被填充,函数将由系统本身调用――这就是术语 回调函 数。

下面是要填充的字段:

      struct firewall_ops * next;                   

      int fw_pf;                                

      int fw_priority;                          


现在,防火墙结构与下面的代码类似:

   

   static struct firewall_ops myOps = {NULL,

            fw_forward,

           fw_input,

          fw_output,


   PF_INET,                                     

   1                                            

   };


回页首

Kernel 注册

现在,您需要将 firewall_ops 结构注册到内核:

         register_firewall(protocol family, struct firewall_ops *);LKM init_module 代码中进行注册。

回页首

取消注册 firewall_ops 结构

当卸载 LKM 时,cleanup_module 函数应包含

         unregister_firewall(protocol family, struct firewall_ops *);LKM 进行编码、编译并加载到内核后,您的数据包拦截器就准备工作了。

完成在接下来的两屏中给出的这个 LKM 的源代码和使用说明。

回页首

源代码:防火墙钩子程序

   

   

   


   


   #define MODULE

   #define __KERNEL__


   #include<linux/config.h>

   #include<linux/module.h>

   #include<linux/version.h>


   #include<linux/netdevice.h>

   #include<net/protocol.h>

   #include<net/pkt_sched.h>

   #include<net/tcp.h>

   #include<net/ip.h>


   #include<linux/if_ether.h>

   #include<linux/ip.h>

   #include<linux/tcp.h>

   #include<linux/skbuff.h>

   #include<linux/icmp.h>


   #include<linux/kernel.h>

   #include<linux/mm.h>

   #include<linux/file.h>

   #include<linux/firewall.h>

   #include<asm/uaccess.h>


   //Function for forwarded packets

   static int fw_forward(struct firewall_ops *this,int pf,struct device
   *dev,void *phdr,void *arg,struct sk_buff **pskb)

   {

               struct iphdr *hdr = (struct iphdr *)(*pskb)->h.ipiph;

               printk("
	fw_forward)() called...");

               printk("
		The source of this packet is:
   %s",in_ntoa(hdr->saddr));

               return FW_ACCEPT;

   }


   

   static int fw_input(struct firewall_ops *this,int pf,struct device
   *dev,void *phdr,void *arg,struct sk_buff **pskb)

   {

               struct iphdr *iph;

               iph = (struct iphdr*)(*pskb)->h.ipiph;

               printk("
	fw_input() called...");

               printk("
		The source of this packet is:
   %s",in_ntoa(iph->saddr));

               return FW_ACCEPT;

   }


   

   static int fw_output(struct firewall_ops *this,int pf,struct device
   *dev,void *phdr,void *arg,struct sk_buff **pskb)

   {

               struct iphdr *iph;

               iph = (struct iphdr*)(*pskb)->h.ipiph;

               printk("
	fw_output)() called...");

               printk("
	This packet is destined for:
   %s",in_ntoa(iph->daddr));

               return FW_ACCEPT;

   }


   

   static struct firewall_ops myOps =
   {NULL,fw_forward,fw_input,fw_output,PF_INE int fw_pf; ,int fw_priority;       T,1};


   

   int init_module(void)

   {

           

               if(register_firewall(PF_INET,&myOps) < 0)

               {

                           printk("

	ERROR...firewall main aag lag
   gayee!!!");

                           return -1;

               }

               else

               {

                           printk("

	Firewall registered");

               }

               return 0;

   }



   

   void cleanup_module(void)

   {

           

               if(unregister_firewall(PF_INET,&myOps)<0)

               {

                           printk("

	Error....Firewall can't be
   unregistered");

               }

               else

               {

                           printk("

	Firewall unregistered");

               }


   }


回页首

使用防火墙钩子程序

    编译和运行防火墙钩子程序:

       gcc -c -O NetFWHook.c -I/usr/src/linux/include/


    您将得到一个名为 NetFWHook.o 的文件。请使用下列命令将其插入到内核中:

       /sbin/insmod  -f NetFWHook.o


    要查看由这个 LKM 生成的消息,请运行 dmesg 命令。

数据包截获:Netfilter

概述

Netfilter 是由内核 2.4.x 2.6.x 提供的数据包截获机制,它替代了内核 2.2.x 中 使用的 ipchains、防火墙钩子和其他方法。Netfilter 也可以作为 LKM 获得。

要使用 netfilter,在内核编译时设置 Packet Filtering 选项。

可以对采用防火墙钩子机制的同类应用程序使用 netfilter 机制,这些应用程序有:路由程序、数据包嗅探器和其他位于网络边缘并访问通信流的实体。

回页首

使用 Netfilter

Netfilter 可以在通过 TCP/IP 协议栈的路径中的几个定义良好的点上捕获数据包:

    NF_IP_PRE_ROUTING
    在对数据包进行初始正确性检查(校验和等)后,保存该数据包。
    NF_IP_LOCAL_IN
    如果数据包将要到达本地主机,则捕获该数据包。
    NF_IP_FORWARD
    如果数据包将要到达某些其他主机,则捕获该数据包。
    NF_IP_LOCAL_OUT
    在本地捕获其目的地是外部的已创建的数据包。
    NF_IP_POST_ROUTING
    这是最后的钩子,在此之后将传输数据包。

当数据包穿过 TCP/IP 协议栈后,协议调用带有数据包和钩子号的 netfilter 框架。钩子也 可以指派优先级。

函数的返回值包括:

    NF_ACCEPT
    数据包继续在正常的 TCP/IP 路径上传输。
    NF_DROP
    丢弃数据包;不进一步处理。
    NF_STOLEN
    已获得数据包;不进一步处理。
    NF_QUEUE
    对数据包排队(通常用于用户空间处理)。
    NF_REPEAT
    再次触发这个钩子。

回页首

步骤

Netfilter 的工作方式与防火墙钩子非常相似。作为 LKM 注册到内核的结构 调用特定于进程的函数。任何基于 netfilter 的数据包拦截器都必须遵循开发 LKM 所采 用的步骤。

回页首

特定于进程的函数

特定于进程的函数(或钩子)的原型如下所示:

   static unsigned int packet_interceptor_hook(unsigned int hook, struct
   sk_buff **pskb,

   const struct net_device *indev, const struct net_device *outdev, int

   (*okfn) (struct sk_buff *))


您可以将字段定义为:

    hook
    您感兴趣的钩子的编号;例如 NF_IP_LOCAL_OUTNF_IP_LOCAL_INNF_IP_ FORWARD 等。
    **pskb
    指向 TCP/IP 协议栈中数据包容器的指针;例如 sk_buff*indev & *outdev
    指向流入和流出网络设备的设备结构的指针。在内核中注册的每种设备(例如,以太网卡)都 有一个由 IRQIO 地址等组成的设备结构。当机器只有一个网络接口来处理流入和流出流量时,这两个结构是相同的。当流入和流出的流量由两种设备处理时,这两种结构是 不同的。
    (*okfn) (struct sk_buff *)
    在激活钩子时调用该函数。

回页首

netfilter 结构

核心 netfilter 结构在 /usr/src/include/linux/netfilter.h 中定义,类似如下:

struct nf_hook_ops
{
         struct list_head list;

         
         nf_hookfn *hook;
         int pf;
         int hooknum;
         
         int priority;
};


参数是:

    list
    Netfilter 本身是一个钩子链;它指向 netfilter 钩子的头部,通常设置为 { NULL, NULL }hook
    该函数在数据包碰到钩子点时被调用。该函数与前面描述的函数相同,它必须返回 NF_ACCEPTNF_DROP NF_QUEUE。如 果返回 NF_ACCEPT,则下一个钩子将被附加到将要调用的点。如 果返回 NF_DROP,则数据包被丢弃。如果返回 NF_QUEUE,则对数据包进行排队。sk_buff 指针被传递到该函数中,并用数据包信息如 IP 报头、TCP 报头等进 行填充。您可以使用 sk_buff 结构指针来操作或删除数据包(要删除数据包,只需将 skb 指 针设置为空即可)。
    pf
    协议簇;例如,适用于 IPv4 PF_INEThooknum
    您感兴趣的钩子号;例如 NF_IP_LOCAL_IN 等。

回页首

内核注册

在 LKM init_module 函数中,需要注册在内核中填充的结构:

int nf_register_hook(struct nf_hook_ops *req);


这里,nf_hook_ops netfilter 操作结构。

一旦该结构注册到内核中,Linux 将调用这里定义的函数来处理数据包。

回页首

取消注册 netfilter 结构

卸载 LKM 时,netfilter 结构需要从内核中取消注册。这一操作在 cleanup_module 函数中完成:

void nf_unregister_hook(struct nf_hook_ops *req);


nf_hook_ops 也是 netfilter 操作结构。


数据包截获:Divert socket

概述

2.2.12 内核的其中一个补丁引入了一种新类型的原始套接字(raw socket),称 为 divert socket,该套接字按照防火墙规范过滤数据包,并将其发送到用户空 间。数据包从这里开始进行处理或简单地再放回到 TCP/IP 协议栈中。

Divert socket 是一种特殊类型的原始套接字,与任何其他套接字一样,通过该套接字 可以接收和发送数据包。Divert socket 使用 Linux 内核的 firewalling 功能:可以 将 Linux firewalling 设置为对流入、流出和转发数据包应用受限的策略,然后将其重 定向到指定的端口。Divert socket 将在该端口进行监听,然后进一步重定向数据包。

使用 divert socket 的主要缺点是将数据包复制到用户空间的开销,这会占用时间 和资源,从而降低了网络性能。

任何没有对数据包实时处理施加硬性限制的联网应用程序(如嗅探 器),您都可以使用 divert socket。

回页首

内核编译选项

Linux firewalling 是使用 divert socket 的先决条件,因此应在内核编译时启用该选项。某些选项已专门为 divert socket 引入到内核中,并应在编译时设置它们:

    Firewalling
    启用内核的 firewalling 功能。
    IP Firewalling
    启用内核的数据包过滤功能。
    IP:divert sockets
    在内核中启用 divert socketIP:divert pass-through
    如果已设置了该选项并且没有应用程序正在监听 divert socket 端口,则该数据包不转 移,只按照正常的路径传输。
    IP:always defragment
    如果设置该选项,则整理内核中的所有碎片,这会严重降低性能。

ipchains 控制网络数据包传输的路径。要将 ipchains divert socket 一起使用,应下载、编译和安装打了补丁的 ipchains 版本 ipchains-1.3.9。

在下一屏对 ipchains 进行一般性介绍。

回页首

ipchains 简介

    Input chain
    允许所有流入的数据包(目的地是主机的数据包和转发的数据包)穿过。
    Output chain
    允许所有流出的数据包(源自主机的数据包和转发的数据包)穿过。
    Forward chain
    只允许转发的数据包穿过。

转发的数据包按以下顺序穿过链:

    输入
    转发
    输出

数据包截获:内核改动

概述

在此,我们将操作内核源代码以扩展内核本地数据包截获能力。

内核源文件位于 /usr/src/linux,要修改的两个主要文件 是 ip_input.c ip_output。这两个文件位于 /usr/src/linux/net/ipv4/ 目录中。

回页首

源文件修改:ip_input.c

ip_input.c 包含这两个函数,可以为所有流入数据包调用它们: incoming packets:

  ip_local_deliver(struct sk_buff, struct device,struct packet_type)


为所有的流入数据包执行而不考虑目的地

   ip_rcv(struct sk_buff, struct device,struct packet_type)


为目的地是本地机器的所有数据包进行调用

    sk_buff
    TCP/IP 协议栈中数据包的容器。
    device
    设备结构。
    packet_type
    数据包的类型:流入或流出。

ip_rcv 执行 IP 层所需的几个任务,包括重新装配、校验和计算等。

由于 ip_rcv 处理所有流入的 IP 数据包,因此这是一个添加要对流入数据包执行任何附加代码的好地方。其他选项是用于编写自己 的 ip_rcv 例程的。

回页首

源文件修改:ip_output.cip_output 一样,ip_output.c 位于 /usr/src/linux/net/ipv4/ 目录中,它处理流出的数据包。它的四个函数是:

     ip_build_and_sent_pkt(struct sk_buff,struct sock,u32 saddr,u32
   daddr, struct ip_options)IP 报头添加到 sk_buff 并将其发送出去

    ip_queue_xmit(struct sk_buff)


对要发送的数据包排队

    ip_build_xmit_slow()


构建和传送数据包

      ip_build_xmit()


“快速”构建和传送数据包,该选项只用于无需碎片整理的选项。

只有 ip_build_xmit_slow ip_build_xmit 处理所有 流出的 IP 数据包,因此任何额外处理均可在任何阶段完成。对 于 ip_input.c,其他选项用于编写自己的例程,然后从这些例程中调用最初的函数。您 选择的策略依赖于您要实现的功能。

回页首

使用 Makefiles 修改源代码

可以使用 Makefiles 动态修改内核源代码;Makefile 脚本确保对源代码做必需的修改。可以使用一条命令(make install make uninstall)添加或删除数据包拦截器,然后重新编译内核并重新启动机器。

由于该机制要求修改 Linux 内核源代码,所以快速调试可能非常困难。而且,由于该方法要求重新编译内核,所以这个过程是冗长、复杂且不灵活的。


数据包截获:创建数据包的副本

概述

某些数据包捕获机制仅提供数据包的副本而非数据包本身。但是,我们前面提到过,在开发网络嗅探器应用程序时,数据包的副本仍然是很有用的。

回页首

协议处理程序

协议处理程序是另一种充当 LKM 的机制。

协议处理程序对处理通过以太网卡传来的数据包。为此,协议处理程序必须注册到网络设备中;在本例中,应该注册到以太网卡的设备结构中。

网卡设备结构还包含一个指向 init 函数的指针,该函数初始化设备。

回页首

实现协议处理程序

实现协议处理程序的步骤:

    为以太网接口创建设备结构的实例,并将其注册到内核中。
    注册处理程序例程,用于处理具有设备结构的数据包。

现在,通过以太网接口的任何数据包都能得到正确处理。对 数据包的副本 而非最初 的数据包进行处理。不可能通过 TCP/IP 协议栈转移来自最初路径的数据包,因此只有数据包的 副本到达协议处理程序本身。

回页首

中断处理程序

顾名思义,该机制是以中断处理作为基础的,也可以作为 LKM 来实现。不论何时,只要有数据包到达以太网卡,就会生成中断。通过编写自己的中断处理程序,您就可以捕获数据包 并对其进行任何必要的处理。

幸运的是,无论何时只要有数据包穿过 TCP/IP 协议栈,就会生成中断,这会设置以太网卡中的标志,表示数据包是流入的还是流出的。这个中断通常是中断 9,因此,您可以编写中断处理程序 来处理中断 9 的信号,然后处理数据包。

在这种情况下,由于有了协议处理程序,只有 数据包的副本 发送给中断处理程序,而 最初的数据包未受任何阻碍,通过 TCP/IP 协议栈正常传输。


结束语和参考资料

数据包截获机制的总结
机制 模块? 可伸缩? 性能(TCP/IP 吞吐量) 可插入/可删除?
防火墙钩子 是,可以将其作为 LKM 插入 是,可以通过更改 LKM 的源代码并重新编译来增强该性 能 降低大约 50% 	是,使用 insmod 命令
Netfilter 	是,可以作为 LKM 插入它 是,可以通过更改 LKM 的源代码并重新编译来增强该功能 下降大约 50% 	是,使用 insmod 命令
Divert socket 	否,divert socket 数据包必须直接应用到内核代码 冗长乏味,因为整个内核需要编译 太慢而无法度量 否,因为它不是模块
内核改动 否,内核数据包拦截器代码必须直接集成到内核源代码中 冗长乏味,因为整个内核需要编译 通常快于 LKM 方法(如果正确实现) 是,如果将 Makefile 用于安装和卸载

防火墙钩子和 netfilter 是模块化的、灵活的和动态加载的(可删除) ,它们只对系统的性能产生适度的影响。

对于预计流量很大且实时处理时有硬性限制的应用程序而言,最适合使用内核改动方法。

如果数据包处理没有计时问题,则可以使用 Divert socketDivert socket 在用户空间中是一种分析和控制网络流量的非常有用的方法。

回页首

反馈

请让我们知道本教程是否对您有帮助,以及我们如何才能做得更好。我们 还希望了解您想要阅读的其他教程主题。

如果对本教程的内容有疑问,请通过 achauras@in.ibm.com 与作者 Ashish Chaurasia 联系。


参考资料

Linux Device Drivers, 2nd Edition ,作者:Alessandro Rubini Jonathan CorbetO'Reilly & Associates2001),该书讨论了设备驱动程序编程;还讨论了 使用 Makefiles 来解决版本问题(这已在 Linux 可加载的内核模块(LKM)概述 中讨论了)。

Linux Kernel Internals ,作者:Michael BeckHarold BohmeUlrich KunitzRobert MagnusMirko Dziadzka Dirk VerwornerACM1996),该书阐述了 Linux 的内部机制,内容包括从进程调度到内存管理和文件系统,还讨论了内核本身。

Di vert Sockets mini-HOWTO,作者:Ilia Baldine2000 2 月),给出了这种数据包截获方法的大量信息。

有关 Netfilter 的更多信息,请 参阅 netfilter Web site Netfilter summary of information(作者:V.R. Sundar Karthik Dantu)。另请参阅 Linux netfilter Hacking HOWTO。

对于较新的内核,则请参考 “Linux 2.4 Packet Filtering HOWTO”,即 Rusty's Remarkably Unreliable Guides 之一(其他包括 Networking Concepts HOWTOLinux 2.4 NAT HOWTO 和 上面列出的 Netfilter Hacking HOWTO)。不过要注意,它们比系列名称所暗示的那样更可靠。

“Linux iptables HOWTO”介绍 如何使用 iptable 来过滤出 Linux 内核 2.3.15 和更高版本的损坏数据包。Linux iptables HOWTO: using iptables 也很有用。

Linux 2.4 Advanced Routing HOWTO 介绍了 iproute2 的使用――需要隧道时,选择它就很好。

    了解在 AIX 上如何将 IPSec 用作数据包过滤器来阻止未授权的用户。
    介绍 TCP/IP 并了解如何使用 Red Hat Linux 来设置 LANNetwork Address Monitoring and Messaging API Java API,用于监视接口地址并以编程方式对其更改进行响应。

Guide to IP Layer Network Administration with Linux 中的 Links to Documentation 一节很精彩,介绍从一般联网到 iproute2netfilteripchains 以及更多内容。它们的 Links to Software 也非常精彩。

Phrack 杂志介绍了从安全问题到攻击无线广播和世界新闻等主题,以及有关 Linux 内核和内核模块的许多很精采的文章。

诗句 “If a packet hits a pocket on a socket on a port” 摘自 A Grandchild's Guide to Using Grandpa's Computer。

有关 LKM 的更多信息,请参阅论文 “The Linux Kernel Module Programming Guide”Peter Jay Salzman Ori Pomerantz2001) 和 “Linux Loadable Kernel Module HOWTO”Bryan Henderson2004)。

Fairly Fast Packet Filter (FFPF) 最大限度减少了数据包复制,准备用于替代 netfilterLinux Device Drivers, 2nd Edition 作者:Alessandro Rubini & Jonathan CorbetO'Reilly & Associates2001) 可在 O'Reilly xml.com 上在线获得。本书的所有章节都很有用;特别 是 Chapter 9: Interrupt Handling 更是如此。

Linux 开发人员可以在 developerWorks Linux 专区 获得更多资源。

在 Developer Bookstore Linux 区,可以找到很多有关 Linux 的书籍。

关于作者

Ashish Chaurasia 是一位计算机科学工程师,目前在 IBM India 致力于存储区域网络(Storage Area NetworkSAN)文件系统的研究。最近,他完成了一个虚拟专用网(VPN)项目,在此期间,他研究和搜集了一些资源,这些资源最后汇集成本教程。可以通过 achauras@in.ibm.com 与他联系。

转载自http://www.ibm.com/developerworks/cn/education/linux/l-packet/index.html的系列文章