3

我的任务是为 Linux 内核编写一个 IPv4-IPv6 转换器 ( RFC 6146 )。简而言之,它是一个介于 IPv4 和 IPv6 网络之间的网关,并通过交换数据包头和掩码地址来实现它们之间的透明通信。

看到内核有 Netfilter,一个用于更改数据包的框架,我原本以为我可以编写一个 Netfilter 模块并从那里进行翻译。我可以拦截所有数据包,使用通常的 skb_pull/skb_push 操作调整它们的大小,覆盖一些字节,最后愉快地将它们返回给内核。

事实证明,切换协议对于 Netfilter 来说过于极端了。因为处理 IPv4 数据包的代码完全独立于处理 IPv6 数据包的代码,所以 Netfilter 模块之前和之后的代码都假定网络协议的标头仍然存在。因此,如果我将 IPv4 标头更改为 IPv6 标头,内核会发疯,因为它会继续读取标头,就好像它是 IPv4 标头一样。

(或者至少,这是我在阅读 net/ipv4/ip_input.c 后所相信的;在调用 NF_HOOK 之后内核做的第一件事就是在 ip_rcv_finish() 期间提取 IPv4 标头。)

我看到了第二种选择:从头开始推导出一个新的 sk_buff,让 Netfilter NF_DROP 原始数据包,然后以某种方式发送新数据包。

这就是我对内核原理和风格的有限熟悉使我停滞不前的地方:我想尽量减少对我的解决方案的皱眉,但是替换整个数据包而不是更改其标头似乎不自然、无效率,甚至是对 Netfilter 设计的亵渎。但我不能确定,我希望有经验的建议。另外,我认为没有其他选择。

问题:还有其他选择吗?最自然的方法是什么?

我想支持自 2.6 以来的所有内核版本。如果那是不可能的,那么更新更好。

4

1 回答 1

1

我曾经写过一个 ebtables 目标,该工作是用 VLAN 标记标记以太网帧。这需要在帧数据之前移动和更改以太网报头。所以它在做类似的事情,但在较低级别。skb 可以在开始时就地放大(至少大部分时间,我猜)所以性能应该没问题。

直接链接:http: //goo.gl/3DPEB

它是“008-ebt-vlan_t-0.1.diff.bz2”,位于:

http://goo.gl/S1tVv

请注意,我已经超过 4 年没有关心此代码,并且从那时起我就没有使用 Linux 网络代码。与此同时,AFAIK 已将 Ebtables 合并到 netfilter 中。但我认为基本方法应该仍然有效并且可以帮助你。

于 2012-10-10T17:43:57.560 回答