2013-04-10 115 views
0

我想捕獲NF_IP_LOCAL_OUT鉤子中的數據包,並稍微修改它們。之後,我使用dev_queue_xmit()發送數據包。不幸的是,雖然函數返回0,但數據包不能成功發出。我可以知道如何解決這個問題嗎?謝謝!無法通過dev_queue_xmit發送數據包()

static struct nf_hook_ops modify_ops; 

static unsigned int modify(unsigned int hooknum, struct sk_buff * skb, const struct net_device * in, const struct net_device * out, int (*okfn)(struct sk_buff *)) 
{ 

     struct sk_buff* nskb; 
     struct iphdr* nip_hdr; 
     unsigned int nip_hdr_off; 
     struct icmphdr *icmph = NULL; 
     int ret = 0; 
     struct net *net = NULL; 

     nskb = skb_copy(skb, GFP_ATOMIC); 
     if(nskb == NULL) 
     { 
       printk("%s\n", "skb_copy return NULL"); 
       return NF_ACCEPT; 
     } 


     if(ip_hdr(nskb)->protocol != IPPROTO_ICMP) 
     { 
       kfree_skb(nskb); 
       return NF_ACCEPT; 
     } 

     nip_hdr = ip_hdr(nskb); //nip_hdr = nskb->nh.iph; 
     nip_hdr_off = nip_hdr->ihl << 2; 

     nip_hdr->daddr = in_aton("192.168.1.1"); 
     nip_hdr->check = 0; 
     nip_hdr->check = ip_fast_csum((unsigned char *)nip_hdr, nip_hdr->ihl); 
     icmph = icmp_hdr(nskb); 
     icmph->checksum = 0; 
     icmph->checksum = in_cksum((unsigned short *)icmph, 
         ntohs(nip_hdr->tot_len) - sizeof(struct iphdr)); 

     nskb->csum = 0; 
     nskb->csum = csum_partial((unsigned char *)(ntcp_hdr + ntcp_hdr_off), 
              ntohs(nip_hdr->tot_len) - 
     nip_hdr_off - ntcp_hdr_off, 0); 
     nskb->ip_summed = CHECKSUM_NONE; 
     nskb->pkt_type = PACKET_OUTGOING; //PACKET_OTHERHOST; 

     neth_hdr = (struct ethhdr *) skb_push(nskb, ETH_HLEN); 
     skb_reset_mac_header(nskb); 
     nskb->protocol = neth_hdr->h_proto = htons(ETH_P_IP); 
     memcpy (neth_hdr->h_dest, DMAC, ETH_ALEN); 
     memcpy (neth_hdr->h_source, SMAC, ETH_ALEN); 
     nskb->dev = dev_get_by_name(&init_net,ETH); 
     if(nskb->dev==NULL) 
     { 
      printk("%s\n", "dev_get_by_name return NULL"); 
      kfree_skb(nskb); 
      return NF_ACCEPT; 
     } 

     dev_hold(nskb->dev); 
     printk("%s\n", "dev_hold ok"); 
     dev_put(nskb->dev); 

     ret = dev_queue_xmit(nskb); 
     printk("ret:%d\n", ret); 
     return NF_STOLEN; 

} 


static int __init init(void) 
{ 
    int ret = 0; 
    modify_ops.hook = modify; 
    modify_ops.hooknum = 3; //NF_IP_LOCAL_OUT; 
    modify_ops.pf = PF_INET; 
    modify_ops.priority = NF_IP_PRI_FIRST; 

    ret = nf_register_hook(&modify_ops); 
    if (ret < 0) 
    { 
    printk("%s\n", "can't modify skb hook!"); 
    return ret; 
    } 

    printk("%s\n", "insmod modify skb module"); 
    return 0; 
} 

static void __exit fini(void) 
{ 
    nf_unregister_hook(&modify_ops); 
    printk("%s\n", "remove modify skb module."); 
} 

module_init(init); 
module_exit(fini); 
+0

您能否讓我們知道數據包未被髮送出去?您是否使用tcpDump或wireshark進行檢查?還是內核崩潰?或究竟是什麼? – Fingolfin 2013-04-11 10:34:39

回答

1

的ICMP校驗在分組沒有設置。校驗和被計算出來,但是放在nskb->csum中,在這種情況下這沒有意義。

下面是我雖然是問題:

NF_IP_LOCAL_OUT被調用的時候,數據包的MAC報頭還沒有設置。然而,
dev_queue_xmit預期MAC頭部到位。

設置所述MAC報頭(其可能需要發送ARP分組)在ip_finish_output完成後,鉤後,並調用dev_queue_xmit之前。您可以撥打dev_queue_xmit。如果您不能簡單地返回NF_ACCEPT,則需要重新輸入數據包(nf_reinject)。

+0

感謝您的評論。實際上,在代碼中,我設置了MAC頭。我認爲應該可以通過dev_queue_xmit傳遞數據包。 – user2232764 2013-04-11 07:44:43

+0

你確實。我仍然認爲,如果你注入到你接收數據包的同一個地方(即'nf_reinject'),情況會更加平滑。無論如何,ICMP校驗和呢? 'nskb-> csum'不會設置它。 – ugoren 2013-04-11 10:56:57

+0

是的,你是對的。我錯誤地評論了ICMP校驗和和SKB cheksum。看來ICMP數據包現在可以通過了。我糾正了上面的代碼。謝謝。 – user2232764 2013-04-11 16:22:53