linuxip协议栈源代码分析pdfWord格式文档下载.docx

上传人:b****5 文档编号:17156012 上传时间:2022-11-28 格式:DOCX 页数:7 大小:19.52KB
下载 相关 举报
linuxip协议栈源代码分析pdfWord格式文档下载.docx_第1页
第1页 / 共7页
linuxip协议栈源代码分析pdfWord格式文档下载.docx_第2页
第2页 / 共7页
linuxip协议栈源代码分析pdfWord格式文档下载.docx_第3页
第3页 / 共7页
linuxip协议栈源代码分析pdfWord格式文档下载.docx_第4页
第4页 / 共7页
linuxip协议栈源代码分析pdfWord格式文档下载.docx_第5页
第5页 / 共7页
点击查看更多>>
下载资源
资源描述

linuxip协议栈源代码分析pdfWord格式文档下载.docx

《linuxip协议栈源代码分析pdfWord格式文档下载.docx》由会员分享,可在线阅读,更多相关《linuxip协议栈源代码分析pdfWord格式文档下载.docx(7页珍藏版)》请在冰豆网上搜索。

linuxip协议栈源代码分析pdfWord格式文档下载.docx

详细地说,netfilter/iptables的体系结构可以分为三个大部分:

  filter的hook机制

  netfilter的通用框架不依赖于具体的协议,而是为每种网络协议定义一套hook函数。

这些hook函数在数据报经过协议栈的几个关键点时被调用,在这几个点中,协议栈将数据报及hook函数标号作为参数,传递给netfilter框架。

  对于它在网络堆栈中增加的这些hook,内核的任何模块可以对每种协议的一个或多个hook进行注册,实现挂接。

这样当某个数据报被传递给netfilter框架时,内核能检测到是否有任何模块对该协议和hook函数进行了注册。

若注册了,则调用该模块的注册时使用的回调函数,这样这些模块就有机会检查、修改、丢弃该数据报及指示netfilter将该数据报传入用户空间的队列。

  这样,hook提供了一种方便的机制:

在数据报通过linux内核的不同位置上截获和操作处理数据报。

  2.iptables基础模块

  iptables基础模块实现了三个表来筛选各种数据报,具体地讲,linux2.4内核提供的这三种数据报的处理功能是相互间独立的模块,都基于netfilter的hook函数和各种表、链实现。

这三个表包括:

filter表,nat表以及mangle表。

  3.具体功能模块

  1.

  1.数据报过滤模块

  2.连接跟踪模块(conntrack)

  3.网络地址转换模块(nat)

  4.数据报修改模块(mangle)

  5.其它高级功能模块

  于是,netfilter/iptables总体架构如图

  

  三、hook的实现

  filter-ipv4中的hook

  netfilter模块需要使用hook来启用函数的动态钩接,它在ipv4中定义了五个hook(位于文件include/linux/netfilter_ipv4.h,line39),分别对应0-4的hooknum

  简单地说,数据报经过各个hook的流程如下:

  数据报从进入系统,进行ip校验以后,首先经过第一个hook函数

  nF_ip_pRe_Routing进行处理;

然后就进入路由代码,其决定该数据报是需要转发还是发给本机的;

若该数据报是发被本机的,则该数据经过hook函数nF_ip_local_in处理以后然后传递给上层协议;

若该数据报应该被转发则它被nF_ip_FoRwaRd处理;

经过转发的数据报经过最后一个hook函数nF_ip_post_Routing处理以后,再传输到网络上。

本地产生的数据经过hook函数nF_ip_local_out处理后,进行路由选择处理,然后经过nF_ip_post_Routing处理后发送出去。

  总之,这五个hook所组成的netfilter-ipv4数据报筛选体系如图

  详细地说,各个hook及其在ip数据报传递中的具体位置如图

  nF_ip_pRe_Routing(0)

  数据报在进入路由代码被处理之前,数据报在ip数据报接收函数ip_rcv()(位于net/ipv4/ip_input.c,line379)的最后,也就是在传入的数据报被处理之前经过这个hook。

在ip_rcv()中挂接这个hook之前,进行的是一些与类型、长度、版本有关的检查。

  经过这个hook处理之后,数据报进入ip_rcv_finish()(位于

  net/ipv4/ip_input.c,line306),进行查路由表的工作,并判断该数据报是发给本地机器还是进行转发。

  在这个hook上主要是对数据报作报头检测处理,以捕获异常情况。

涉及功能(优先级顺序):

conntrack(-200)、mangle(-150)、dnat(-100)

  nF_ip_local_in

(1)

  目的地为本地主机的数据报在ip数据报本地投递函数ip_local_deliver()(位于net/ipv4/ip_input.c,line290)的最后经过这个hook。

  经过这个hook处理之后,数据报进入ip_local_deliver_finish()(位于net/ipv4/ip_input.c,line219)

  这样,iptables模块就可以利用这个hook对应的input规则链表来对数据报进行规则匹配的筛选了。

防火墙一般建立在这个hook上。

  涉及功能:

mangle(-150)、filter(0)、snat(100)、conntrack(int_max-1)

  nF_ip_FoRwaRd

(2)

  目的地非本地主机的数据报,包括被nat修改过地址的数据报,都要在ip数据报转发函数ip_forward()(位于net/ipv4/ip_forward.c,line73)的最后经过这个hook。

  经过这个hook处理之后,数据报进入ip_forward_finish()(位于

  net/ipv4/ip_forward.c,line44)

  另外,在net/ipv4/ipmr.c中的ipmr_queue_xmit()函数(line1119)最后也会经过这个hook。

(ipmr为多播相关,估计是在需要通过路由转发多播数据时的处理)

  这样,iptables模块就可以利用这个hook对应的FoRwaRd规则链表来对数据报进行规则匹配的筛选了。

mangle(-150)、filter(0)

  nF_ip_local_out(3)

  本地主机发出的数据报在ip数据报构建/发送函数ip_queue_xmit()(位于net/ipv4/ip_output.c,line339)、以及ip_build_and_send_pkt()(位于

  net/ipv4/ip_output.c,line122)的最后经过这个hook。

(在数据报处理中,前者最为常用,后者用于那些不传输有效数据的syn/ack包)

  经过这个hook处理后,数据报进入ip_queue_xmit2()(位于

  net/ipv4/ip_output.c,line281)

  另外,在ip_build_xmit_slow()(位于net/ipv4/ip_output.c,line429)和ip_build_xmit()(位于net/ipv4/ip_output.c,line638)中用于进行错误检测;

在igmp_send_report()(位于net/ipv4/igmp.c,line195)的最后也经过了这个hook,进行多播时相关的处理。

  这样,iptables模块就可以利用这个hook对应的output规则链表来对数据报进行规则匹配的筛选了。

conntrack(-200)、mangle(-150)、dnat(-100)、filter(0)

  nF_ip_post_Routing(4)

  所有数据报,包括源地址为本地主机和非本地主机的,在通过网络设备离开本地主机之前,在ip数据报发送函数ip_finish_output()(位于net/ipv4/ip_output.c,line184)的最后经过这个hook。

  经过这个hook处理后,数据报进入ip_finish_output2()(位于

  net/ipv4/ip_output.c,line160)另外,在函数ip_mc_output()(位于

  net/ipv4/ip_output.c,line195)中在克隆新的网络缓存skb时,也经过了这个hook进行处理。

mangle(-150)、snat(100)、conntrack(int_max)

  其中,入口为net_rx_action()(位于net/core/dev.c,line1602),作用是将数据报一个个地从cpu的输入队列中拿出,然后传递给协议处理例程。

  出口为dev_queue_xmit()(位于net/core/dev.c,line1035),这个函数被高层协议的实例使用,以数据结构structsk_buff*skb的形式在网络设备上发送数据报。

  2.hook的调用

  hook的调用是通过宏nF_hook实现的,其定义位于

  include/linux/netfilter.h,line122:

  #definenF_hook(pf,hook,skb,indev,outdev,okfn)/

  (list_empty(/*userid*/

  structlist_headlist;

  }

  3.

  针对上述user_queue链表,

  要求以队列方式向其中依次添加10个类型为structuser的宿主节点,并要求这10个宿主节点的id依次为1-10

  4.依次遍历输出这10个宿主节点的id

  5.从队列中删除首个宿主节点,然后依次遍历该队列并输出余下

  各宿主节点的id值

  四、

  实现原理

  linux的内核源文件list.h提供了所有的链表定义、各类操作接口及其实现。

其中

  创建链表的方法如下:

  list_head(my_list);

  内核源文件list.h中定义了以下若干接口,用于对通用链表进行各类操作:

  1)

  在指定的head后插入新节点,常用于堆栈数据结构的实现//@new:

即将添加的新链表节点

  //@head:

在此节点后添加

  list_add(structlist_head*new,structlist_head*head);

  2)

  在指定的head前插入新节点,常用于队列数据结构的实现//@new:

在此节点前添加

  list_add_tail(structlist_head*new,structlist_head*head)3)

  从链表中删除一个指定节点

  //@entry:

要从链表中删除的链表节点

  list_del(structlist_head*entry)

  4)

  根据当前链表节点指针ptr获得宿主节点指针

  //*@ptr:

  structlist_head类型的指针

  //*@type:

链表节点所在的宿主节点的类型

  //*@member:

嵌入宿主的链表节点的变量名

  list_entry(ptr,type,member)

  5)

  遍历链表

  //@pos:

遍历链表时用于指示正在遍历的链表节点的指针//@head:

链表头

  list_for_each(pos,head)

  五、

  实现代码和运行结果

  #include

  #include"

list.h"

  list_head(user_quene);

  intmain()

  {

  structuseruid[10];

  structlist_head*pos;

  inti;

  for(i=0;

i  list_add_tail(

  uid[i].id=i+1;

  list_for_each(pos,

  printf("

\n"

);

  list_del(

  return0;

  }structuser{intid;

/*userid*/structlist_headlist;

};

  实验二、

  实验项目名称:

一、

  实验目的和要求:

  学习linux内核的通用哈希链表的设计原理,

  熟练掌握linux内核通用哈希链表的使用。

  二、

  实验内容

  1.掌握linux通用哈希链表的创建

  2.掌握通用哈希表增加元素、查找元素的方法。

  三、

  实验要求

  待创建的哈希表头数组为structhlist_headuser_hash[16],要求对哈希表宿主元素的

  name成员的值进行散列,并将散列值作为哈希表宿主元素的key。

  2.

  作为哈希表元素的宿主节点类型定义如下:

  structusermap{

  structhlist_nodehlist;

  unsignedcharname[8];

  };

  针对上述user_hash哈希表,

  要求向其中添加3个类型为structusermap的宿主元素,并要求这3个宿主元素的name成员分别为"

smith"

"

john"

bob"

  4.

  向哈希表user_hash中添加第4个宿主元素。

若新宿主元素的name成员已经存在

  (例如"

  ,则提示已经存在该用户,否则向哈希表中添加该宿主元素。

四、

  linux的内核源文件list.h提供了哈希表各类操作接口及其实现。

其中创建具有16

  个key值的哈希表的方法如下:

  structhlist_headuser_hash[16];

  在上述user_hash数组的16个元素中存放的哈希表头元素定义如下:

  structhlist_head{

  structhlist_node*first;

  哈希表节点元素定义如下:

  structhlist_node{

  structhlist_node*next,**pprev;

  本实验对哈希表宿主元素节点的name值进行散列的算法如下:

  unsignedintbkdRhash(unsignedchar*str)

  unsignedintseed=131;

  unsignedinthash=0;

  while(*str){

  hash=hash*seed+(*str++);

  return(hash

  //返回此*str所对应的哈希值

  于是,本实验中对一个字符串name求最终哈希值hash的方法如下:

  unsignedinthash=bkdRhash(name)*prev;

  内核把sk_buff组织成为双向链表,为了每个skb能被头部快速找到,在第一个skb节点的前面会插入另一个辅助的sk_buff_head结构的头结点。

  structsk_buff_head{

__u32qlen;

//skb链表的节点数,队列长度/*thesetwomembersmustbefirst.*/structsk_buffstructsk_buff*next;

*prev;

spinlock_tlock;

//对链表并发操作需要自旋锁

  数据存储相关

  structsock*sk;

  skb的宿主传输控制块。

skb在由本地产生或者本地接收的时候才有效。

当skb在2层或者3层转发的时候,没有意义,null。

  unsignedint

  len,mac_len,data_lenlen:

skb中数据部分的长度。

mac_len:

以太帧首部长度data_len:

sg类型和FRaglist类型聚合分散i/o存储区中的数据长度。

  users;

atomic_t

  引用计数,标识有多少个实体在使用skb,以此来确定释放skb的时机。

  truesize;

unsignedint

  skb的实际长度,包括skb描述符和数据缓存区的长度。

如果申请了一个len字节的缓存区,alloc_skb()会将truesize初始化成len+sizeof(sk_buff)unsignedchar

  *head,*data,*tail,*end;

  发送数据时,每一层协议会在head与data之间填充协议首部。

  通用的成员变量

  structskb_timeval

  tstamp;

接收时间戳或者发送时间戳,一般在网络设备收到数据包以后通过netif_receive_skb()调用net_timestamp()进行设置

  structnet_device*dev;

  网络设备指针,该字段的设置与skb是发送包还是接收包有关。

在初始化网络设备驱动的时候会分配接受缓存队列,将该指针指向接收到数据包的网络设备。

  发送数据包时这个字段的设置要复杂的多,见后面。

linux支持虚拟网络设备,dev可能会指向虚拟网络设备。

数据包在输入或者输出的时候dev的指针可能会在包处理过程中被改变。

  structnet_device*input_dev;

  接收报文最原始的设备,本地生成为null。

  union{}h、union{}nh、union{}mac

  分别指向四层、三层、二层协议的首部,联合体内表示能解析的协议。

报文从二层向三层传递时指针的变化:

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1