【问题标题】:Packet Processing in NetFilter Hooks ?NetFilter Hooks 中的数据包处理?
【发布时间】:2016-06-01 01:52:31
【问题描述】:

寻找关于 NF_STOLEN 的信息。

从 NET-FILTER 窃取数据包后;我通过扩展 SKUBUFFER 添加 IP 标头。在那之后;要将数据包发送到相应的接口。我们应该使用什么功能来执行此步骤???或者,如果我们说; NF_ACCEPT.,我们能否确保 Manipulated Packet 将被内核正确处理并转发到正确的接口??

期待回复!!!

-提前致谢, VKS

【问题讨论】:

    标签: linux-kernel kernel


    【解决方案1】:

    是的,如果您更改 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;
    }
    

    如果有什么可以帮助您的,请告诉我。

    【讨论】:

    • 感谢 Fred 的坚定答复。寻求您的更多澄清。我到底想做的是;获取 ICMP 数据包并尝试在其上添加额外的 20 字节 IP 标头并希望将数据包转发到相应的输出接口 [类似于 IpinIp 隧道的东西]。这里很少查询! 1] 如果我在现有套接字缓冲区上添加一个新的 IP 标头,其中包含所有字段;内核堆栈将查看的目标 IP 地址是什么?它是否具有查找新 IP 并做出决定的逻辑,还是我的工作是窃取数据包并转发到正确的 iface ?
    • 嗯,这是个好问题。我不确定,但我认为这取决于你的钩子在哪里。看看这个meghadoot.sourceforge.net/files/megh_doc/netfilterArch.png - 我认为如果你的钩子在local in 中,路由仍然没有发生,你不需要担心什么。另一方面,在post-routing 路由已经发生。在这种情况下,您可以尝试 ip_route_me_hard(skb) 之类的方法 - 抱歉不记得函数名称,即使我记得我也不确定它在 netfilters 中是否合法。
    • 是的。这是一个很好的答案。忘记了基础知识:)。我正在使用 PRE_ROUTING Hook。所以;在我形成新数据包之后,似乎内核没有做出路由决定;希望它会寻找新添加的 Header & Take Decision.well;让我稍后尝试和更新。再次感谢。
    • 好的。我认为 ;如果我们更改应用层并返回 NF_ACCEPT;内核会处理所有事情。但就我而言;通过在 PRE_ROUTING 获取 ICMP 数据包添加新 IP 标头后,内核不处理钩子。我认为;需要偷走它并路由我自己。这有意义吗??
    • 其实你不应该做那样的事情。你能把你已经得到的代码发给我吗?我可以帮你解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 2018-08-18
    • 2020-03-14
    相关资源
    最近更新 更多