Linux连接跟踪源码分析报告.docx

上传人:b****6 文档编号:7053093 上传时间:2023-01-16 格式:DOCX 页数:40 大小:37.45KB
下载 相关 举报
Linux连接跟踪源码分析报告.docx_第1页
第1页 / 共40页
Linux连接跟踪源码分析报告.docx_第2页
第2页 / 共40页
Linux连接跟踪源码分析报告.docx_第3页
第3页 / 共40页
Linux连接跟踪源码分析报告.docx_第4页
第4页 / 共40页
Linux连接跟踪源码分析报告.docx_第5页
第5页 / 共40页
点击查看更多>>
下载资源
资源描述

Linux连接跟踪源码分析报告.docx

《Linux连接跟踪源码分析报告.docx》由会员分享,可在线阅读,更多相关《Linux连接跟踪源码分析报告.docx(40页珍藏版)》请在冰豆网上搜索。

Linux连接跟踪源码分析报告.docx

Linux连接跟踪源码分析报告

Linux连接跟踪源码分析

IPConnectiontracking

连接跟踪用来跟踪和记录连接状态,是netfilter的一部份,也是通过在hook点上注册相应的结构来工作的。

无论是发送,接收,还是转发的数据包,都要经过两个conntrack模块。

第一个conntrack点的优先级是最高的,所有数据包进入netfilter后都会首先被它处理,其作用是创建ip_conntrack结构。

而最后一个conntrack的优先级最低,总是在数据包离开netfilter之前做最后的处理,它的作用是将该数据包的连接跟踪结构添加到系统的连接状态表中

1.ip_conntarck结构ip_conntrack.h

内核中用一个ip_conntrack结构来描述一个连接的状态

structip_conntrack

{

/*nf_conntrack结构定义于include/linux/skbuff.h,Line89,其中包括一个计数器use和一个destroy函数。

计数器use对本连接记录的公开引用次数进行计数*/

structnf_conntrackct_general;

/*其中的IP_CT_DIR_MAX是一个枚举类型ip_conntrack_dir(位于include/linux/netfilter_ipv4/ip_conntrack_tuple.h,Line65)的第3个成员,从这个结构实例在源码中的使用看来,实际上这是定义了两个tuple多元组的hash表项tuplehash[IP_CT_DIR_ORIGINAL/0]和tuplehash[IP_CT_DIR_REPLY/1],利用两个不同方向的tuple定位一个连接,同时也可以方便地对ORIGINAL以及REPLY两个方向进行追溯*/

structip_conntrack_tuple_hashtuplehash[IP_CT_DIR_MAX];

/*这是一个位图,是一个状态域。

在实际的使用中,它通常与一个枚举类型ip_conntrack_status(位于include/linux/netfilter_ipv4/ip_conntrack.h,Line33)进行位运算来判断连接的状态。

其中主要的状态包括:

IPS_EXPECTED(_BIT),表示一个预期的连接

IPS_SEEN_REPLY(_BIT),表示一个双向的连接

IPS_ASSURED(_BIT),表示这个连接即使发生超时也不能提早被删除

IPS_CONFIRMED(_BIT),表示这个连接已经被确认(初始包已经发出)*/

unsignedlongstatus;

/*其类型timer_list位于include/linux/timer.h,Line11,其核心是一个处理函数。

这个成员表示当发生连接超时时,将调用此处理函数*/

structtimer_listtimeout;

/*所谓“预期的连接”的链表,其中存放的是我们所期望的其它相关连接*/

structlist_headsibling_list;

/*目前的预期连接数量*/

unsignedintexpecting;

/*结构ip_conntrack_expect位于ip_conntrack.h,这个结构用于将一个预期的连接分配给现有的连接,也就是说本连接是这个master的一个预期连接*/

structip_conntrack_expect*master;

/*helper模块。

这个结构定义于ip_conntrack_helper.h,这个模块提供了一个可以用于扩展Conntrack功能的接口。

经过连接跟踪HOOK的每个数据报都将被发给每个已经注册的helper模块(注册以及卸载函数分别为ip_conntrack_helper_register()以及ip_conntrack_helper_unregister(),分别位于ip_conntrack_core.c)。

这样我们就可以进行一些动态的连接管理了*/

structip_conntrack_helper*helper;

/*一系列的nf_ct_info类型(定义于include/linux/skbuff.h,Line92,实际上就是nf_conntrack结构)的结构,每个结构对应于某种状态的连接。

这一系列的结构会被sk_buff结构的nfct指针所引用,描述了所有与此连接有关系的数据报。

其状态由枚举类型ip_conntrack_info定义(位于include/linux/netfilter_ipv4/ip_conntrack.h,Line12)共有5个成员:

IP_CT_ESTABLISHED:

数据报属于已经完全建立的连接

IP_CT_RELATED:

数据报属于一个新的连接,但此连接与一个现有连接相关(预期连接);或者是ICMP错误

IP_CT_NEW:

数据报属于一个新的连接

IP_CT_IS_REPLY:

数据报属于一个连接的回复

IP_CT_NUMBER:

不同IP_CT类型的数量,这里为7,NEW仅存于一个方向上*/

structnf_ct_infoinfos[IP_CT_NUMBER];

/*为其他模块保留的部分*/

unionip_conntrack_protoproto;

unionip_conntrack_helphelp;

#ifdefCONFIG_IP_NF_NAT_NEEDED

struct{

structip_nat_infoinfo;

unionip_conntrack_nat_helphelp;

#ifdefined(CONFIG_IP_NF_TARGET_MASQUERADE)||\

defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)

intmasq_index;

#endif

#ifdefined(CONFIG_IP_NF_RTSP)||defined(CONFIG_IP_NF_RTSP_MODULE)

structip_nat_rtsp_infortsp_info;

#endif

}nat;

#endif/*CONFIG_IP_NF_NAT_NEEDED*/

#ifdefined(CONFIG_IP_NF_CONNTRACK_MARK)

unsignedlongmark;

#endif

};

structip_conntrack_tuple_hash结构描述链表中的节点,这个数组包含“初始”和“应答”两个成员(tuplehash[IP_CT_DIR_ORIGINAL]和tuplehash[IP_CT_DIR_REPLY]),所以,当一个数据包进入连接跟踪模块后,先根据这个数据包的套接字对转换成一个“初始的”tuple,赋值给tuplehash[IP_CT_DIR_ORIGINAL],然后对这个数据包“取反”,计算出“应答”的tuple,赋值给tuplehash[IP_CT_DIR_REPLY],这样,一条完整的连接已经跃然纸上了。

enumip_conntrack_dir

{

IP_CT_DIR_ORIGINAL,

IP_CT_DIR_REPLY,

IP_CT_DIR_MAX

};

 

2.连接跟踪表

Netfilter用“来源地址/来源端口+目的地址/目的端口”,即一个“tuple”,来唯一标识一个连接。

用一张连接跟踪表来描述所有的连接状态,该表用了hash算法。

hash表用一个全局指针来描述(ip_conntrack_core.c)

structlist_head*ip_conntrack_hash;

表的大小,即hash节点的个数由ip_conntrack_htable_size全局变量决定,默认是根据内存计算出来的。

而每个hash节点又是一条链表的首部,所以,连接跟踪表就是一个由ip_conntrack_htable_size条链表构成的一个hash表,整个连接跟踪表大小使用全局变量ip_conntrack_max描述,与hash表的关系是ip_conntrack_max=8*ip_conntrack_htable_size。

链表的每个节点,都是一个ip_conntrack_tuple_hash结构:

structip_conntrack_tuple_hash

{

/*用来组织链表*/

structlist_headlist;

/*用来描述一个tuple*/

structip_conntrack_tupletuple;

/*this==&ctrack->tuplehash[DIRECTION(this)].*/

structip_conntrack*ctrack;

};

实际描述一个tuple的是ip_conntrack_tuple结构ip_conntrack_tuple.h

structip_conntrack_tuple

{

/*源*/

structip_conntrack_manipsrc;

/*Thesearethepartsofthetuplewhicharefixed.*/

struct{

/*目的地址*/

u_int32_tip;

union{

/*Addotherprotocolshere.*/

u_int64_tall;

struct{

u_int16_tport;

}tcp;

struct{

u_int16_tport;

}udp;

struct{

u_int8_ttype,code;

}icmp;

struct{

u_int16_tprotocol;

u_int8_tversion;

u_int32_tkey;

}gre;

struct{

u_int16_tspi;

}esp;

}u;

/*协议类型*/

u_int16_tprotonum;

}dst;

};

对于所有IP协议,协议类型、源地址、目的地址这三个参数是识别连接所必须的,具体到各个协议,就要提取出各协议的唯一特征数据,如TCP、UDP的源端口、目的端口,ICMP的ID、TYPE、CODE等值,这些值就是tuple结构要处理的数据。

各协议相关数据是以联合(union)形式定义在tuple结构中的,netfilter缺省支持TCP、UDP和ICMP协议,如果还要支持其他IP协议,如GRE、ESP、AH、SCTP等,需要在联合中添加相应的协议参数值。

ip_conntrack_manip和ip_conntrack_manip_protoip_conntrack_tuple.h

structip_conntrack_manip

{

u_int32_tip;

unionip_conntrack_manip_protou;

};

unionip_conntrack_manip_proto

{

/*Addotherprotocolshere.*/

u_int32_tall;

struct{

u_int16_tport;

}tcp;

struct{

u_int16_tport;

}udp;

struct{

u_int16_tid;

}icmp;

struct{

u_int32_tkey;

}gre;

struct{

u_int16_tspi;

}esp;

};

Netfilter将每一个数据包转换成tuple,再根据tuple计算出hash值,这样,就可以使用ip_conntrack_hash[hash_id]找到hash表中链表的入口,并组织链表;找到hash表中链表入口后,如果链表中不存在此“tuple”,则是一个新连接,就把tuple插入到链表的合适位置;两个节点tuple[ORIGINAL]和tuple[REPLY]虽然是分开的,在两个链表当中,但是如前所述,它们同时又被封装在ip_conntrack结构的tuplehash数组中

 

3.       连接跟踪初始化

初始化函数init()调用init_or_cleanup

(1)函数ip_conntrack_standalone.c

staticint__initinit(void)

{

returninit_or_cleanup

(1);

}

3.1init_or_cleanup()函数

intinit_or_cleanup函数,(ip_conntrack_standalone.c)参数为1则执行init,为0则执行clean,它主要做三件工作:

1.     调用ip_conntrack_init()初始化连接跟踪表的相关变量,见3.2

2.     初始化proc文件系统节点

3.     为连接跟踪注册hook

staticintinit_or_cleanup(intinit)

{

structproc_dir_entry*proc;

intret=0;

if(!

init)gotocleanup;

/*初始化连接跟踪的一些变量和数据结构,如连接跟踪表的大小,Hash表的大小等*/

ret=ip_conntrack_init();

if(ret<0)

gotocleanup_nothing;

/*初始化proc文件系统*/

proc=proc_net_create("ip_conntrack",0440,list_conntracks);

proc=proc_net_create("ip_clear_dnsconntrack",0644,clear_dns_conntracks);

if(!

proc)gotocleanup_init;

proc->owner=THIS_MODULE;

/*为连接跟踪注册hook,一共六个,所在的hook点、注册的hook函数和优先级分别如下(和最开始的图是一致的):

NF_IP_PRE_ROUTING:

ip_conntrack_defragNF_IP_PRI_CONNTRACK_DEFRAG

ip_conntrack_inNF_IP_PRI_CONNTRACK

NF_IP_LOCAL_OUT:

ip_conntrack_defragNF_IP_PRI_CONNTRACK_DEFRAG

ip_conntrack_localNF_IP_PRI_CONNTRACK

NF_IP_POST_ROUTING:

ip_refragNF_IP_PRI_LAST

NF_IP_LOCAL_IN:

ip_confirmNF_IP_PRI_LAST-1

优先级的顺序为:

NF_IP_PRI_FIRST(最高)

NF_IP_PRI_CONNTRACK_DEFRAG

NF_IP_PRI_CONNTRACK

NF_IP_PRI_MANGLE

NF_IP_PRI_NAT_DST

NF_IP_PRI_FILTER

NF_IP_PRI_NAT_SRC

NF_IP_PRI_LAST(最低)

我们知道,LOCAL_OUT和PRE_ROUTING点可以看作是netfilter的入口,而POST_ROUTING和LOCAL_IN可以看作是出口。

也就是说,在每个数据包刚一进入netfilter之后首先都会调用ip_conntrack_defrag做分片处理,紧接着就是对收到的和发出的数据包分别进行ip_conntrack_in和ip_conntrack_loacl(ip_conntrack_loacl里还是调用了ip_conntrack_in)。

而在数据包即将离开netfilter之前,会对进入主机的数据包进行ip_confirm处理,对发出的数据包进行ip_refrag处理(ip_refrag里也会调用ip_confirm)。

这就是整个连接跟踪模块在netfilter中的分布情况。

另外,我们分析的是2.6.8的内核,在linux2.6.12中,这个地方还增加了两个hook,分别是ip_conntrack_helper_out_ops和ip_conntrack_helper_in_ops。

将helper模块相关的处理提前了。

*/

ret=nf_register_hook(&ip_conntrack_defrag_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterpre-routingdefraghook.\n");

gotocleanup_proc;

}

ret=nf_register_hook(&ip_conntrack_defrag_local_out_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterlocal_outdefraghook.\n");

gotocleanup_defragops;

}

ret=nf_register_hook(&ip_conntrack_in_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterpre-routinghook.\n");

gotocleanup_defraglocalops;

}

ret=nf_register_hook(&ip_conntrack_local_out_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterlocalouthook.\n");

gotocleanup_inops;

}

ret=nf_register_hook(&ip_conntrack_out_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterpost-routinghook.\n");

gotocleanup_inandlocalops;

}

ret=nf_register_hook(&ip_conntrack_local_in_ops);

if(ret<0){

printk("ip_conntrack:

can'tregisterlocalinhook.\n");

gotocleanup_inoutandlocalops;

}

#ifdefCONFIG_SYSCTL

ip_ct_sysctl_header=register_sysctl_table(ip_ct_net_table,0);

if(ip_ct_sysctl_header==NULL){

printk("ip_conntrack:

can'tregistertosysctl.\n");

gotocleanup;

}

#endif

returnret;

cleanup:

#ifdefCONFIG_SYSCTL

unregister_sysctl_table(ip_ct_sysctl_header);

#endif

nf_unregister_hook(&ip_conntrack_local_in_ops);

cleanup_inoutandlocalops:

nf_unregister_hook(&ip_conntrack_out_ops);

cleanup_inandlocalops:

nf_unregister_hook(&ip_conntrack_local_out_ops);

cleanup_inops:

nf_unregister_hook(&ip_conntrack_in_ops);

cleanup_defraglocalops:

nf_unregister_hook(&ip_conntrack_defrag_local_out_ops);

cleanup_defragops:

nf_unregister_hook(&ip_conntrack_defrag_ops);

cleanup_proc:

proc_net_remove("ip_conntrack");

proc_net_remove("ip_clear_dnsconntrack");

cleanup_init:

ip_conntrack_cleanup();

cleanup_nothing:

returnret;

}

 

3.2ip_conntrack_init()函数

ip_conntrack_init函数(ip_conntrack_core.c)用于初始化连接跟踪的包括hash表相关参数在内一些重要的变量:

int__initip_conntrack_init(void)

{

unsignedinti;

intret;

/*Ideafromtcp.c:

use1/16384ofmemory.Oni386:

32MB

*machinehas256buckets.>=1GBmachineshave8192buckets.*/

/*如果指定hash表的大小则用制定值,否则根据内存计算*/

if(hashsize){

ip_conntrack_htable_size=hashsize;

}else{

ip_conntrack_htable_size

=(((num_physpages<

/sizeof(structlist_head));

if(num_physpages>(1024*1024*1024/PAGE_SIZE))

ip_conntrack_htable_size=8192;

if(ip_conntrack_htable_size<16)

ip_conntrack_htable_size=16;

}

ip_conntrack_max=8*ip_conntrack_htable_size;

#ifdefCONFIG_MIPS_BRCM

ip_conntrack_max=0;

#endif

printk("ip_conntrackversion%s(%ubuckets,%dmax)"

"-%Zdbytesperconntrack\n",IP_CONNTRACK_VERSION,

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

当前位置:首页 > 幼儿教育 > 幼儿读物

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

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