免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 8874 | 回复: 16
打印 上一主题 下一主题

请教一个netfilter和netif_rx配合使用的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-05-04 21:16 |只看该作者 |倒序浏览
正在做一个项目 里面需要有这样一个步骤

1.在网络层将数据包截住并修改
2.重新把修改后的数据包交付给协议栈底端 让它重新经过协议栈

开始阶段 为了实现简单 用ICMP报文作为拦截对象 且截住的数据包不做过多修改 只将协议头部若干指针修改 让它的报文头状态变为好像刚刚从网卡到来的时候一样

实现的时候 用的是netfilter的PRE_ROUTING钩子 检查每一个数据包 如果是ICMP报文且类型为8 即ECHO报文 就将报文截获 复制一个 修改头部信息 然后重新调用netif_rx 让协议栈接收 原来的报文使用NF_STOLEN处理

注册在PRE_ROUTING钩子处的回调函数如下

  1. static unsigned int pre_routing_hook(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, \
  2.                 const struct net_device *out, int (*okfn)(struct sk_buff *))
  3. {
  4.         struct sk_buff *skb;
  5.         struct sk_buff *new_skb;
  6.         //unsigned char src_ip[4];
  7.         //unsigned char dst_ip[4];
  8.         //
  9.         struct icmphdr *icmp_hdr;
  10.         int icmp_hdr_off;
  11.         //
  12.         struct iphdr *ip_hdr;
  13.         int ip_hdr_off;
  14.         struct ethhdr *eth_hdr;
  15.        
  16.         struct net_device *NIC = NULL;
  17.         const char nic[5] = "eth0";
  18.         // printk(KERN_INFO "inside the filter\n");
  19.        
  20.         int index;
  21.        
  22.         int rx_ret;
  23.        
  24.         skb = skb_copy(*pskb, GFP_ATOMIC);
  25.         NIC = dev_get_by_name(nic);
  26.        
  27.         if (!NIC) {
  28.                 return NF_ACCEPT;
  29.         }
  30.        
  31.         if (skb->nh.iph->protocol == IPPROTO_ICMP) {
  32.                 // get ip header
  33.                 ip_hdr = (struct iphdr *)skb->nh.iph;
  34.                 // calcutate ip header length
  35.                 ip_hdr_off = ip_hdr->ihl << 2;
  36.                
  37.                 // get icmp header
  38.                 icmp_hdr = (struct icmphdr *)(skb->data + ip_hdr_off);
  39.                                                
  40.                 // only modify icmp request
  41.                 // #define ICMP_ECHO        8        /* Echo Request */
  42.                 // in <linux/icmp/h>
  43.                 if (icmp_hdr->type == ICMP_ECHO) {
  44.                         new_skb = alloc_skb(skb->len + 5 + ETH_HLEN, GFP_ATOMIC);
  45.                         skb_reserve(new_skb, 2);
  46.                         skb_put(new_skb, skb->len + ETH_HLEN);
  47.                         memcpy(new_skb->data, skb->data - ETH_HLEN, skb->len + ETH_HLEN);
  48.                         new_skb->mac.raw = new_skb->data;
  49.                         // commented
  50.                         //skb_pull(new_skb, ETH_HLEN);
  51.                        
  52.                         new_skb->mac_len = ETH_HLEN;
  53.                         new_skb->len = skb->len + ETH_HLEN;
  54.                        
  55.                         new_skb->ip_summed = CHECKSUM_UNNECESSARY;
  56.                         new_skb->pkt_type = PACKET_HOST;
  57.                         new_skb->protocol = htons(ETH_P_IP);
  58.                         new_skb->dev = NIC;
  59.                         skb_shinfo(new_skb)->nr_frags = 0;
  60.                         skb_shinfo(new_skb)->frag_list = NULL;
  61.                         skb_shinfo(new_skb)->frags[0].page = NULL;
  62.                        
  63.                         rx_ret = netif_rx(new_skb);
  64.                         NIC->last_rx = jiffies;
  65.                         kfree_skb(skb);
  66.                         return NF_STOLEN;
  67.                 }
  68.         }
  69.         kfree_skb(skb);
  70.         return NF_ACCEPT;
  71. }

复制代码
现在的情况是 将修改的数据包送给netif_rx函数 通过Wireshark截包 可以看到原来的ICMP报文以及复制后重新交给协议栈的数据包
由于ping命令是在Windows里发出的 默认是4个ICMP request报文 所以在Wireshark里看到的是8个ICMP request报文
但是 复制修改后重新交给协议栈的ICMP request报文并没有得到上层的回应 因为没有ICMP reply报文发出 原有的ICMP request被NF_STOLEN处理 因此也不会被回应 没有ICMP reply
情况如下图



请教各位 如何才能让我自己复制并交给协议栈的ICMP request报文得到上层的回应?

是我调用netif_rx的方式不对?还是我复制的sk_buff 修改包头指针时候出现了错误?或者是什么其他错误?

还有一个问题 我查了很多论坛 有的人说 传给netif_rx的sk_buff是网络层的 没有eth_hdr 有人说是链路层的 应该包含eth_hdr 到底哪个才是正确的呢?

论坛徽章:
0
2 [报告]
发表于 2010-05-05 02:09 |只看该作者
你重新 netif_rx的包,在通过钩子时,
依然return NF_STOLEN;
IPPROTO_ICMP包永远被你 return NF_STOLEN,
协议栈当然忽略这个包了

重新经过netif_rx,意义何在?
你的需求,可直接修改数据包,然后 NF_ACCEPT

论坛徽章:
0
3 [报告]
发表于 2010-05-05 09:56 |只看该作者
本帖最后由 ipiszhang 于 2010-05-05 10:16 编辑

2楼的朋友
明白你的意思了 这一点是我之前忽略了 如果数据包能再次经过协议栈 一定会次被 NF_STOLEN

至于方法问题 没办法 这是科研项目的需求 上面领导必须要求这么做……

可是现在的情况是 复制的数据包一定没有到达钩子
因为如果到达了 会再次复制一个新的数据包 再次送netif_rx
这样 即使收到一个ICMP request报文A 程序会复制新的ICMP request 报文B 送交netif_rx B经过钩子时又会复制出C 网卡上会出现无限多个ICMP报文的情况 可是我现在的情况却不是这样的

是不是还是哪个指针的错误呢?

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
4 [报告]
发表于 2010-05-05 11:18 |只看该作者
如果是内核源码,建议说一下在什么内核版本上实现的

论坛徽章:
0
5 [报告]
发表于 2010-05-05 12:56 |只看该作者
如果是内核源码,建议说一下在什么内核版本上实现的
Godbach 发表于 2010-05-05 11:18 AM


斑竹你好~
我是在 Kernel 2.6.18-164.15.1.el5 上实现的
操作系统是 CentOS 5.4

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
6 [报告]
发表于 2010-05-05 13:01 |只看该作者
既然你对原始包的处理时NF_STOLEN,那么可以考虑直接在原始报文上修改,而不用copy。

论坛徽章:
0
7 [报告]
发表于 2010-05-05 13:27 |只看该作者
既然你对原始包的处理时NF_STOLEN,那么可以考虑直接在原始报文上修改,而不用copy。
Godbach 发表于 2010-05-05 01:01 PM


不好意思 不太明白了……
如果修改了原始包 再NF_STOLEN 这个包还是被废弃了 到了网络层就不往上走了啊

我现在只是用ICMP报文试验如何自定义一个数据包交给协议栈 让它能接受 并且以为这个包就是来自网卡 以后还会处理TCP或者UDP报文 如果NF_STOLEN了 数据包就更到不了传输层了

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
8 [报告]
发表于 2010-05-05 13:41 |只看该作者
修改了原始的报纸后,你不是让他走新的流程了吗,已经相当于再次发出去了。同时告诉hook函数,当前进入流程的这个包不用管了啊。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
9 [报告]
发表于 2010-05-05 13:42 |只看该作者
另外,你肯定是要做一些机制。来确保你修改后的包,在进入这个hook的时候,能够直接交给协议栈后续处理,而不用被再次修改,那样就是个死循环了。

论坛徽章:
0
10 [报告]
发表于 2010-05-05 13:51 |只看该作者
修改了原始的报纸后,你不是让他走新的流程了吗,已经相当于再次发出去了。同时告诉hook函数,当前进入流程 ...
Godbach 发表于 2010-05-05 01:41 PM
另外,你肯定是要做一些机制。来确保你修改后的包,在进入这个hook的时候,能够直接交给协议栈后续处理,而 ...
Godbach 发表于 2010-05-05 01:42 PM


恩 这一点之前的确欠考虑

我是这样修改的 因为在我定义的数据包里 有这样一句
  1. new_skb->ip_summed = CHECKSUM_UNNECESSARY;
复制代码
所以再前面判断的时候 可以以这个为依据 区分是原始的数据包还是修改后的数据包

就是把上面代码里的
  1. if (skb->nh.iph->protocol == IPPROTO_ICMP)
复制代码
改为
  1. if (skb->nh.iph->protocol == IPPROTO_ICMP && skb->ip_summed != CHECKSUM_UNNECESSARY)
复制代码
就保证不会进入死循环 而只处理原始的数据包了 但是目前问题依然 就是对于每个ICMP request报文 Wireshark能截到两次 但是两个都没有回应
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP