linux的SNAT和DNAT目标函数
SNAT、DNAT目标函数 前面在ip_nat_fn()函数中调用的ip_nat_rule_find()用来查找NAT规则,执行规则的动作,规则目标不是SNAT就是DNAT,该目标的具体实现在net/ipv4/netfilter/ip_nat_rule.c中。 不论是SNAT还是DNAT规则,其目标函数最终都是调用ip_nat_setup_info()函数来建立连接的NAT info信息。 net/ipv4/netfilter/ip_nat_rule.c: /* Source NAT */ static unsigned int ipt_snat_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING); ct = ip_conntrack_get(*pskb, &ctinfo); /* Connection must be valid and new. */ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); IP_NF_ASSERT(out); // 只有新连接才进行NAT info的建立 // targinfo实际是struct ip_nat_multi_range结构指针,记录转换后的 // 地址、端口等信息, 一个NAT规则可以转换到可以转换到多个地址端口上 return ip_nat_setup_info(ct, targinfo, hooknum); } static unsigned int ipt_dnat_target(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, const void *targinfo, void *userinfo) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; #ifdef CONFIG_IP_NF_NAT_LOCAL IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_LOCAL_OUT); #else IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING); #endif ct = ip_conntrack_get(*pskb, &ctinfo); /* Connection must be valid and new. */ IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); // 只有新连接才进行NAT info的建立 // targinfo实际是struct ip_nat_multi_range结构指针,记录转换后的 // 地址、端口等信息, 一个NAT规则可以转换到可以转换到多个地址端口上 return ip_nat_setup_info(ct, targinfo, hooknum); } ...... int ip_nat_rule_find(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, struct ip_conntrack *ct, struct ip_nat_info *info) { int ret; ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); if (ret == NF_ACCEPT) { // 数据接受但有没有初始化,分配一个NULL binding,实际不作任何修改,也就是 // 说对该包没有相应的NAT规则对于,不需要进行NAT处理 if (!(info->initialized & (1 nat.info; // 如果info->initialized不为0,表示已经初始化过了 int in_hashes = info->initialized; MUST_BE_WRITE_LOCKED(&ip_nat_lock); IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING || hooknum == NF_IP_LOCAL_OUT); IP_NF_ASSERT(info->num_manips initialized & (1 tuplehash[IP_CT_DIR_ORIGINAL].tuple) */ // 根据连接的回应方向的tuple进行反转得到原始方向的tuple invert_tuplepr(&orig_tp, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple); #if 0 { unsigned int i; DEBUGP("Hook %u (%s), ", hooknum, HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST"); DUMP_TUPLE(&orig_tp); DEBUGP("Range %p: ", mr); for (i = 0; i rangesize; i++) { DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %un", i, (mr->range.flags & IP_NAT_RANGE_MAP_IPS) ? " MAP_IPS" : "", (mr->range.flags & IP_NAT_RANGE_PROTO_SPECIFIED) ? " PROTO_SPECIFIED" : "", (mr->range.flags & IP_NAT_RANGE_FULL) ? " FULL" : "", NIPQUAD(mr->range.min_ip), NIPQUAD(mr->range.max_ip), mr->range.min.all, mr->range.max.all); } } #endif do { // 找一个未使用的进行了转换后的tuple结构参数,mr是NAT规则确定的要转换后的 // 地址端口参数, new_tuple保持转换后的连接原始方向的tuple if (!get_unique_tuple(&new_tuple, &orig_tp, mr, conntrack, hooknum)) { DEBUGP("ip_nat_setup_info: Can't get unique for %p.n", conntrack); return NF_DROP; } #if 0 DEBUGP("Hook %u (%s) %pn", hooknum, HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", conntrack); DEBUGP("Original: "); DUMP_TUPLE(&orig_tp); DEBUGP("New: "); DUMP_TUPLE(&new_tuple); #endif /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): 本文URL地址:http://www.bianceng.cn/OS/Linux/201410/45494.htm the original (A/B/C/D') and the mangled one (E/F/G/H'). We're only allowed to work with the SRC per-proto part, so we create inverses of both to start, then derive the other fields we need. */ /* Reply connection: simply invert the new tuple (G/H/E/F') */ // 建立连接地址转换后的反向的tuple,这使netfilter能自动对连接的反方向数据 // 进行处理,也就是说定义了一条SNAT规则后,并不需要再定义一条DNAT规则来处理 // 返回的数据,netfilter已经自动处理了 invert_tuplepr(&reply, &new_tuple); /* Alter conntrack table so it recognizes replies. If fail this race (reply tuple now used), repeat. */ // 修改连接参数使能正确识别返回数据,如果reply已经对应一条连接 // ip_conntrack_alter_reply()函数返回0,表示要继续修改转换后的参数值 } while (!ip_conntrack_alter_reply(conntrack, &reply)); /* FIXME: We can simply used existing conntrack reply tuple here --RR */ /* Create inverse of original: C/D/A/B' */ invert_tuplepr(&inv_tuple, &orig_tp); /* Has source changed?. */ // 源NAT if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) { /* In this direction, a source manip. */ // 连接正方向是SNAT info->manips[info->num_manips++] = ((struct ip_nat_info_manip) { IP_CT_DIR_ORIGINAL, hooknum, IP_NAT_MANIP_SRC, new_tuple.src }); IP_NF_ASSERT(info->num_manips manips[info->num_manips++] = ((struct ip_nat_info_manip) { IP_CT_DIR_REPLY, opposite_hook[hooknum], IP_NAT_MANIP_DST, orig_tp.src }); IP_NF_ASSERT(info->num_manips manips[info->num_manips++] = ((struct ip_nat_info_manip) { IP_CT_DIR_ORIGINAL, hooknum, IP_NAT_MANIP_DST, reply.src }); IP_NF_ASSERT(info->num_manips manips[info->num_manips++] = ((struct ip_nat_info_manip) { IP_CT_DIR_REPLY, opposite_hook[hooknum], IP_NAT_MANIP_SRC, inv_tuple.src }); IP_NF_ASSERT(info->num_manips master) info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, &reply); /* It's done. */ // 完成该方向的NAT info初始化 info->initialized |= (1 bysource.conntrack); replace_in_hashes(conntrack, info); } else { place_in_hashes(conntrack, info); } return NF_ACCEPT; } (编辑:佛山站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |