前段时间我实施了基于vnat模块的ebtables模块,由Ashwin Kashyap(http://www.research.rutgers.edu/~ashwink/misc_projs/ebt_vnat.html)完成。模块可以在broute表中的BROUTING链中使用,用于剥离vlan标记并将vlan id放入nf标记中。模块还允许在nat表的POSTROUTING链中基于nf标记值添加vlan标记。模块在处理桥接流量时没有任何问题。系统坚如磐石。一旦我将tproxy拦截添加到混合中,问题就会开始。这会在一段时间后导致内核崩溃。我强调这样一个事实,即我在第一个数据包之后没有看到内核恐慌,只是在几分钟的tGPxx流量流之后。似乎我破坏SKB的方式对于L3 +处理来说还不够干净。顺便说一句,我正在研究2.6.32内核。请查看模块的关键部分,并在下面添加注释:
// code for adding vlan tag based on skb->mark value
if (!skb_make_writable(skb, 0))
return EBT_DROP;
if(skb->mark > 0){
// maybe we should always seek VLAN_HLEN+ETH_HLEN instead of using condition?
if (skb_headroom(skb) < (skb->mac_len == 0 ? VLAN_HLEN + ETH_HLEN : VLAN_HLEN ) ) {
struct sk_buff *sk_tmp = skb;
skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN );
kfree_skb(sk_tmp);
if (skb == NULL) {
return EBT_DROP;
}
}
// we need 4 more bytes for 802.1q header, so push!...I can almost see the head(er)
skb_push(skb, VLAN_HLEN);
skb->mac_header-=VLAN_HLEN;
skb->network_header-=VLAN_HLEN;
skb->transport_header-=VLAN_HLEN;
veth = (struct vlan_ethhdr *) eth_hdr(skb);
// move dst/src mac addresses (12b of header) 4 bytes back to make room for
// 802.1q header
memmove( skb->head + skb->mac_header, skb->head + skb->mac_header + VLAN_HLEN, 12);
// fill 802.1q header
veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
veth_TCI = skb->mark & 0xfff;
veth->h_vlan_TCI = htons(veth_TCI);
}
// code for stripping vlan tag and putting it into skb->mark value
veth = (struct vlan_ethhdr *)eth_hdr(skb);
if(veth->h_vlan_proto == __constant_htons(ETH_P_8021Q)){
if (!skb_make_writable(skb, 0))
return EBT_DROP;
// determine vlan id
vid=(ntohs(veth->h_vlan_TCI) & 0xfff);
mark = vid;
// copy dst/src mac addresses (12b) 4 bytes fwd, so it covers 802.1q header
memmove(skb->head + skb->mac_header + VLAN_HLEN, skb->head + skb->mac_header, 12);
// adapt header pointers
skb->mac_header+=VLAN_HLEN;
skb->mac_len = ETH_HLEN;
skb->network_header+=VLAN_HLEN;
skb->transport_header+=VLAN_HLEN;
skb->data += VLAN_HLEN;
skb->len -= VLAN_HLEN;
eth = eth_hdr(skb);
skb->protocol=eth->h_proto;
}
skb->mark=mark;
我会感激任何指针(只要它们至少64位长)。谢谢!
答案 0 :(得分:0)
您的代码应该更改MAC标头以添加或删除802.1q标头。现在我可能错了,但为什么你需要将指针转移到网络和传输层头?
我希望MAC头扩展并收缩到skb空间,而其余的数据包在任何一种情况下都保持不变。移动网络和传输标头会导致上层(3+)读取错误的前4个字节。
(NB我会把它写成评论而不是答案,因为我对自己没有信心,但我最近一直致力于为ebtables开发VLAN标签翻译模块这是我第一次为SO做出贡献,所以我的声誉显然不够高。)