Пакетная обработка в крючках NetFilter? - PullRequest
3 голосов
/ 23 ноября 2011

Поиск информации о NF_STOLEN.

После кражи пакета из NET-FILTER; я добавляю заголовок IP, расширяя SKUBUFFER. После этого; хочу отправить пакет в соответствующий интерфейс. Какую функцию мы должны использовать, чтобы сделать этот шаг ??? ИЛИ если мы скажем; NF_ACCEPT., Можем ли мы гарантировать, что обработанный пакет будет обработан ядром правильно, перенаправив его на правильный интерфейс ??

Жду ответа !!!

-Спасибо заранее, VKS

1 Ответ

4 голосов
/ 24 ноября 2011

Да, если вы измените структуру skbuff и вычислите соответствующие контрольные суммы, вам просто нужно вернуть NF_ACCEPT. Ядро за вас разберется.

Я сделал это в своей диссертации. Вот некоторый код, который я сделал (он не расширяет и не урезает skbuff, но меняет поле в полезной нагрузке приложения. Однако я также сделал некоторый код, расширяющий skbuff, и теория та же): *

unsigned int pre_routing_hook(filter_specs* sp, unsigned int hooknum,
                              struct sk_buff* skb, const struct net_device* in,
                              const struct net_device *out, 
                              int(*okfn)(struct sk_buff*)) {
    struct iphdr* iph;
    struct udphdr* udp;
    __tp(pdu)* pdu;

    /*Omitted some sanity checks */

    iph = ip_hdr(skb);
    udp = (struct udphdr*) (((char*) iph) + (iph->ihl << 2));

    //I didn't care about udp checksum so I've stored zero in this field.
    udp->check = 0;

    switch (iph->protocol) {
    case IPPROTO_UDP:
          pdu = (__tp(pdu)*) (((char*) iph) + (iph->ihl << 2)
                               + sizeof(struct udphdr));

          swap_pdu_byte_order(pdu);

          pdu->timestamp = get_kernel_current_time() - 
                           (pdu->timestamp + pdu->rtt * 1000); 

          swap_pdu_byte_order(pdu);
          break;
    default:
            printk("\tProtocol not supported.\n");
    }
    return NF_ACCEPT;
}

РЕДАКТИРОВАТЬ : Я посмотрел на код, который вы опубликовали, и вот что я придумал. У меня это работает:

#include <linux/ip.h>
#include <linux/in.h>


static uint16_t csum(uint16_t* buff, int nwords) {
    uint32_t sum;
    for (sum = 0; nwords > 0; nwords--)
            sum += *buff++;
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);

    return ((uint16_t) ~sum);
}

//I'm assuming this will run in PRE_ROUTING                                                                                                  
unsigned int main_hook(unsigned int hooknum,
            struct sk_buff *skb, const struct net_device *in,
                   const struct net_device *out, int(*okfn)(struct sk_buff*)) {
  uint16_t lets_keep_the_original_size;
  struct in_device* ipa;

  iph = ip_hdr(sock_buff);

  lets_keep_the_original_size = ntohs(iph->tot_len);

  if(iph->protocol == 1) {
    if(skb_headroom(skb) < sizeof(struct iphdr)) {
      if( 0 != pskb_expand_head(skb, (sizeof(struct iphdr))- 
                                skb_headroom(skb),0,GFP_ATOMIC) ){
        kfree_skb(skb);
        return NF_STOLEN;
    }
  }

  iph = (struct iphdr*) skb_push(skb, sizeof(struct iphdr)); 
  iph->proto = IPPROTO_IP;
  iph->ihl = 5;
  iph->version = 4;
  iph->tos = 0;
  iph->tot_len = htons(lets_keep_the_original_size + sizeof(struct iphdr));
  iph->id = 0;
  iph->frag_off = 0;
  iph->ttl = 60;

  //This must be zero to be able to calculate it with csum above.                                                                          
  iph->check = 0;
  //in is the interface where the packet arrived, provided by netfilters. 
  //In PRE_ROUTING there is no out interface yet so you'll need to add 
  //the ip manually:                                                                                                                          
  ipa = (struct in_device*) in->ip_ptr;
  iph->saddr = ipa->ifa_list->ifa_address;

  //in_aton already gives you the address in network byte order .                                                                          
  //You can just add an integer, but I've chosen to use in_aton                                                                            
  //so the code is more readable                                                                                                           
  iph->daddr = in_aton("192.168.1.1");

  //Here is the important part.                                                                                                            
  iph->check = csum((uint16_t*) iph, (iph->ihl << 1));

  //Let the kernel deal with the rest for us.                                                                                              
  return NF_ACCEPT;
 }
 return NF_ACCEPT;
}

Дайте мне знать, если я могу вам чем-то помочь.

...