类似 netfilter 的内核模块来获取源地址和目标地址 [英] netfilter-like kernel module to get source and destination address

查看:26
本文介绍了类似 netfilter 的内核模块来获取源地址和目标地址的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了

[2]:"Linux 内核网络:实现和理论"作者:Rami Rosen

[3]:这个答案可能也有用

I read this guide to write a kernel module to do simple network filtering.

First, I have no idea of what below text this means, and what's the difference between inbound and outbound data packet(by transportation layer)?

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.

Second, I hate magic numbers, and I want to replace the 20 (the length of typical IP header) with any function from the linux kernel's utilities(source file).

Any help will be appreciated.

解决方案

This article is a little outdated now. Text that you don't understand is only applicable to kernel versions below 3.11.

For new kernels (>= 3.11)

If you are sure that your code will only be used with kernels >= 3.11, you can use next code for both input and output packets:

udp_header = (struct udphdr *)skb_transport_header(skb);  

Or more elegant:

udp_header = udp_hdr(skb);

It's because transport header is already set up for you in ip_rcv():

skb->transport_header = skb->network_header + iph->ihl*4;

This change was brought by this commit.

For old kernels (< 3.11)

Outgoing packets (NF_INET_POST_ROUTING)

In this case .transport_header field set up correctly in sk_buffer, so it points to actual transport layer header (UDP/TCP). So you can use code like this:

udp_header = (struct udphdr *)skb_transport_header(skb);  

or better looking (but actually the same):

udp_header = udp_hdr(skb);  

Incoming packets (NF_INET_PRE_ROUTING)

This is the tricky part.

In this case the .transport_header field is not set to the actual transport layer header (UDP or TCP) in sk_buffer structure (that you get in your netfilter hook function). Instead, .transport_header points to IP header (which is network layer header).

So you need to calculate address of transport header by your own. To do so you need to skip IP header (i.e. add IP header length to your .transport_header address). That's why you can see next code in the article:

udp_header = (struct udphdr *)(skb_transport_header(skb) + 20);

So 20 here is just the length of IP header.

It can be done more elegant in this way:

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);

In this code we use an actual IP header size (which is iph->ihl * 4, in bytes) instead of magic number 20.

Another magic number in the article is 17 in next code:

if (ip_header->protocol == 17) {

In this code you should use IPPROTO_UDP instead of 17:

#include <linux/udp.h>

if (ip_header->protocol == IPPROTO_UDP) {

Netfilter input/output packets explanation

If you need some reference about difference between incoming and outgoing packets in netfilter, see the picture below.

Details:

[1]: Some useful code from GitHub

[2]: "Linux Kernel Networking: Implementation and Theory" by Rami Rosen

[3]: This answer may be also useful

这篇关于类似 netfilter 的内核模块来获取源地址和目标地址的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆