netfilter-like内核模块获取源地址和目的地址
netfilter-like kernel module to get source and destination address
我阅读 this guide 编写内核模块来进行简单的网络过滤。
首先,我不知道下面的文字是什么意思,入站和出站数据包(按传输层)有什么区别?
When a packet goes in from wire, it travels from physical layer, data
link layer, network layer upwards, therefore it might not go through
the functions defined in netfilter for skb_transport_header to work.
其次,我讨厌幻数,我想用 linux 内核实用程序中的任何函数替换 20
(典型 IP 的长度 header)(source file).
任何帮助将不胜感激。
这篇文章现在有点过时了。看不懂的文字只适用于3.11以下内核版本
对于新内核 (>= 3.11)
如果您确定您的代码将仅用于 >= 3.11 的内核,您可以将下一个代码用于 input 和 output 数据包:
udp_header = (struct udphdr *)skb_transport_header(skb);
或更优雅:
udp_header = udp_hdr(skb);
这是因为 运输 header 已经在 ip_rcv():
中为您设置好了
skb->transport_header = skb->network_header + iph->ihl*4;
此更改由 this commit 带来。
对于旧内核 (< 3.11)
传出数据包(NF_INET_POST_ROUTING
)
在本例中 .transport_header
字段在 sk_buffer
中正确设置,因此它指向实际的 传输层 header (UDP/TCP).所以你可以使用这样的代码:
udp_header = (struct udphdr *)skb_transport_header(skb);
或更好看(但实际上相同):
udp_header = udp_hdr(skb);
传入数据包(NF_INET_PRE_ROUTING
)
这是棘手的部分。
在这种情况下,.transport_header
字段未设置为 sk_buffer
结构中的实际 传输层 header(UDP 或 TCP) (你在你的 netfilter 钩子函数中得到)。相反,.transport_header
指向 IP header(即 网络层 header)。
所以你需要自己计算传输header的地址。为此,您需要跳过 IP header(即将 IP header 长度添加到您的 .transport_header
地址)。这就是为什么你可以在文章中看到下一个代码:
udp_header = (struct udphdr *)(skb_transport_header(skb) + 20);
所以20
这里只是IP的长度header.
可以这样做更优雅:
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);
在此代码中,我们使用实际 IP header 大小(即 iph->ihl * 4
,以字节为单位)而不是幻数 20
。
文章中的另一个神奇数字是 17
在下一个代码中:
if (ip_header->protocol == 17) {
在这段代码中你应该使用 IPPROTO_UDP
而不是 17
:
#include <linux/udp.h>
if (ip_header->protocol == IPPROTO_UDP) {
Netfilter input/output 数据包解释
如果您需要一些关于 netfilter 中传入和传出数据包之间差异的参考,请参见下图。
详情:
[1]: Some useful code from GitHub
[2]: "Linux Kernel Networking: Implementation and Theory" by Rami Rosen
我阅读 this guide 编写内核模块来进行简单的网络过滤。
首先,我不知道下面的文字是什么意思,入站和出站数据包(按传输层)有什么区别?
When a packet goes in from wire, it travels from physical layer, data link layer, network layer upwards, therefore it might not go through the functions defined in netfilter for skb_transport_header to work.
其次,我讨厌幻数,我想用 linux 内核实用程序中的任何函数替换 20
(典型 IP 的长度 header)(source file).
任何帮助将不胜感激。
这篇文章现在有点过时了。看不懂的文字只适用于3.11以下内核版本
对于新内核 (>= 3.11)
如果您确定您的代码将仅用于 >= 3.11 的内核,您可以将下一个代码用于 input 和 output 数据包:
udp_header = (struct udphdr *)skb_transport_header(skb);
或更优雅:
udp_header = udp_hdr(skb);
这是因为 运输 header 已经在 ip_rcv():
中为您设置好了skb->transport_header = skb->network_header + iph->ihl*4;
此更改由 this commit 带来。
对于旧内核 (< 3.11)
传出数据包(NF_INET_POST_ROUTING
)
在本例中 .transport_header
字段在 sk_buffer
中正确设置,因此它指向实际的 传输层 header (UDP/TCP).所以你可以使用这样的代码:
udp_header = (struct udphdr *)skb_transport_header(skb);
或更好看(但实际上相同):
udp_header = udp_hdr(skb);
传入数据包(NF_INET_PRE_ROUTING
)
这是棘手的部分。
在这种情况下,.transport_header
字段未设置为 sk_buffer
结构中的实际 传输层 header(UDP 或 TCP) (你在你的 netfilter 钩子函数中得到)。相反,.transport_header
指向 IP header(即 网络层 header)。
所以你需要自己计算传输header的地址。为此,您需要跳过 IP header(即将 IP header 长度添加到您的 .transport_header
地址)。这就是为什么你可以在文章中看到下一个代码:
udp_header = (struct udphdr *)(skb_transport_header(skb) + 20);
所以20
这里只是IP的长度header.
可以这样做更优雅:
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);
在此代码中,我们使用实际 IP header 大小(即 iph->ihl * 4
,以字节为单位)而不是幻数 20
。
文章中的另一个神奇数字是 17
在下一个代码中:
if (ip_header->protocol == 17) {
在这段代码中你应该使用 IPPROTO_UDP
而不是 17
:
#include <linux/udp.h>
if (ip_header->protocol == IPPROTO_UDP) {
Netfilter input/output 数据包解释
如果您需要一些关于 netfilter 中传入和传出数据包之间差异的参考,请参见下图。
详情:
[1]: Some useful code from GitHub
[2]: "Linux Kernel Networking: Implementation and Theory" by Rami Rosen