- 浏览: 228364 次
- 性别:
- 来自: 北京
最新评论
-
qq452739204:
如果构造的报文大于mtu值,是否需要分片之后再发送出去列?
Linux内核构造数据包并发送(二)(dev_queue_xmit方式) -
xingzengmou:
你好,我搞的原理跟你差不多,但播放的时候有papapa的声音, ...
AudioRecord和AudioTrack类的使用 -
wenjiefeng:
楼主,你有录制pcm格式和播放pcm格式的录音器的demo吗, ...
AudioRecord和AudioTrack类的使用 -
lovepeakingA:
...
AudioRecord和AudioTrack类的使用 -
ZaneLee007:
假的,不学无术
Android禁用键盘的所有按键
一、构造数据包简析
这里并不详细介绍如何在内核中构造数据包,下文如有需要会在适当的位置进行分析。这里简单的分析讲一下内核态基于Netfilter框架构造数据包的方式。
内核中可以用到的构造数据包的方式,个人认为可以分为两种。
其一,我们直接用alloc_skb申请一个skb结构体,然后根据实际的应用填充不同的成员,或者基于当前数据包的skb,调用skb_copy_expand()函数等新申请一个nskb,并且拷贝skb的内容。
其二,也是个人比较常用的,就是直接在先前接收到的数据包skb上作修改,主要有源IP、目IP,如果是TCP/UDP协议的话,还有源端口目的端口号。总之,就是根据自己的需求去调整数据包的相关成员即可。
通常,这两种方式最终可能都要涉及到重新计算各个部分的校验和,这也是必须的。
二、如何发送构造的数据包
承接上文,数据包已经构造完毕,下一步关键就是如何发送数据包了。个人这里总结的有两种方法。
方法一,就是让数据包接着按照Netfilter的流程进行传输。因为数据包的一些内容已经被更改,尤其是当源IP和目的IP被更改,主要是交换的情况下,是需要确保有路由可查的。
NF框架中查路由的位置一是在PREROUTING之后,而是在LOCALOUT之后。又由于这里是需要将数据包从本地发送出去。因此,可以考虑让修改后的数据包从LOCALOUT点发出。
内核代码中有这种方式的典型体现。本文涉及的相关内核代码的版本都是2.6.18.3。源文件为ipt_REJECT.c,函数send_reset用于往当前接收到数据包的源IP上发送RST包,整个函数涉及了数据包的构造和发送,这里一起做个简单分析。
/* Send RST reply */ static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; struct rtable *rt; u_int16_t tmp_port; u_int32_t tmp_addr; int needs_ack; int hh_len; /* 判断是否是分片包*/ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) return; /*得到TCP头部指针*/ oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4, sizeof(_otcph), &_otcph); if (oth == NULL) return; /* 当期收到的包就是RST包,就不用再发送RST包了*/ if (oth->rst) return; /*检查数据包的校验和是否正确*/ if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) return; /*这一步比较关键,做的就是更新路由的工作。该函数的主要工作就是将当前数据包的源IP当做路由的目的IP,同时考虑数据包的目的IP,得到去往该源IP的路由*/ if ((rt = route_reverse(oldskb, oth, hook)) == NULL) return; hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); /* 拷贝当前的oldskb,包括skb结构体和数据部分。这就是我们上面提到的构造数据包的第一种方式*/ nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), GFP_ATOMIC); if (!nskb) { dst_release(&rt->u.dst); return; } /*因为是拷贝的oldskb,这里不需要再引用了,因此释放对该路由项的引用*/ dst_release(nskb->dst); /*将新构造数据包引用的路由指向上面由route_reverse函数返回的新的路由项 */ nskb->dst = &rt->u.dst; /* 清除nskb中拷贝过来的oldskb中链接跟踪相关的内容*/ nf_reset(nskb); nskb->nfmark = 0; skb_init_secmark(nskb); /*以下就是构造数据包的实际数据部分。如果我们将这里不为nskb新申请缓冲区,而直接指向oldskb的缓冲区,就使我们上面提到的第二种构造数据包的方法。*/ /*获取nskb的tcp header*/ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); /*交换源和目的IP */ tmp_addr = nskb->nh.iph->saddr; nskb->nh.iph->saddr = nskb->nh.iph->daddr; nskb->nh.iph->daddr = tmp_addr; /*交换源和目的端口 */ tmp_port = tcph->source; tcph->source = tcph->dest; tcph->dest = tmp_port; /*重置TCP头部的长度,并修改IP头部中记录的数据包的总长度。因为这里是发送RST报文,只需要有TCP的头部,不需要TCP的数据部分*/ tcph->doff = sizeof(struct tcphdr)/4; skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); nskb->nh.iph->tot_len = htons(nskb->len); /*重新设置 seq, ack_seq,分两种情况(TCP/IP详解有描述)*/ if (tcph->ack) { /*原始数据包中ACK标记位置位的情况*/ needs_ack = 0; tcph->seq = oth->ack_seq; /*原始数据包的ack_seq作为nskb的seq*/ tcph->ack_seq = 0; } else { /*原始数据包中ACK标记位没有置位的情况,初始连接SYN或者结束连接FIN等*/ needs_ack = 1; /*这种情况应该是SYN或者FIN包,由于SYN和FIN包都占用1个字节的长度。因此ack_seq应该等于旧包的seq+1即可。这里之所以这样表示,可能是还存在其他情况的数据包。*/ tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - oldskb->nh.iph->ihl*4 - (oth->doff<<2)); tcph->seq = 0; } /* RST标记位置1*/ ((u_int8_t *)tcph)[13] = 0; tcph->rst = 1; tcph->ack = needs_ack; tcph->window = 0; tcph->urg_ptr = 0; /*重新计算TCP校验和*/ tcph->check = 0; tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), nskb->nh.iph->saddr, nskb->nh.iph->daddr, csum_partial((char *)tcph, sizeof(struct tcphdr), 0)); /* 修改IP包的TTL,并且设置禁止分片*/ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); /* Set DF, id = 0 */ nskb->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->id = 0; /*重新计算IP数据包头部校验和*/ nskb->nh.iph->check = 0; nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, nskb->nh.iph->ihl); /* "Never happens" */ if (nskb->len > dst_mtu(nskb->dst)) goto free_nskb; /*使nskb和oldskb的链接记录关联*/ nf_ct_attach(nskb, oldskb); /*这里就是最终发送数据包的方式,具体方法就是让新数据包经过LOACLOUT的hook点,然后查路由,最后经由PREROUTING点,将数据包发送出去。 其实这里我还是有1个疑问:(1)为什么不可以直接查找路由,而必须先经过LOCALOUT点;*/ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, dst_output); return; free_nskb: kfree_skb(nskb); }其实,这不是丢到了高层,而是和ip_queue_xmit()发送过程意义一样。
对这包进行重新路由后,封装了头部,之后,放到了NF_IP_LOCAL_IN之前而已。
其实,这里面只要修改了中途修改了ip地址,肯定是需要手动重新路由的。
这就涉及到一些比较复杂的route cache的查找,如果没有就去查找route tables;之后,进行路由结构和neighbour结构的关联,就涉及到邻居子系统的相关操作;接着就涉及到arp cache的查找,如果没有,进行一些操作,arp的过程等等,才找到了相关的ip对应的mac信息。
转自:http://blog.chinaunix.net/u/33048/showart_2043789.html,作者:Godbach
发表评论
-
Netfilter 地址转换的实现
2011-03-17 23:04 0作者:九贱内核版本:2 ... -
Linux内核构造数据包并发送(二)(dev_queue_xmit方式)
2011-03-03 12:24 8899linux内核太构造数据包 ... -
iphdr与tcphdr详解(skb_header_pointer函数分析)
2011-03-01 12:25 4655linux 2.6.26 下获取tcp信息: tcph=sk ... -
unp.h文件内容
2010-11-28 15:33 2153/* Our own header. Tabs are se ... -
inet_pton和inet_ntop函数
2010-11-28 15:03 1935Linux下这2个IP地址转换函数,可以在将IP地址在“点分十 ... -
linux类原版电子书589本
2010-10-27 16:13 4218ftp://202.96.64.144/pub/books/( ... -
Linux下线程同步对象——互斥量
2010-10-09 10:47 1616进程是Linux资源分配的对象,Linux会为进程分配虚 ... -
系统信息相关命令
2010-09-27 15:55 831系统 # uname -a ... -
Unix/Linux环境下创建和使用静/动态库
2010-09-27 15:51 1328库的作用 大体上库的存在,有两方面的原因,一是代码 ... -
Linux中实现30分钟无操作自动关机
2010-09-27 15:42 1720这是一个自动关机的小程序。该程序可以守护进程的方式运行, ... -
linux IPC-消息队列
2010-09-27 14:02 2386几乎所有的 Linux 发行版本都包含 ipcs 命 ... -
8)Linux程序设计入门--网络编程(下)
2010-09-26 14:12 1095网络编程(7) 7. TCP/IP协议 你也许听说过T ... -
8)Linux程序设计入门--网络编程 (上)
2010-09-26 14:07 1232Linux系统的一个主要 ... -
7)Linux程序设计入门--线程操作
2010-09-26 13:58 946前言:Linux下线程的创 ... -
6)Linux程序设计入门--消息管理
2010-09-26 13:56 987前言:Linux下的进程通 ... -
5)Linux程序设计入门--信号处理
2010-09-26 13:54 1024Linux下的信号事件 前 ... -
4)程序设计入门--时间概念
2010-09-26 13:50 793前言:Linux下的时间概 ... -
3)Linux程序设计入门--文件操作
2010-09-26 13:48 1003Linux下文件的操作 前言: 我们在这一节将要讨论 ... -
2)Linux程序设计入门--进程介绍
2010-09-26 11:05 915前言: 这篇文章是用 ... -
1)Linux程序设计入门--基础知识
2010-09-26 11:02 847Linux下C语言编程基础知识 前言: 这篇文章介绍 ...
相关推荐
linux 内核netfilter 源码分析 的一些资料
Linux内核防火墙netfilter的原理和应用.pdf
介绍了Linux内核防火墙的发展,对2.4.x内核中的Netfilter框架的流程和IPv4协议栈中Netfilter的实现进行了分析,通过一个内核防火墙模块实例介绍了基于Netfilter框架下的内核防火墙设计方法,对Netfilter框架下的防火墙...
Linux网络防火墙Netfilter的数据包传输过滤原理.pdf
linux内核中使用哈希的例子,利用netfilter抓包然后做成哈希链表
Netfilter是Linux内核中的一个重要子系统,它提供了强大的网络处理能力,包括数据包过滤、网络地址转换(NAT)以及连接跟踪等功能。Netfilter的核心机制是通过一系列的hook点来拦截并处理网络数据包。这些hook点分布...
它提供了一个抽象、通用化的框架,相比之前的任何一版本Linux内核防火墙子系统都要完善强大。 Netfilter的功能框架主要包括数据包过滤、数据包处理和NAT等几个方面。数据包过滤是指对进入系统的数据包进行检查和...
在linux2.2内核中的防火墙ipchains已经被用户广泛认可,它提供了完整的防火墙功 能(包过滤,地址伪装,透明代理),又避免了商业防火墙那高的惊人的价格。如果 你用的是某款国产防火墙,那么十有八九你实际在受到...
Linux内核Netfilter包过滤防火墙的设计与实现.pdf
Linux内核防火墙Netfilter的原理及应用分析
知识基础:本防火墙的开发基于对Linux内核网络栈有个良好的概念,本人对网络栈的分析是基于早期版本(Linux 1.2.13),在明确了网络栈架构的前提下,上升一步分析高级版本内核中的Netfilter防火墙实现原理,然后进行...
Linux的Netfilter框架和数据包捕获技术
与传统链表定义不同的是,Linux内核中的链表结构并不包含数据域。相反,链表结构被嵌入到需要组织的数据结构中。例如,在`include/linux/netfilter.h`文件中,`nf_sockopt_ops`结构体中就包含了一个`struct list_...
netfilter是Linux内核中用于数据包过滤、处理的框架,其允许插入不同的模块来进行网络数据包的修改、检查等操作。数据包在netfilter中通过不同hook点的处理可能包括: - NF_INET_PRE_ROUTING:在数据包到达本机并...
文章《基于Linux内核Netfilter框架的P2P管理》主要探讨了如何利用Netfilter框架来识别和管理P2P网络数据包。作者提出了两种方法: 1. **端口识别法**:P2P应用通常使用特定的端口号进行通信,例如BitTorrent使用...
基于Linux内核防火墙Netfilter的安全应用的设计方法.pdf
内核数据包处理是Linux内核中的一种机制,用于处理网络数据包的接收和处理。下面将详细介绍内核数据包处理的相关知识点。 1. 数据包处理的一些建议 在内核数据包处理中,我们需要解析数据,进行一系列的包匹配完成...