2

我正在编写网络设备驱动程序。
内核 2.6.35.12
设备在连接到网桥端口时应该可以工作。

我试图拦截从网桥转发到接口的 ICMPv6 RA 和 NS 消息(路由器/邻居请求)。
eth <–> br0 <–> mydevice

在设备 start_xmit 函数中,我正在执行以下操作:

检查以太网头后的协议字段是否为 IPV6 (0x86dd)

检查 ipv6 下一个标头是否为 ICMPv6 并检查其类型:

__u8 nexthdr = ipv6_hdr(skb)->nexthdr;
if (nexthdr == htons (IPPROTO_ICMPV6))
{
   struct icmp6hdr *hdr = icmp6_hdr(skb);
   u8 type = hdr->icmp6_type;
   if(type == htons (NDISC_NEIGHBOUR_SOLICITATION) || type == htons (NDISC_ROUTER_SOLICITATION))
       {
        ….Do something here…
       }
   }

当从设备(例如 br0)内部发送 RS/NS 时,我看到代码工作正常。

问题是当流量从另一个端口通过网桥转发时。

我看到 icmp6_hdr(skb) 返回了不正确的标题。
再调试一些,似乎 skb->network_header 和 skb->transport_header 指向同一个地方。

icmp6_hdr 正在使用 transport_header 来解释它为什么不正确。

转储 skb 数据,它看起来所有的标头和有效负载都在正确的偏移量(也将它与 tcpdump 进行比较)

我怀疑它可能与桥代码有关,在深入研究之前,

我想也许有人遇到过类似的事情或有任何其他想法?

4

1 回答 1

0

部分问题在于您假设 Netfilter 所做的不仅仅是找出下一个标头是什么。根据我的经验(虽然不是很长),你想做这样的事情:

struct icmp6hdr *icmp6;
// Obviously don't do this unless you check to make sure that it's the right protocol
struct ipv6_hdr *ip6hdr = (struct ipv6_hdr*)skb->network_header;
// You need to move the headers around
// Notice the memory address of skb->data and skb->network_header are the same
// that means that the IP header hasn't been "pulled"
skb->transport_header = skb_pull(skb, sizeof(struct ipv6_hdr));
if(ntohs(ip6hdr->nexthdr) == IPPROTO_ICMPV6) {
    icmp6 = (struct icmp6hdr*)skb->transport_header;
    // Doing this is more efficient, since you only are calling the
    // Network to Host function once
    __u8 type = ntohs(hdr->icmp6_type);
    switch(type) {
    case NDISC_NEIGHBOUR_SOLICITATION:
    case NDISC_ROUTER_SOLICITATION:
         // Do your stuff
         break;
    }
}

希望这会有所帮助。我刚开始潜心编写 Netfilter 代码,所以我不确定 100%,但是当我尝试使用 IPv4 做类似的事情时,我发现了这一点NF_IP_LOCAL_IN

于 2013-08-12T14:07:15.390 回答