얼마 전 Ashwin Kashyap (http://www.research.rutgers.edu/~ashwink/misc_projs/ebt_vnat.html)의 vnat 모듈을 기반으로 ebtables 모듈을 구현했습니다. 모듈은 vlan 태그를 제거하고 vlan id를 nf 표시로두기 위해 broute 테이블의 BROUTING 체인에서 사용할 수 있습니다. 또한 모듈은 NAT 테이블의 POSTROUTING 체인에 nf 표시 값을 기반으로 VLAN 태그를 추가 할 수 있습니다. 모듈은 브리지 된 트래픽에 대한 작업에 아무런 문제가 없습니다. 시스템은 견고하고 안정적입니다. tproxy 차단을 믹스에 추가하자 마자 문제가 시작됩니다. 이 작업으로 인해 커널 패닉이 발생합니다. 필자는 트래픽 스트림이 몇 분만 지나면 첫 번째 패킷 이후에 커널 패닉이 발생하지 않는다는 사실을 강조합니다. SKB를 망가 뜨리는 방식이 L3 + 처리를 위해 충분히 깨끗하지 않은 것 같습니다. BTW 2.6.32 커널에서 일하고 있습니다. 아래 의견 모듈의 중요한 부분을 찾아주세요 :맞춤 ebtables 모듈 && skb 조작 && 커널 패닉
이// 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 비트이기 때문에). 감사!