免费注册 查看新帖 |

Chinaunix

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

使用send_reset发送数据包问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-06-08 12:07 |只看该作者 |倒序浏览
本帖最后由 boonie 于 2010-06-08 12:08 编辑

我在2.6.9内核下,改造内核中的send_reset函数,可以把自己构造的skb发送出去,但是再2.6.29下,会出现内核错误
方法是改造send_reset函数

构造skb的函数:

  1. int send_packet_to_nf(char *data, int data_len)
  2. {
  3.     static struct sk_buff *skb;
  4.     static unsigned int headroom = 14 + 2; // ll is 14, and  Force 16 byte alignment
  5.     unsigned int len = data + headroom ;  // data是从三层协议开始
  6.     int ret;
  7.    
  8.     if (data == NULL) return -1;

  9.     skb = alloc_skb(len, GFP_ATOMIC);
  10.     if (skb == NULL) {
  11.         printk("alloc skb error\n");
  12.         return -1;
  13.     }

  14.     skb_reserve(skb, headroom);
  15.     skb_put(skb, data_len);
  16.     memcpy(skb->data, data, data_len);
  17.    
  18.     skb->protocol = 8;    // IP type
  19.    
  20.     if (connect_type == 1)
  21.         skb->pkt_type = PACKET_HOST;    // dest mac == host mac
  22.     else if(connect_type == 2)
  23.         skb->pkt_type = PACKET_OUTGOING;    // dest mac != host mac

  24.     skb->mac.raw = skb->data;
  25.     skb->nh.raw = skb->data;

  26.     ret = send_skb(skb, hook);
  27.     kfree_skb(skb);
  28.    
  29.     return ret;
  30. }
复制代码
改造后的send_reset的函数名为send_skb()


  1. static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
  2. {
  3.     void (*attach)(struct sk_buff *, struct sk_buff *);

  4.     /* Avoid module unload race with ip_ct_attach being NULLed out */
  5.     if (skb->nfct && (attach = ip_ct_attach) != NULL) {
  6.         mb(); /* Just to be sure: must be read before executing this */
  7.         attach(new_skb, skb);
  8.     }
  9. }


  10. static int send_skb(struct sk_buff *oldskb, int hook)
  11. {
  12.     struct sk_buff *nskb;
  13.     struct tcphdr _otcph, *oth;
  14.     struct rtable *rt;
  15.     //int needs_ack;
  16.     int hh_len;

  17.     if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) return -1;

  18.     /* FIXME: Check checksum --RR */
  19.     if ((rt = route_reverse(oldskb, hook)) == NULL) return -1;

  20.     hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);

  21.     nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
  22.                    GFP_ATOMIC);
  23.     if (!nskb) {
  24.         dst_release(&rt->u.dst);
  25.         return -1;
  26.     }

  27.     dst_release(nskb->dst);
  28.     nskb->dst = &rt->u.dst;

  29.     /* This packet will not be the same as the other: clear nf fields */
  30.     nf_reset(nskb);
  31.     nskb->nfcache = 0;
  32.     nskb->nfmark = 0;
  33. #ifdef CONFIG_BRIDGE_NETFILTER
  34.     nf_bridge_put(nskb->nf_bridge);
  35.     nskb->nf_bridge = NULL;
  36. #endif

  37.     connection_attach(nskb, oldskb);

  38.     NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
  39.         ip_finish_output);
  40.     return 0;
  41. }
复制代码
2.6.29下改造后的send_reset的函数名为send_skb

  1. static int  send_skb(struct sk_buff *oldskb, int hook)
  2. {
  3.         struct sk_buff *nskb;
  4.         const struct iphdr *oiph;
  5.         struct iphdr *niph;
  6.         const struct tcphdr *oth;
  7.         struct tcphdr _otcph, *tcph;
  8.         unsigned int addr_type;


  9.         oiph = ip_hdr(oldskb);

  10.         nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
  11.                          LL_MAX_HEADER, GFP_ATOMIC);
  12.         if (!nskb)
  13.                 return -1;

  14.         skb_reserve(nskb, LL_MAX_HEADER);

  15.         skb_reset_network_header(nskb);

  16.         addr_type = RTN_UNSPEC;
  17.         if (hook != NF_INET_FORWARD
  18. #ifdef CONFIG_BRIDGE_NETFILTER
  19.             || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
  20. #endif
  21.            )
  22.                 addr_type = RTN_LOCAL;

  23.         /* ip_route_me_harder expects skb->dst to be set */
  24.         dst_hold(oldskb->dst);
  25.         nskb->dst = oldskb->dst;

  26.         if (ip_route_me_harder(nskb, addr_type))
  27.                 goto free_nskb;

  28.         niph->ttl        = dst_metric(nskb->dst, RTAX_HOPLIMIT);
  29.         nskb->ip_summed = CHECKSUM_NONE;

  30.         /* "Never happens" */
  31.         if (nskb->len > dst_mtu(nskb->dst))
  32.                 goto free_nskb;

  33.         nf_ct_attach(nskb, oldskb);

  34.         ip_local_out(nskb);
  35.         return 0;

  36. free_nskb:
  37.         kfree_skb(nskb);
  38.                 return -1;
  39. }
复制代码
有在2.6.29做过类似的事情吗?

论坛徽章:
0
2 [报告]
发表于 2010-06-08 12:25 |只看该作者
报错的地方时在dst_hold(oldskb->dst)处,从使用netfilter抓包到发送,oldskb->dst都是空的,但不知道如何修改

论坛徽章:
0
3 [报告]
发表于 2010-06-08 13:03 |只看该作者
调用 send_skb 的位置在哪里?
此时 oldskb->dst 也是空的吗?

论坛徽章:
0
4 [报告]
发表于 2010-06-08 13:49 |只看该作者
流程是这样的,通过netfilter抓取包,然后把数据包保存下来,从data开始到tail的内容,然后开始构造,调用send_packet_to_nf,把数据包的内容放入skb中,使用send_skb发送,在2.6.9中,nskb->dst = &rt->u.dst;所以dst不为空,而在2.6.29中dst总是空的

论坛徽章:
0
5 [报告]
发表于 2010-06-08 15:42 |只看该作者
哦,我的意思是,你在哪个 hook 点,以什么 prio 去获取数据并构造 send_packet 的?可能和位置有关
dst 应该是查找路由后的结果

论坛徽章:
0
6 [报告]
发表于 2010-06-08 17:43 |只看该作者
我使用的获取数据包的点是NF_INET_PRE_ROUTING

已经解决了,查一些路由,就是类似2.6.9
rt = route_reverse(oldskb, hook);
nskb->dst = &rt->u.dst;

然后就可以了

论坛徽章:
0
7 [报告]
发表于 2010-06-08 22:30 |只看该作者
哦,如果是 PRE_ROUTING 那就对了,这是路由前,如果你要在此作路由查询,必须要自己实现了
恭喜 boonie 解决了问题

论坛徽章:
0
8 [报告]
发表于 2012-08-21 17:38 |只看该作者
楼主好!但是在2.6.24以后的版本里面都没有route_reverse这个函数了,你是不是用的这个版本之前的route_reverse函数啊?还有既然新版本的内核都去掉查找路由,我想应该有别的新的办法能解决楼主的问题吧,!!!

论坛徽章:
0
9 [报告]
发表于 2018-11-06 18:40 |只看该作者
回复 8# jasenwan88

ip_route_input_noref 我想可以解决这个问题
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP