Пользовательский модуль ebtables && skb манипулирование && паника ядра

Некоторое время назад я реализовал модуль ebtables на основе модуля vnat Эшвина Кашьяпа ( http://www.research.rutgers.edu/~ashwink/misc_projs/ebt_vnat.html). Модуль может использоваться в цепочке BROUTING в таблице броутера для удаления тегов vlan и помещения идентификатора vlan в метку nf. Модуль также позволяет добавлять теги vlan на основе значения метки nf в цепочке POSTROUTING таблицы nat. Модуль не имеет проблем с работой на мостовом трафике. Система стабильна. Проблема начинается, как только я добавляю перехват tproxy в микс. Это приводит к панике ядра ПОСЛЕ некоторого времени работы. Я подчеркиваю тот факт, что я не вижу паники ядра после первого пакета только после нескольких минут потоков трафика tproxied. Кажется, что способ манипулирования 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 бит). Спасибо!

1 ответ

Ваш код должен изменить заголовок MAC, чтобы добавить или удалить заголовок 802.1q. Теперь я могу ошибаться, но зачем вам смещать указатели на заголовки сетевого и транспортного уровней?

Я ожидал бы, что заголовок MAC расширится и сократится в запасе skb, в то время как остальная часть пакета остается нетронутой в любом случае. Перемещение заголовков сети и транспорта приводит к тому, что верхние уровни (3+) читают неправильные первые 4 байта.

(Примечание: я бы написал это как комментарий, а не как ответ, так как не уверен, что прав, но недавно я работал над модулем перевода тегов VLAN для ebtables, и я впервые помог ТАК, поэтому моя репутация явно не достаточно высока).

Другие вопросы по тегам