`

2.6.17中ip_nat_info结构的变化

阅读更多
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

1. 前言
struct ip_nat_info结构是连接结构struct ip_conntrack在NAT功能打开的情况下的直接组成部分,非指针,在2.4和2.6.17中差异变化较大,本文分析其变化后的使用情况。
以下代码版本2.4的是2.4.26,2.6的是2.6.17.11。
2. 结构变化
/* include/linux/netfilter_ipv4/ip_nat.h */
2.4.26:
/* The structure embedded in the conntrack structure. */
struct ip_nat_info
{
    /* Set to zero when conntrack created: bitmask of maniptypes */
    int initialized;
   
    unsigned int num_manips;
   
    /* Manipulations to be done on this conntrack. */
    struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS];
   
    /* The mapping type which created us (NULL for null mapping). */
    const struct ip_nat_mapping_type *mtype;
   
    struct ip_nat_hash bysource, byipsproto;
    /* Helper (NULL if none). */
    struct ip_nat_helper *helper;
    struct ip_nat_seq seq[IP_CT_DIR_MAX];
};
 
2.6.17.11:
struct ip_nat_info
{
 struct list_head bysource;
 struct ip_nat_seq seq[IP_CT_DIR_MAX];
};
两个结构差异巨大,但明显新结构大小比以前的小了很多。
3. 差异分析
3.1 initialized
在新结构中已经没有了initalized参数,该参数原先是用来检测数据包是否进行过某类NAT操作了,包括(SNAT、DNAT),新版中没有了此参数,但提供了以下函数来完成同样的功能,也就是实际上这些信息已经包含在连接结构的status参数中:
/* include/linux/netfilter_ipv4/ip_conntrack.h */
static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
         enum ip_nat_manip_type manip)
{
 if (manip == IP_NAT_MANIP_SRC)
  return test_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
 return test_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
}

3.2 bysource
bysource既是ip_nat_info结构中的参数,它其实只是用于挂接链表;同名的还有一个静态的全局变量,是个动态分配HASH数组指针,数组中每个元素表示一个连接链表,先看看这个参数记录的是什么样的连接:
分配:
/* net/ipv/netfilter/ip_nat_core.c */
static int __init ip_nat_init(void)
{
......
 bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
 if (!bysource)
  return -ENOMEM;
......
bysource这个数组大小和连接HASH数组大小是一样的

元素增加:
unsigned int
ip_nat_setup_info(struct ip_conntrack *conntrack,
    const struct ip_nat_range *range,
    unsigned int hooknum)
{
......
 int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
......
 if (have_to_hash) {
  unsigned int srchash
   = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
          .tuple);
  write_lock_bh(&ip_nat_lock);
  list_add(&info->bysource, &bysource[srchash]);
  write_unlock_bh(&ip_nat_lock);
 }
......
也就是说加入此HASH数组中的连接是那些还没有进行任何NAT设置(包括SNAT和DNAT)的连接,也就是新连接,因此这个HASH数组中的元素个数和连接数应该是相同的,但不占用新的内存。
而struct ip_nat_info中的bysource参数就是链表的连接指针。

元素删除:
链表元素的删除是由以下函数完成的:
static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
{
 if (!(conn->status & IPS_NAT_DONE_MASK))
  return;
 write_lock_bh(&ip_nat_lock);
 list_del(&conn->nat.info.bysource);
 write_unlock_bh(&ip_nat_lock);
}
这个函数实际就是ip_conntrack_destroyed:
 ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
而ip_conntrack_destroyed函数又是在destroy_conntrack(struct nf_conntrack *nfct)时调用的,也就是在连接删除的时候才删除。
3.3 manips
2.6.17中一个最明显的变化就是struct ip_nat_info_manip结构消失了,struct ip_nat_info中也没有了相应2.4中的结构参数:struct ip_nat_info_manip manips[IP_NAT_MAX_MANIPS]。2.4中这些参数是用来描述进行NAT的操作类型以及变化前后的IP地址信息和传输层参数信息等。现在既然在2.6.17中没有了这个参数,netfilter又是如何查找NAT修改后信息的呢?这需要从函数ip_nat_setup_info()说起。

因为无论是SNAT还是DNAT规则都要调用ip_nat_setup_info()函数
unsigned int
ip_nat_setup_info(struct ip_conntrack *conntrack,
    const struct ip_nat_range *range,
    unsigned int hooknum)
{
 struct ip_conntrack_tuple curr_tuple, new_tuple;
 struct ip_nat_info *info = &conntrack->nat.info;
 int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
 enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
       || hooknum == NF_IP_POST_ROUTING
       || hooknum == NF_IP_LOCAL_IN
       || hooknum == NF_IP_LOCAL_OUT);
 BUG_ON(ip_nat_initialized(conntrack, maniptype));
 /* What we've got will look like inverse of reply. Normally
    this is what is in the conntrack, except for prior
    manipulations (future optimization: if num_manips == 0,
    orig_tp =
    conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
// 通过连接反方向的tuple获取连接正方向的tuple值存到curr_tuple中,
// 也就是NAT转换前的tuple
 invert_tuplepr(&curr_tuple,
         &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
// 获取地址转换后的新的tuple值到new_tuple中,已经包括了传输层上的转换
 get_unique_tuple(&new_tuple, &curr_tuple, range, conntrack, maniptype);
// 检查转换前后的tuple值是否相同,new_tuple是NAT后的新的原始方向的tuple
 if (!ip_ct_tuple_equal(&new_tuple, &curr_tuple)) {
// 不同,进行NAT转换
  struct ip_conntrack_tuple reply;
  /* Alter conntrack table so will recognize replies. */
// 获取转换后的连接响应方向的tuple值到reply中
  invert_tuplepr(&reply, &new_tuple);
// 修改连接中的响应方向的tuple值
// 即conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = reply
  ip_conntrack_alter_reply(conntrack, &reply);
  /* Non-atomic: we own this at the moment. */
// 设置NAT操作标志
  if (maniptype == IP_NAT_MANIP_SRC)
   conntrack->status |= IPS_SRC_NAT;
  else
   conntrack->status |= IPS_DST_NAT;
 }
 /* Place in source hash if this is the first time. */
// 连接到基于起始方向源IP的HASH链表中
 if (have_to_hash) {
  unsigned int srchash
   = hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
          .tuple);
  write_lock_bh(&ip_nat_lock);
  list_add(&info->bysource, &bysource[srchash]);
  write_unlock_bh(&ip_nat_lock);
 }
// 在连接的状态值中设置源或目的NAT完成标志
 /* It's done. */
 if (maniptype == IP_NAT_MANIP_DST)
  set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
 else
  set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
 return NF_ACCEPT;
}
由此可见,连接中tuple值中记录了转换前后的参数,因此在进行NAT修改的函数ip_nat_packet()函数中就直接利用tuple 中的值进行修改了,不需要再用ip_nat_info_manip结构记录转换前后的地址端口信息。优点是减少了内存消耗,也比较直观。
/* Do packet manipulations according to ip_nat_setup_info. */
unsigned int ip_nat_packet(struct ip_conntrack *ct,
      enum ip_conntrack_info ctinfo,
      unsigned int hooknum,
      struct sk_buff **pskb)
{
 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 unsigned long statusbit;
 enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
 if (mtype == IP_NAT_MANIP_SRC)
  statusbit = IPS_SRC_NAT;
 else
  statusbit = IPS_DST_NAT;
 /* Invert if this is reply dir. */
 if (dir == IP_CT_DIR_REPLY)
  statusbit ^= IPS_NAT_MASK;
 /* Non-atomic: these bits don't change. */
 if (ct->status & statusbit) {
  struct ip_conntrack_tuple target;
  /* We are aiming to look like inverse of other direction. */
// 根据当前数据的反方向tuple获取转换后的地址端口的tuple信息到target中
  invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
// 根据target中信息修改当前包中的信息
  if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
   return NF_DROP;
 }
 return NF_ACCEPT;
}

3.4 helper
在2.6.17中struct ip_nat_helper整个也被取消,因此也不会包括了。

3.5 seq
seq参数算是唯一NAT价值的保留参数,和原来一样,也是在记录连接的TCP序列号的变化情况的。

4. 结论
struct ip_nat_info的变化表示了在2.6.17.11中NAT的转换信息已经不再用专门的数据进行保存,而是完全根据连接的tuple值进行NAT。

发表于: 2006-09-11,修改于: 2006-09-11 08:48,已浏览3068次,有评论5条 推荐 投诉
	网友: 本站网友 	时间:2007-03-07 10:37:53 IP地址:218.5.3.★
	

因为我没找到2.6的代码,所以想请教一个问题:

在2.6中是通过conntrack节点来完成大部分操作的,特别是status域.在你上面提到的应该多了IPS_SRC_NAT_DONE_BIT和IPS_DST_NAT_DONE_BIT宏,但你另外一篇介绍2.4和2.6的不同的时候,并没有说这些有变化?


	网友: yfydz 	时间:2007-03-08 09:08:52 IP地址:218.247.216.★
	

以前那篇是针对2.6.8.1的,那时和2.4的还差不多,2.6.1*后才改的


	网友: 本站网友 	时间:2008-03-05 23:10:22 IP地址:121.34.72.★
	

分析不错,不过我还是对中间那些转换有疑问,为什么看到代码中老是通过取得方向tuple的反转tuple,而不是直接使用该ct的原始IPC_DIR_ORIG呢?

还有,比如这种:

invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);

为什么要这样去呢?直接取得该取得该ct的对应方向的tuple不就可以了吗?

不知道为什么要反转来反转去的,脑袋都搞晕了。。。。


	网友: 本站网友 	时间:2008-03-05 23:10:30 IP地址:121.34.72.★
	

分析不错,不过我还是对中间那些转换有疑问,为什么看到代码中老是通过取得方向tuple的反转tuple,而不是直接使用该ct的原始IPC_DIR_ORIG呢?

还有,比如这种:

invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);

为什么要这样去呢?直接取得该取得该ct的对应方向的tuple不就可以了吗?

不知道为什么要反转来反转去的,脑袋都搞晕了。。。。


	网友: yfydz 	时间:2008-03-06 20:26:59 IP地址:58.31.246.★
	

因为NAT情况下反向tuple的IP和正向的不一定相同


分享到:
评论

相关推荐

    linux 2.6.17 提权

    linux 2.6.17 提权

    2.6.17 exp

    local exploit root 2.6.17

    kernel-api-html-2.6.17.part02

    kernel-api-html-2.6.17.part02 全面系统讲解linux内核2.6.17 api函数,数据结构,应用函数

    kernel-api-html-2.6.17.part01

    两部分, linux内核 2.6.17 所有api函数,数据结构,应用函数。

    kernel-default-2.6.17-jad1.i586.rpm

    kernel-default-2.6.17-jad1.i586.rpm 很多人都在找的lvs文件

    phpMyFAQ v2.6.17 多国语言版.rar

    phpMyFAQ是一个支持多语言的FAQ系统,类似百度知道,支持多种数据库。phpMyFAQ具有内容管理功能,图片管理,支持多用户,用户组、新闻系统、用户跟踪、语言模块,支持 Microsoft Active Directry 活动目录。...

    ClouderaImpala_JDBC-2.6.15.1017.zip

    ClouderaImpala_JDBC-2.6.15.1017.zip,官方文档最新版本The Cloudera JDBC Driver for Hive enables your enterprise users to access Hadoop data through Business Intelligence (BI) applications with JDBC ...

    CXF2.6.7完整架包

    CXF2.6.7完整架包

    ClouderaImpala_JDBC-2.6.17.1020.zip

    ImpalaJDBC42-2.6.17.1020.jar ImpalaJDBC41-2.6.17.1020.jar ImpalaJDBC40-2.6.17.1020.jar

    Python库 | arcade-2.6.9.dev2-py3-none-any.whl

    python库,解压后可用。 资源全名:arcade-2.6.9.dev2-py3-none-any.whl

    radhat el5 安装oracle rac需要用到的包kernel-xen-2.6.18-53.el5.i686.rpm

    radhat el5 安装oracle rac需要用到的包kernel-xen-2.6.18-53.el5.i686.rpm

    redis-2.6.14

    redis资源安装包下载,tar包解压安装即可,数据缓存必备

    交叉编译器

    我们需要如下压缩包:gcc-3.4.1.tar.gz glibc-2.3.3.tar.gz linux-2.6.17binutils-2.15.tar.gz glibc-linuxthreads-2.3.3.tar.gz gdb6.0a.tar.gz,且还要下载内核arm补丁,给它打补丁,之后再压缩成原来格式,并...

    LinuxEelvation:Linux Eelvation(持续更新)

    这是什么该项目主要用于收集用于Linux平台特权提升的exp,仅用于帮助渗透测试人员在实战中快速实现特权提升。信息CVE ID 描述核仁 Linux内核2.4.20、2.2.24、2.4.25、2.4.26、2.4.27 Linux内核2.4.29 Linux内核2.6.5...

    yaf.app:基于YafPHP应用程序框架

    Redis-2.6.17 ####PHP扩展 Yaf-2.2.9+ XHProf-0.9.4 phpredis-2.2.4 Yar-1.2.1 msgpack-0.5.5 pcntl ####INI配置 yaf.ini extension=yaf.so yaf.cache_config=1 yaf.use_namespace=1 xhprof.ini ex

    移植linux2.6.17.13到s3c2410

    移植2.6.17.13到s3c2410 前一阵子移植了u-boot1.1.4之后,移植2.6.17.13走了一些弯路,采用了别人移植的2.6.14或2.6.11等方法都不成功,后来发现2.6.17比前几个版本的内核更容易。

    Vscode安装leetcode插件-LeetCode:力码

    中打开 LeetCode 问题 基于 LeetCode 问题生成文件 请参阅设置步骤 由于 VSCode Python 扩展删除了代码片段,因此为本地测试添加了main和test VSCode LeetCode 扩展设置 VSCode LeetCode 扩展需要用户登录才能使用。...

    FreeNAS 开发人员手册

    2.6.17 SMART 2.6.18 aaccli 2.6.19 beep 2.6.20 mDNSReponder (Apple bonjour) 2.7 构建boot loader 3.8 添加库 3.9 添加WebGUI 3.10 创建msfroot 2.11 创建image (为了hard drive 或 CF) 2.12 创建cd-rom...

    beanstalkd:Beanstalk是一个简单,快速的工作队列

    快速开始$ make$ ./beanstalkd也尝试$ ./beanstalkd -h$ ./beanstalkd -VVV$ make CFLAGS=-O2$ make CC=clang$ make check$ make install$ make install PREFIX=/usr需要Linux(2.6.17或更高版本),Mac OS X,...

    LINUX系统移植及UBOOT代码分析.zip

    Linux系统移植 目 录 第一部分 前言....................................................................................................................................8 1 硬件环境.........................

Global site tag (gtag.js) - Google Analytics