开始之前
目前,信息要通过管道(也就是网络)传输,需要花很多时间封装在数据包中。在本教程 中,我们将在这些数据包传输过程中捕获它们,捕获数据包所采用的平台是 Linux。
大多数网络应用程序――从虚拟专用网(VPN)到路由程序,再到嗅探器――都具有某种 数据包捕获机制。因此,编写此类软件的任何人都可以从本教程中受益。
由于我们将要研究的几种数据包过滤机制都是内核模块,所以还将简要地介绍这些模块以 及内核编译。
我们还将回顾一些我没有成功使用的机制:我只能获得数据包的一个副本而无法截获最初 的数据包。这里的讨论不仅能省去您重复我所做工作的麻烦,而且还对编写网络应用程序(如嗅探器) 很有用。
除大致熟悉不同的数据包捕获机制(如防火墙钩子、divert socket 和 netfilter)外; 读者还应具备有关 Linux 网络和 TCP/IP 协议栈方面的知识。开始之前最好了解一些源代 码的知识。
本教程最适合那些以前在系统编程、Linux 网络和 Linux 内核模块方面 至少有一些经验的读者。但是,本教程尽可能简单地给出一些概念,并在适当的时候给 予详细解释,因此,即使读者缺少一种或多种这方面的知识,也能从本文的讨论中获益。
简介
TCP/IP 协议栈是 Linux 网络的重要支柱,其体系结构设计得非常优美。数据包 是 TCP/IP 协议栈 中信息流的载体。在 Linux 网络编程中,许多有意义的工作都包括了捕获这些信息丰富的数据包、提取或操作这些数据包所包含的信息。
数据包捕获 对我们而言意味着某种机制,即获取一个数据包,直到达到所要求的目 的后才将其释放,以便该数据包能够按照常规路径通过其余的任何处理。其他相同或相似 操作的术语有 数据包过滤、数据包嗅探、网络嗅探 以及 数据包 或 网络监视。
数据包过滤是许多网络软件的基础,这些软件有网络监视工具、VPN、网络分析程序、路由 程序、入侵监测系统(Intrusion Detection Systems,IDS)和嗅探器。
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 可使内核变得轻便、模块化、灵活和可伸缩。
编写 Linux 内核模块的体系结构如下:
-
init_module
这个 LKM 初始化函数是强制执行的。当 LKM 加载到内核时触发该函数,因此 所有初始化工作都是在这个函数中完成的。 - 处理特定的函数
这些函数执行实际的工作,如读、写、打开、关闭设备,等等。 -
cleanup_module
当从内核中删除 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 编程的更多信息。
一旦模块加载到内核中,它将开始执行预定的功能。使用命令 lsmod
可 以看到当前所有加载的 LKM 的列表。
可以使用 rmmod <module_name>
从内核中加载或删除模块。
编译内核
本教程讨论的许多机制都要求设置某些内核选项,然后重新编译内核。因此在开始前,我 们将复习内核编译的步骤。如果您已经了解内核编译,则可以跳至下一 节 数据包截获:防火墙钩子 ,在那里开始复习数据包捕获机制。
重新编译内核:
-
make xconfig
允许设置不同的内核选项。(也可以使用make menuconfig
或make config
;这只是个人偏好问题。) -
make dep
解决内核编译的文件依赖性。 -
make bzImage
编译(make)内核映像并将其存储在 vmlinuz 中。 -
make install
将 vmlinuz 复制到 /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; /*Pointer to the next firewall hook structure */ int fw_pf; /* Protocol family */ int fw_priority; /* Priority of chosen firewalls */ |
现在,防火墙结构与下面的代码类似:
/* Filling the firewall_ops structure */ static struct firewall_ops myOps = {NULL, fw_forward, fw_input, fw_output, PF_INET, /* Protocol family */ 1 /* Priority of chosen firewalls*/ }; |
现在,您需要将 firewall_ops 结构注册到内核:
register_firewall(protocol family, struct firewall_ops *); |
在 LKM 的 init_module
代码中进行注册。
当卸载 LKM 时,cleanup_module
函数应包含
unregister_firewall(protocol family, struct firewall_ops *); |
对 LKM 进行编码、编译并加载到内核后,您的数据包拦截器就准备工作了。
完成在接下来的两屏中给出的这个 LKM 的源代码和使用说明。
/* This is an insertable module that uses the firewall hooks mechanism on 2.2.16 to intercept a packet */ /* gcc -O -c NetFWHook.c -I/usr/src/linux/include*/ /* No one can then telnet,ftp,ping your machine */ /*NetFWHook.c*/ #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("\n\tfw_forward)() called..."); printk("\n\t\tThe source of this packet is: %s",in_ntoa(hdr->saddr)); return FW_ACCEPT; } /*Function for incoming packets*/ 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("\n\tfw_input() called..."); printk("\n\t\tThe source of this packet is: %s",in_ntoa(iph->saddr)); return FW_ACCEPT; } /*Function for outgoing packets*/ 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("\n\tfw_output)() called..."); printk("\n\tThis packet is destined for: %s",in_ntoa(iph->daddr)); return FW_ACCEPT; } /*Filling the firewall_ops structure*/ static struct firewall_ops myOps = {NULL,fw_forward,fw_input,fw_output,PF_INE int fw_pf; /* Protocol family*/,int fw_priority; /* Priority of chosen firewalls */T,1}; /*First function to be called at the time of loading of module*/ int init_module(void) { /*registering the firewall_ops structure*/ if(register_firewall(PF_INET,&myOps) < 0) { printk("\n\n\tERROR...firewall main aag lag gayee!!!"); return -1; } else { printk("\n\n\tFirewall registered"); } return 0; } /*Function that is called when the module is unloaded*/ void cleanup_module(void) { /*Unregistering the firewall_ops structure*/ if(unregister_firewall(PF_INET,&myOps)<0) { printk("\n\n\tError....Firewall can't be unregistered"); } else { printk("\n\n\tFirewall 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 可以在通过 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_OUT
、NF_IP_LOCAL_IN
、NF_IP_ FORWARD
等。 -
**pskb
指向 TCP/IP 协议栈中数据包容器的指针;例如 sk_buff。 -
*indev & *outdev
指向流入和流出网络设备的设备结构的指针。在内核中注册的每种设备(例如,以太网卡)都 有一个由 IRQ、IO 地址等组成的设备结构。当机器只有一个网络接口来处理流入和流 出流量时,这两个结构是相同的。当流入和流出的流量由两种设备处理时,这两种结构是 不同的。 -
(*okfn) (struct sk_buff *)
在激活钩子时调用该函数。
核心 netfilter 结构在 /usr/src/include/linux/netfilter.h 中定义,类似如下:
struct nf_hook_ops { struct list_head list; /* User fills in from here down. */ nf_hookfn *hook; int pf; int hooknum; /* Hooks are ordered in ascending priority. */ int priority; }; |
参数是:
-
list
Netfilter 本身是一个钩子链;它指向 netfilter 钩子的头部,通常设置为{ NULL, NULL }
。 -
hook
该函数在数据包碰到钩子点时被调用。该函数与前面描述的函数相同,它必须返回NF_ACCEPT
、NF_DROP
或NF_QUEUE
。如 果返回NF_ACCEPT
,则下一个钩子将被附加到将要调用的点。如 果返回NF_DROP
,则数据包被丢弃。如果返回NF_QUEUE
,则对数据包 进行排队。sk_buff 指针被传递到该函数中,并用数据包信息如 IP 报头、TCP 报头等进 行填充。您可以使用 sk_buff 结构指针来操作或删除数据包(要删除数据包,只需将 skb 指 针设置为空即可)。 -
pf
协议簇;例如,适用于 IPv4 的PF_INET
。 -
hooknum
您感兴趣的钩子号;例如NF_IP_LOCAL_IN
等。
在 LKM 的 init_module
函数中,需要注册在内核中填充的结构:
int nf_register_hook(struct nf_hook_ops *req); |
这里,nf_hook_ops 是 netfilter 操作结构。
一旦该结构注册到内核中,Linux 将调用这里定义的函数来处理数据包。
卸载 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 socket。 - IP:divert pass-through
如果已设置了该选项并且没有应用程序正在监听 divert socket 端口,则该数据包不转 移,只按照正常的路径传输。 - IP:always defragment
如果设置该选项,则整理内核中的所有碎片,这会严重降低性能。
ipchains 控制网络数据包传输的路径。要将 ipchains 与 divert socket 一起使用, 应下载、编译和安装打了补丁的 ipchains 版本 ipchains-1.3.9。
在下一屏对 ipchains 进行一般性介绍。
- Input chain
允许所有流入的数据包(目的地是主机的数据包和转发的数据包)穿过。 - Output chain
允许所有流出的数据包(源自主机的数据包和转发的数据包)穿过。 - Forward chain
只允许转发的数据包穿过。
转发的数据包按以下顺序穿过链:
- 输入
- 转发
- 输出
数据包截获:内核改动
在此,我们将操作内核源代码以扩展内核本地数据包截获能力。
内核源文件位于 /usr/src/linux,要修改的两个主要文件 是 ip_input.c 和 ip_output。这两个文件位于 /usr/src/linux/net/ipv4/ 目录中。
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 一样,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 动态修改内核源代码;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 socket。Divert socket 在用户空间中是一种分 析和控制网络流量的非常有用的方法。
请让我们知道本教程是否对您有帮助,以及我们如何才能做得更好。我们 还希望了解您想要阅读的其他教程主题。
如果对本教程的内容有疑问,请通过 achauras@in.ibm.com 与作者 Ashish Chaurasia 联系。
-
Linux Device Drivers, 2nd Edition ,作者:Alessandro Rubini 和 Jonathan Corbet(O'Reilly & Associates,2001),该书讨论了设备驱动程序编程;还讨论了 使用 Makefiles 来解决版本问题(这已在 Linux 可加载的内核模块(LKM)概述 中讨论了)。
Linux Kernel Internals ,作者:Michael Beck、Harold Bohme、Ulrich Kunitz、Robert Magnus、Mirko Dziadzka 和 Dirk Verworner(ACM,1996),该书阐述了 Linux 的内部机制,内容包括从进程 调度到内存管理和文件系统,还讨论了内核本身。
Di vert Sockets mini-HOWTO,作者:Ilia Baldine(2000 年 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 HOWTO、Linux 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 来设置 LAN。
- Network Address Monitoring and Messaging API 是 Java API,用于监视接口地址并以编程方式对 其更改进行响应。
Guide to IP Layer Network Administration with Linux 中的 Links to Documentation 一节很精彩,介绍从一般联网到 iproute2、netfilter、 ipchains 以及更多内容。它们的 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 Pomerantz,2001) 和 “Linux Loadable Kernel Module HOWTO”(Bryan Henderson,2004)。
Fairly Fast Packet Filter (FFPF) 最大限度减少了数据包复制,准备用于替代 netfilter。
Linux Device Drivers, 2nd Edition 作者:Alessandro Rubini & Jonathan Corbet(O'Reilly & Associates,2001) 可在 O'Reilly 的 xml.com 上在线获得。本书的所有章节都很有用;特别 是 Chapter 9: Interrupt Handling 更是如此。
Linux 开发人员可以在 developerWorks Linux 专区 获得更多资源。
在 Developer Bookstore 的 Linux 区,可以找到很多有关 Linux 的书籍。