Chinaunix

标题: netfilter修改IP以后一直发不出包 [打印本页]

作者: tinysniper    时间: 2014-05-29 01:06
标题: netfilter修改IP以后一直发不出包
下面是hook的代码
麻烦各位帮忙看下,怎么做

static unsigned int hook_func_postrouting(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 tcphdr *tcph;
    struct rtable *rt;
    int dest_port;
    int orig_ip;
    int datalen;
    if (!skb) {
        return NF_ACCEPT;
    } else {
        rt = skb_rtable(skb);
        iph = ip_hdr(skb);
        if (!iph) {
            return NF_ACCEPT;
        } else {
            if ( skb_linearize(skb) != 0 ) {
                printk(KERN_INFO "skb not liner\n");
                return NF_ACCEPT;
            }
            if ( iph->protocol == IPPROTO_TCP ) {
                tcph = (struct tcphdr*) (((char*) iph) + iph->ihl * 4);
                if ( !tcph ) {
                    return NF_ACCEPT;
                }
                dest_port = ntohs(tcph->dest);
                // printk(KERN_INFO "[FILTER]: from %pI4:%d to %pI4:%d\n", &iph->saddr, ntohs(tcph->source), &iph->daddr, ntohs(tcph->dest));

                if ( dest_port == 80 ) {
                    orig_ip = iph->daddr;      
                    iph->daddr = in_aton("192.168.2.116");
                    // printk(KERN_INFO "[FILTER]: modify dest ip from %pI4:%d to %pI4:%d\n", &orig_ip, dest_port, &iph->daddr, 80);

                    iph->check = 0;
                    ip_send_check(iph);
                    datalen = skb->len - iph->ihl * 4;

                    tcph->check = 0;
                    tcph->check = tcp_v4_check(datalen, iph->saddr, iph->daddr, csum_partial(tcph, datalen, 0));

                }
                    
            }
            return NF_ACCEPT;
        }
    }
}

作者: 黎明748    时间: 2014-05-29 01:18
。。。。怎么都返回NF_ACCEPT。。还是不明白你说什么。。。
作者: tinysniper    时间: 2014-05-29 10:26
我只是拿来做下测试,修改了ip头的目的ip以后,包就发不出去了,感觉是tcp校验和的问题
作者: bfdhczw    时间: 2014-05-29 10:45
我是这么算的,你试试看。
  1. static void update_chksum(struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcp)
  2. {
  3.         //ip
  4.         iph->check = 0;       
  5.         iph->check = ip_fast_csum(iph,iph->ihl);

  6.         //tcp
  7.         tcp->check = 0;
  8.         tcp->check = csum_tcpudp_magic(iph->saddr, iph->daddr,  
  9.             ntohs(iph->tot_len)-iph->ihl*4, IPPROTO_TCP,  
  10.             csum_partial(tcp, ntohs(iph->tot_len)-iph->ihl*4, 0));
  11. }
复制代码

作者: tinysniper    时间: 2014-05-29 11:25
回复 4# bfdhczw
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/inet.h>
  5. #include <linux/skbuff.h>
  6. #include <linux/tcp.h>
  7. #include <linux/netfilter.h>
  8. #include <linux/netfilter_ipv4.h>
  9. #include <linux/ip.h>
  10. #include <linux/udp.h>
  11. #include <net/tcp.h>
  12. #include <net/ip.h>

  13. static struct nf_hook_ops nfho_postrouting;


  14. static void update_checksum(struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcp)
  15. {
  16.     iph->check = 0;
  17.     iph->check = ip_fast_csum(iph, iph->ihl);

  18.     tcp->check = 0;
  19.     tcp->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
  20.             ntohs(iph->tot_len) - iph->ihl * 4, IPPROTO_TCP,
  21.             csum_partial(tcp, ntohs(iph->tot_len) - iph->ihl * 4, 0));
  22. }

  23. static unsigned int hook_func_postrouting(unsigned int hooknum,
  24.         struct sk_buff *skb,
  25.         const struct net_device *in,
  26.         const struct net_device *out,
  27.         int (*okfn)(struct sk_buff *))
  28. {
  29.     struct iphdr *iph;
  30.     struct tcphdr *tcph;
  31.     struct rtable *rt;
  32.     int dest_port;
  33.     int orig_ip;
  34.     int datalen;
  35.     if (!skb) {
  36.         return NF_ACCEPT;
  37.     } else {
  38.         rt = skb_rtable(skb);
  39.         iph = ip_hdr(skb);
  40.         if (!iph) {
  41.             return NF_ACCEPT;
  42.         } else {
  43.             if ( skb_linearize(skb) != 0 ) {
  44.                 printk(KERN_INFO "skb not liner\n");
  45.                 return NF_ACCEPT;
  46.             }
  47.             if ( iph->protocol == IPPROTO_TCP ) {
  48.                 tcph = (struct tcphdr*) (((char*) iph) + iph->ihl * 4);
  49.                 if ( !tcph ) {
  50.                     return NF_ACCEPT;
  51.                 }
  52.                 dest_port = ntohs(tcph->dest);

  53.                 if ( dest_port == 80 ) {
  54.                     orig_ip = iph->daddr;      
  55.                     // 直接浏览器打开http://192.168.2.1,只要挂上重新算了checksum就失败
  56.                     iph->daddr = in_aton("192.168.2.1");            
  57.                     update_checksum(skb, iph, tcph);
  58.                 }
  59.                     
  60.             }
  61.             return NF_ACCEPT;
  62.         }
  63.     }
  64. }

  65. static int __init init_main(void)
  66. {
  67.     nfho_postrouting.hook  = hook_func_postrouting;
  68.     nfho_postrouting.hooknum  = NF_INET_POST_ROUTING;
  69.     nfho_postrouting.pf       = PF_INET;
  70.     nfho_postrouting.priority = NF_IP_PRI_FIRST;

  71.     nf_register_hook(&nfho_postrouting);

  72.     return 0;
  73. }

  74. static void __exit cleanup_main(void)
  75. {
  76.     nf_unregister_hook(&nfho_postrouting);
  77. }

  78. module_init(init_main);
  79. module_exit(cleanup_main);

  80. MODULE_LICENSE("GPL");
复制代码
依旧有问题

我直接wget http://192.168.2.1,等于是,我压根没有修改ip,只是重新计算了一次checksum
直接就发不出包了
但是,不计算checksum的话,就完全没问题了

另外,我的内核版本有点高,我现在的内核是3.11.0
作者: tinysniper    时间: 2014-05-29 12:09
回复 4# bfdhczw


又抓包确认了下,还是tcp的校验和求错了
ip层的校验和没问题
   
作者: tinysniper    时间: 2014-05-29 13:18
谢谢各位,搞定了
skb->ip_summed忘记处理了
作者: 天外来的飞猪    时间: 2014-10-15 16:30
你好,请问你是怎么解决的,ip_summed设置成了什么




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2