<pre class="cjk" style="margin-top:0px; margin-bottom:0px; white-space:pre-wrap; word-wrap:break-word; color:rgb(75,75,75); font-size:13px; line-height:19.5px; background-color:rgb(255,255,255)" name="code">数据包截获:<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US"></span></span><pre class="cjk" style="margin-top:0px; margin-bottom:0px; white-space:pre-wrap; word-wrap:break-word; color:rgb(75,75,75); font-size:13px; line-height:19.5px; background-color:rgb(255,255,255)" name="code"><span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter </span></span>是由内核 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">2.4.x </span></span>和 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">2.6.x </span></span>提供的数据包截获机制,它替代了内核 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">2.2.x </span></span>中 使用的 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">ipchains</span></span>、防火墙钩子和其他方法。<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter </span></span>也可以作为 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">LKM </span></span>获得。
要使用 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter</span></span>,在内核编译时设置 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Packet Filtering </span></span>选项。
可以对采用防火墙钩子机制的同类应用程序使用 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>机制,这些应用程序有:路由程序、数据包嗅探器和其他位于网络边缘并访问通信流的实体。
使用 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter </span></span>可以在通过 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">TCP/IP </span></span>协议栈的路径中的几个定义良好的点上捕获数据包:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_PRE_ROUTING</span></span>
在对数据包进行初始正确性检查(校验和等)后,保存该数据包。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_LOCAL_IN</span></span>
如果数据包将要到达本地主机,则捕获该数据包。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_FORWARD</span></span>
如果数据包将要到达某些其他主机,则捕获该数据包。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_LOCAL_OUT</span></span>
在本地捕获其目的地是外部的已创建的数据包。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_POST_ROUTING</span></span>
这是最后的钩子,在此之后将传输数据包。
当数据包穿过 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">TCP/IP </span></span>协议栈后,协议调用带有数据包和钩子号的 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>框架。钩子也 可以指派优先级。
函数的返回值包括:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_ACCEPT</span></span>
数据包继续在正常的 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">TCP/IP </span></span>路径上传输。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_DROP</span></span>
丢弃数据包;不进一步处理。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_STOLEN</span></span>
已获得数据包;不进一步处理。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_QUEUE</span></span>
对数据包排队(通常用于用户空间处理)。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_REPEAT</span></span>
再次触发这个钩子。
特定于进程的函数
特定于进程的函数(或钩子)的原型如下所示:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">static unsigned int packet_interceptor_hook(unsigned int hook, struct</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">sk_buff **pskb,</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">const struct net_device *indev, const struct net_device *outdev, int</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">(*okfn) (struct sk_buff *))</span></span>
您可以将字段定义为:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">hook</span></span>
您感兴趣的钩子的编号;例如 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_LOCAL_OUT</span></span>、<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_LOCAL_IN</span></span>、<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_ FORWARD </span></span>等。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">**pskb</span></span>
指向 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">TCP/IP </span></span>协议栈中数据包容器的指针;例如 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">sk_buff</span></span>。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">*indev & *outdev</span></span>
指向流入和流出网络设备的设备结构的指针。在内核中注册的每种设备(例如,以太网卡)都 有一个由 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">IRQ</span></span>、<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">IO </span></span>地址等组成的设备结构。当机器只有一个网络接口来处理流入和流出流量时,这两个结构是相同的。当流入和流出的流量由两种设备处理时,这两种结构是 不同的。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">(*okfn) (struct sk_buff *)</span></span>
在激活钩子时调用该函数。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构
<pre class="cjk" style="margin-top:0px; margin-bottom:0px; white-space:pre-wrap; word-wrap:break-word; color:rgb(75,75,75); font-size:13px; line-height:19.5px; background-color:rgb(255,255,255)" name="code">核心 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构在 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">/usr/src/include/linux/netfilter.h </span></span>中定义,类似如下:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">struct nf_hook_ops</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">{</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">struct list_head list;</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">nf_hookfn *hook;</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">int pf;</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">int hooknum;</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">int priority;</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">};</span></span>
<pre class="cjk" style="margin-top:0px; margin-bottom:0px; white-space:pre-wrap; word-wrap:break-word; color:rgb(75,75,75); font-size:13px; line-height:19.5px; background-color:rgb(255,255,255)" name="code">参数是:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">list</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Netfilter </span></span>本身是一个钩子链;它指向 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>钩子的头部,通常设置为 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">{ NULL, NULL }</span></span>。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">hook</span></span>
该函数在数据包碰到钩子点时被调用。该函数与前面描述的函数相同,它必须返回 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_ACCEPT</span></span>、<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_DROP </span></span>或 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_QUEUE</span></span>。如 果返回 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_ACCEPT</span></span>,则下一个钩子将被附加到将要调用的点。如 果返回 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_DROP</span></span>,则数据包被丢弃。如果返回 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_QUEUE</span></span>,则对数据包进行排队。<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">sk_buff </span></span>指针被传递到该函数中,并用数据包信息如 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">IP </span></span>报头、<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">TCP </span></span>报头等进 行填充。您可以使用 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">sk_buff </span></span>结构指针来操作或删除数据包(要删除数据包,只需将 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">skb </span></span>指 针设置为空即可)。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">pf</span></span>
协议簇;例如,适用于 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">IPv4 </span></span>的 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">PF_INET</span></span>。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">hooknum</span></span>
您感兴趣的钩子号;例如 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">NF_IP_LOCAL_IN </span></span>等。
内核注册
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">init_module </span></span>函数中,需要注册在内核中填充的结构:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">int nf_register_hook(struct nf_hook_ops *req);</span></span>
这里,<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">nf_hook_ops </span></span>是 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>操作结构。
一旦该结构注册到内核中,<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Linux </span></span>将调用这里定义的函数来处理数据包。
取消注册 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构需要从内核中取消注册。这一操作在 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">cleanup_module </span></span>函数中完成:
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">void nf_unregister_hook(struct nf_hook_ops *req);</span></span>
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">nf_hook_ops </span></span>也是 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>操作结构。
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">init_module </span></span>函数中,需要注册在内核中填充的结构: <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">int nf_register_hook(struct nf_hook_ops *req);</span></span> 这里,<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">nf_hook_ops </span></span>是 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>操作结构。 一旦该结构注册到内核中,<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">Linux </span></span>将调用这里定义的函数来处理数据包。
取消注册 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构
<span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>结构需要从内核中取消注册。这一操作在 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">cleanup_module </span></span>函数中完成: <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">void nf_unregister_hook(struct nf_hook_ops *req);</span></span> <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">nf_hook_ops </span></span>也是 <span style="font-family:'DejaVu Sans Mono',monospace;line-height:1.5;"><span style="line-height:1.5" lang="en-US">netfilter </span></span>操作结构。