注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

BCB-DG's Blog

...

 
 
 

日志

 
 

Linux Netfilter 分析五  

2013-10-04 15:27:30|  分类: Linux |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
//轉

3. 连接跟踪的实现

    有了以上的数据结构,连接跟踪的具体实现其实就非常简单而常规了,无非就是初始化、连接记录的创建、在连接跟踪hash表中搜索并定位数据报、将数据报转 换为一个多元组、判断连接的状态以及方向、超时处理、协议的添加、查找和注销、对不同协议的不同处理、以及在两个连接跟踪相关的HOOK上对数据报的处理 等。

    下面重点说明一下我在分析中遇到的几个比较重要或者比较难理解的地方:
所谓“预期链接”
        可以将预期连接看作父子关系来理解,如图
http://blog.chinaunix.net/photo/24896_061206192612.jpg
ip_conntrack的状态转换
        ip_conntrack的状态转换分两种,同样用图来描述。首先是正常的状态转换,如图
http://blog.chinaunix.net/photo/24896_061206192631.jpg
然后是ICMP error时的状态转换(由函数icmp_error_track()来判断,位于net/ipv4/netfilter/ip_conntrack_core.c,Line495),如图
http://blog.chinaunix.net/photo/24896_061206192648.jpg
在NF_IP_PRE_ROUTING上对分片IP数据报的处理
    在经过HOOK中的NF_IP_PRE_ROUTING时(函数ip_conntrack_in(),位于net/ipv4/netfilter /ip_conntrack_core.c,Line796),由于外来的数据报有可能是经过分片的,所以必须对分片的情形进行处理,将IP数据报组装后 才能分配给连接。
    具体的操作是首先由函数ip_ct_gather_frags()对分片的数据报进行收集,然后调用ip_defrag()函数(位于net/ipv4/ip_fragment.c,Line632)组装之
4. 协议的扩展

    由于我们可能要添加新的协议,所以单独对协议的扩展进行分析。

    各种协议使用一个全局的协议列表存放,即protocol_list(位于include/linux/netfilter_ipv4 /ip_conntrack_core.h,Line21),使用结构ip_conntrack_protocol(位于include/linux /netfilter_ipv4/ip_conntrack_protocol.h,Line6)来表示:

struct ip_conntrack_protocol

{

struct list_head list;

u_int8_t proto; //协议号

const char *name;

int (*pkt_to_tuple)(const void *datah, size_t datalen,

struct ip_conntrack_tuple *tuple);

int (*invert_tuple)(struct ip_conntrack_tuple *inverse,

const struct ip_conntrack_tuple *orig);

unsigned int (*print_tuple)(char *buffer,

const struct ip_conntrack_tuple *);

unsigned int (*print_conntrack)(char *buffer,

const struct ip_conntrack *);

int (*packet)(struct ip_conntrack *conntrack,

struct iphdr *iph, size_t len,

enum ip_conntrack_info ctinfo);

int (*new)(struct ip_conntrack *conntrack, struct iphdr *iph,

size_t len);

void (*destroy)(struct ip_conntrack *conntrack);

int (*exp_matches_pkt)(struct ip_conntrack_expect *exp,

struct sk_buff **pskb);

struct module *me;

};

    其中重要成员:

`int (*pkt_to_tuple)(……)`:其指向函数的作用是将协议加入到ip_conntrack_tuple的dst子结构中

`int (*invert_tuple)(……)`:其指向函数的作用是将源和目的多元组中协议部分的值进行互换,包括IP地址、端口等

`unsigned int (*print_tuple)(……)`:其指向函数的作用是打印多元组中的协议信息

`unsigned int (*print_conntrack)(……)`:其指向函数的作用是打印整个连接记录

`int (*packet)(……)`:其指向函数的作用是返回数据报的verdict值

`int (*new)(……)`:当此协议的一个新连接发生时,调用其指向的这个函数,调用返回true时再继续调用packet()函数

`int (*exp_matches_pkt)(……)`:其指向函数的作用是判断是否有数据报匹配预期的连接

    添加/删除协议使用的是函数ip_conntrack_protocol_register()以及 ip_conntrack_protocol_unregister(),分别位于net/ipv4/netfilter /ip_conntrack_standalone.c,Line298 & 320,其工作就是将ip_conntrack_protocol添加到全局协议列表protocol_list。
七、网络地址转换模块(Network Address Translation)
1. 概述

    网络地址转换的机制一般用于处理IP地址转换,在Netfilter中,可以支持多种NAT类型,而其实现的基础是连接跟踪。

        NAT可以分为SNAT和DNAT,即源NAT和目的NAT,在Netfilter中分别基于以下HOOK:

NF_IP_PRE_ROUTING:可以在这里定义DNAT的规则,因为路由器进行路由时只检查数据报的目的IP地址,所以为了使数据报得以正确路由,我们必须在路由之前就进行DNAT

NF_IP_POST_ROUTING:可以在这里定义SNAT的规则,系统在决定了数据报的路由以后在执行该HOOK上的规则

NF_IP_LOCAL_OUT:定义对本地产生的数据报的DNAT规则

CONFIG_IP_NF_NAT_LOCAL定义后,NF_IP_LOCAL_IN上也可以定义DNAT规则。

    同时,MASQUERADE(伪装)是SNAT的一种特例,它与SNAT几乎一样,只有一点不同:如果连接断开,所有的连接跟踪信息将被丢弃,而去使用重 新连接以后的IP地址进行IP伪装;而REDIRECT(重定向)是DNAT的一种特例,这时候就相当于将符合条件的数据报的目的IP地址改为数据报进入 系统时的网络接口的IP地址。
2. 基于连接跟踪的相关数据结构

    NAT是基于连接跟踪实现的,NAT中所有的连接都由连接跟踪模块来管理,NAT模块的主要任务是维护nat表和进行实际的地址转换。这样,我们来回头重新审视一下连接跟踪模块中由条件编译决定的部分。

    首先,是连接的描述ip_conntrack,在连接跟踪模块部分中提到,这个结构的最后有“为NAT模块设置的信息”,即:

#ifdef CONFIG_IP_NF_NAT_NEEDED

struct {

struct ip_nat_info info;

union ip_conntrack_nat_help help;

#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || /

defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)

int masq_index;

#endif

} nat;

#endif /* CONFIG_IP_NF_NAT_NEEDED */

这是一个叫做nat的子结构,其中有3个成员:

一个ip_nat_info结构,这个结构下面会具体分析

一个ip_conntrack_nat_help结构,是一个空结构,为扩展功能而设

一个为伪装功能而设的index,从源码中对这个变量的使用看来,是对应所伪装网络接口的ID,也就是net_device中的ifindex成员


    好,下面我们来看一下这个ip_nat_info结构,这个结构存储了连接中的地址绑定信息,其定义位于include/linux/netfilter_ipv4/ip_nat.h,Line98:

struct ip_nat_info

{

int initialized;

unsigned int num_manips;

struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS];

const struct ip_nat_mapping_type *mtype;

struct ip_nat_hash bysource, byipsproto;

struct ip_nat_helper *helper;

struct ip_nat_seq seq[IP_CT_DIR_MAX];

};

`int initialized;`:这是一个位图,表明源地址以及目的地址的地址绑定是否已被初始化

`unsigned int num_manips;`:这个成员指定了存放在下面的manip数组中的可执行操作的编号,在不同的HOOK以及不同的方向上,可执行操作是分别进行计数的。

`struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS];`:ip_nat_info_manip结构定义于include/linux /netfilter_ipv4/ip_nat.h,Line66,一个ip_nat_info_manip结构对应着一个可执行操作或地址绑定,其成员 包括方向(ORIGINAL以及REPLY)、HOOK号、操作类型(由一个枚举类型ip_nat_manip_type定义,有 IP_NAT_MANIP_SRC和IP_NAT_MANIP_DST两种)以及一个ip_conntrack_manip结构

`const struct ip_nat_mapping_type *mtype;`:ip_nat_mapping_type这个结构在整个内核源码中都没有定义,根据注释来看应该也是一个预留的扩展,一般就是NULL

`struct ip_nat_hash bysource, byipsproto;`:ip_nat_hash结构定义于include/linux/netfilter_ipv4 /ip_nat.h,Line89,实际上就是一个带表头的ip_conntrack结构,跟连接跟踪中hash表的实现类似。其中,

bysource表是用来管理现有连接的

byipsproto表则管理已经完成的转换映射,以保证同一个IP不会同时有两个映射,避免地址转换冲突

`struct ip_nat_helper *helper;`:扩展用

`struct ip_nat_seq seq[IP_CT_DIR_MAX];`:这是为每一个方向(其实就两个方向)记录一个序列号。ip_nat_seq结构定义于 include/linux/netfilter_ipv4/ip_nat.h,Line33,这个结构用得并不多,应该是用于TCP连接的计数和对涉及 TCP的修改的定位

  评论这张
 
阅读(601)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017