netfilter-like内核模块获取源和目标地址

sch*_*acs 1 linux kernel-module linux-kernel

我阅读本指南来编写内核模块来进行简单的网络过滤.

首先,我不知道这意味着什么,以及入站和出站数据包(通过传输层)之间的区别是什么?

当数据包从线路进入时,它会从物理层,数据链路层,网络层向上传播,因此它可能无法通过netfilter中定义的功能来使skb_transport_header工作.

其次,我讨厌幻数,我想20用linux内核的实用程序(源文件)中的任何函数替换(典型IP头的长度).

任何帮助将不胜感激.

Sam*_*nko 6

这篇文章现在有点过时了.您不理解的文本仅适用于3.11以下的内核版本.

对于新内核(> = 3.11)

如果您确定您的代码仅用于内核> = 3.11,则可以对输入输出数据包使用下一个代码:

udp_header = (struct udphdr *)skb_transport_header(skb);  
Run Code Online (Sandbox Code Playgroud)

或者更优雅:

udp_header = udp_hdr(skb);
Run Code Online (Sandbox Code Playgroud)

这是因为已经在ip_rcv()中为您设置了传输头:

skb->transport_header = skb->network_header + iph->ihl*4;
Run Code Online (Sandbox Code Playgroud)

此更改是由此提交引起的.

对于旧内核(<3.11)

传出包(NF_INET_POST_ROUTING)

在这种情况下,.transport_header字段正确设置sk_buffer,因此它指向实际的传输层标头(UDP/TCP).所以你可以使用这样的代码:

udp_header = (struct udphdr *)skb_transport_header(skb);  
Run Code Online (Sandbox Code Playgroud)

或更好看(但实际上相同):

udp_header = udp_hdr(skb);  
Run Code Online (Sandbox Code Playgroud)

传入数据包(NF_INET_PRE_ROUTING)

这是棘手的部分.

在这种情况下,.transport_header字段未设置为结构中的实际传输层标头(UDP或TCP)sk_buffer(您在netfilter挂钩函数中获得).相反,.transport_header指向IP标头(即网络层标头).

所以你需要自己计算传输头的地址.为此,您需要跳过IP标头(即将IP标头长度添加到您的.transport_header地址).这就是为什么你可以看到文章中的下一个代码:

udp_header = (struct udphdr *)(skb_transport_header(skb) + 20);
Run Code Online (Sandbox Code Playgroud)

所以20这里只是IP头的长度.

以这种方式可以做得更优雅:

struct iphdr *iph;
struct udphdr *udph;

iph = ip_hdr(skb);

/* If transport header is not set for this kernel version */
if (skb_transport_header(skb) == (unsigned char *)iph)
    udph = (unsigned char *)iph + (iph->ihl * 4); /* skip IP header */
else
    udph = udp_hdr(skb);
Run Code Online (Sandbox Code Playgroud)

在这段代码中,我们使用实际的IP头大小(iph->ihl * 4以字节为单位)而不是幻数20.

本文中的另一个神奇数字17在下一个代码中:

if (ip_header->protocol == 17) {
Run Code Online (Sandbox Code Playgroud)

在此代码中,您应该使用IPPROTO_UDP而不是17:

#include <linux/udp.h>

if (ip_header->protocol == IPPROTO_UDP) {
Run Code Online (Sandbox Code Playgroud)

Netfilter输入/输出包解释

如果您需要一些关于netfilter中传入和传出数据包之间差异的参考,请参见下图.

netfilter的钩

细节:

[1]:来自GitHub的一些有用的代码

[2]:Rami Rosen撰写的"Linux内核网络:实现与理论"

[3]:这个答案也许有用