我的任务是为Linux内核编写一个IPv4-IPv6转换器(RFC 6146)。简而言之,它是一个位于IPv4和IPv6网络之间的网关,通过交换数据包头和掩码地址,允许它们之间的透明通信。
看到内核有Netfilter,一个用于更改数据包的框架,我最初认为我可以只编写一个Netfilter模块并从那里进行转换。我可以截取所有的包,使用通常的skb_pull/skb_push操作调整它们的大小,覆盖一些字节,最后愉快地将它们返回给内核。
事实证明,交换协议对于Netfilter来说太极端了。由于处理IPv4数据包的代码完全独立于处理IPv6数据包的代码,因此Netfilter模块之前和之后的代码都假定网络协议的报头仍然有效。因此,如果我将IPv4标头更改为IPv6标头,内核将会变得疯狂,因为它将继续读取标头,就好像它是IPv4标头一样。
(至少,这是我在阅读net/ IPv4 /ipput.c之后所相信的;在调用NF_HOOK之后,内核做的第一件事就是在ip_rcv_finish()过程中提取IPv4头部。)
我看到了第二种选择:从头推导出一个新的sk_buff,让Netfilter对原始数据包执行NF_DROP操作,然后以某种方式发送新数据包。
这就是我对内核原理和风格的有限熟悉让我停滞不前的地方:我想尽量减少对我的解决方案的不满,但替换整个包而不是更改其报头似乎是不自然的,无效的,甚至是对Netfilter的设计的亵渎。但是我不能肯定,我想要一些有经验的建议。此外,我也看不到其他选择。
问题:还有其他选择吗?最自然的方法是什么?
我希望支持2.6以后的所有内核版本。如果这是不可能的,更新更好。
发布于 2012-10-11 01:43:58
我曾经写过一次ebtables,目标是用VLAN标签标记以太网帧。这需要在帧数据之前移动和改变以太网头。所以它正在做类似的事情,但在较低的级别。skb可以在开始时适当地放大(至少在大多数情况下是这样),所以性能应该是可以的。
直接链接:http://goo.gl/3DPEB
在下面是“008-ebt-vlan_t-0.1.ff.bz2”:
http://goo.gl/S1tVv
请注意,我已经有4年多没有关心过这个代码了,从那时起我就不再使用Linux网络代码了。同时,Ebtables已经被合并到netfilter中,AFAIK。但我认为基本的方法应该仍然有效,并且可以帮助你。
https://stackoverflow.com/questions/12823789
复制相似问题