测试环境: CentOS5.3 2.6.18 工具: sendip和wireshark sendip可以发送各种数据包,确实方便.wireshark图形化的显示对于分析整个数据包还是相当不错的... |
一:内核态基于Netfilter构造数据包
主要有两种方式:1. alloc_skb申请一个skb结构体,然后根据实际的应用填充不同的成员,或者基于当前数据包的skb,
调用skb_copy() pskb_copy() skb_copy_expand()等新申请一个nskb,并且拷贝skb的内容。
2. 直接在先前接收到的数据包skb上作修改,主要有源IP、目IP,如果是TCP/UDP协议的话,还有源端口目的端口号。
就是根据你自己的需求去调整数据包的相关成员即可。然后重新计算各个部分的校验和。
不管你第一种方式还是第二种方式,你需要知道你也必须知道的就是对于l2 l3 l4层的数据你都必须去构造,我之前就是
由于没有构造L2而郁闷了一天...
让我们先从一个小程序开始,把5个hook都挂上mac这个函数,主要就是看看l2,对于l3 l4以及应用层我以前的几个帖子里面
已经有很多了,这里就不说了
insmod mac.ko加载mac模块后,随便发个ping包
Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_OUT--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: mac is NULL------end NF_IP_LOCAL_OUT--------
Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_PRE_ROUTING--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a
Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac
Jan 10 09:44:13 nfs-client kernel: ------end NF_IP_PRE_ROUTING--------
Jan 10 09:44:13 nfs-client kernel: ------begin NF_IP_LOCAL_IN--------
Jan 10 09:44:13 nfs-client kernel: IPPROTO_ICMP
Jan 10 09:44:13 nfs-client kernel: len is 84, data len is 0
Jan 10 09:44:13 nfs-client kernel: SOURCE:00:50:56:fa:70:2a
Jan 10 09:44:13 nfs-client kernel: DEST:00:0c:29:4f:de:ac
Jan 10 09:44:13 nfs-client kernel: ------end NF_IP_LOCAL_IN--------
可以看到对于挂载在out上的数据包mac已经被剥掉
当接收一个包时,处理n层协议头的函数从n-1层收到一个缓冲区,它的skb->data指向n层协议的头。处理n层协议的函数把本层的指针(例如,L3对应的是skb->nh指针)初始化为skb->data,因为这个指针的值会在处理下一层协议时改变(skb->data将被初始化成缓冲区里的其他地址)。在处理n层协议的函数结束时,在把包传递给n+1层的处理函数前,它会把skb->data指针指向n层协议头的末尾,这正好是n+1层协议的协议头。
发送包的过程与此相反,但是由于要为每一层添加新的协议头,这个过程要比接收包的过程复杂。
好的,到现在你已经知道要重新搞一个数据包需要自己来DIY l2 l3 l4当然还有l7如果你想....
来先看看skb的几个重要指针吧
unsigned char *head
unsigned char *end
unsigned char *data
unsigned char *tail
它们表示缓冲区和数据部分的边界。在每一层申请缓冲区时,它会分配比协议头或协议数据大的空间。head和end指向缓冲区的头部和尾部,而data和tail指向实际数据的头部和尾部。每一层会在head和data之间填充协议头,或者在tail和end之间添加新的协议数据
那么具体操作这些指针呢?
(a)skb_put, (b)skb_push, (c)skb_pull, and (d)skb_reserve
再加上dev_queue_xmit这个函数,你已经可以完成整件事了,对你现在有点蒙感觉无从下手,我也是!!! 我是历经几十次的死机才成功的,写这个文章也是希望后来人少走点弯路...
那就从修改开始吧....
测试结果:
sendip -p ipv4 -is 192.168.238.180 -p tcp -ts 598982 -td 80 192.168.1.1
// sip sport dport dip
sendip比较好用吧,你可以指定syn ack之类的呢
上面的三个数据包是没有加载skb_modify模块的...上面的具体函数你们可以sourceinsight跟踪看看,我也不可能一一讲解
因为我们是挂在NF_IP_LOCAL_OUT上所以我们需要重新搞mac header
那么DIY SKB呢?
测试结果:
我这里并没有填充上层的东西 但是已经提供接口
pdata = skb_put (skb, pkt_len);
{
if (NULL != pkt)
memcpy (pdata, pkt, pkt_len);
}
你可以自己先截获一个上层的包再填充进去... 关于上层的东西我 开源应用层DPI--l7detect初步成果 已经很清楚了,都已经DPI了
就这么多吧,天冷在寝室又没有暖气和空调,考个研还不让我们进实验室^_^,经过这两天的奋战终于搞定修改skb DIY SKB再加上以前基于netfilter的深度数据包检测.... 至此我可以很自信的说对于netfilter不算静态也算熟练了...
由于本人也是菜鸟,纰漏和不对之处还望指正... 写这些东西纯属爱好,由于内核网络代码这块变化看对于测试环境不一样的机子,概不保证正确性...但是思路肯定还是这样的,主要就是几个API的变化而已
参考:
http://blog.chinaunix.net/u/33048/showart_2043789.html
http://hi.baidu.com/zshidong/blo ... 5f1d00213f2eb0.html