include/net/netfilter/nf_nat.h
//避开ip_conntrack_status枚举成员即可,然而13可谓一个重量级的数字 #define NF_FORCE_NAT_BIT 13说明:增加了一个新的CT状态,用来指示是否要做NAT匹配。
struct nf_conntrack_l4proto { ... int (*can_force_nat)(struct nf_conn *ct, struct sk_buff *skb); ... }说明:nf_conntrack_l4proto结构体增加了一个can_force_nat回调函数,将判断是否能重新执行NAT的决定权交给4层协议自己而不是在ip_conntrack以及nat逻辑中为之代劳。
////////////////////////// static int nf_ct_can_force_nat(struct nf_conn *ct, struct sk_buff *skb) { //没什么好说的... return 1; } ////////////////////////// ... struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = { ... ////////////////////////// .can_force_nat = nf_ct_can_force_nat, ////////////////////////// ... };说明:添加了nf_ct_can_force_nat回调函数,指示在ESTABLISH状态不能重新执行NAT。
////////////////////////// #ifdef CONFIG_SYSCTL //增加用户态的sysctl接口,位于/proc/sys/net/ipv4/netfilter/nf_force_nat static struct ctl_table_header *nat_sysctl_header; static unsigned int nf_force_nat __read_mostly = 0; static struct ctl_table nf_nat_sysctl_table[] = { { .procname = "nf_force_nat", .data = &nf_force_nat, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 } }; #endif ////////////////////////// ... static unsigned int nf_nat_fn(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { ... ////////////////////////// #ifdef CONFIG_SYSCTL if (nf_force_nat !=0) { set_bit(NF_FORCE_NAT_BIT, &ct->status); } else { clear_bit(NF_FORCE_NAT_BIT, &ct->status); } #else clear_bit(13, &ct->status); #endif ////////////////////////// switch (ctinfo) { case IP_CT_RELATED: ... case IP_CT_NEW: /////////////######## //增加一个标签 renat: /* Seen it before? This can happen for loopback, retrans, or local packets.. */ //增加一个允许NAT的可能性 if (!nf_nat_initialized(ct, maniptype) || test_bit(NF_FORCE_NAT_BIT, &ct->status)) /////////////######## { unsigned int ret; ... default: /* ESTABLISHED */ NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); ////////////////////////// if (test_bit(NF_FORCE_NAT_BIT, &ct->status)) { struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; unsigned int dataoff; u_int8_t protonum; int ret; l3proto = __nf_ct_l3proto_find(NFPROTO_IPV4); ret = l3proto->get_l4proto(skb, skb_network_offset(skb), &dataoff, &protonum); l4proto = __nf_ct_l4proto_find(NFPROTO_IPV4, protonum); /** * 实际上本来就应该由四层协议本身来决定是否可以强制NAT, * 但是那样就要修改conn层的回调 */ if (l4proto->can_force_nat == NULL || !l4proto->can_force_nat(ct, skb)){ goto renat; } } ////////////////////////// } ... } ... static int __init nf_nat_standalone_init(void) { ... ////////////////////////// #ifdef CONFIG_SYSCTL nat_sysctl_header = register_sysctl_paths(nf_net_ipv4_netfilter_sysctl_path, nf_nat_sysctl_table); if (nat_sysctl_header == NULL) { printk("nf_nat_init: can't register nat_sysctl"); goto cleanup_rule_init; } #endif ////////////////////////// return ret; cleanup_rule_init: ... } static void __exit nf_nat_standalone_fini(void) { ////////////////////////// #ifdef CONFIG_SYSCTL unregister_sysctl_table(nat_sysctl_header); nat_sysctl_header = NULL; #endif ////////////////////////// ... }说明:为NAT的Netflter的HOOK函数添加何时执行NAT的判断逻辑。
int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, const struct net_device *in, const struct net_device *out, struct nf_conn *ct) { struct net *net = nf_ct_net(ct); int ret; ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table); if (ret == NF_ACCEPT) { /////////////######## if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)) || test_bit(NF_FORCE_NAT_BIT, &ct->status)) { /////////////######## ////////////////////////// //如果在ipt_do_table中没有匹配到NAT规则,并且此时允许重新NAT,则说明要把反向五元组还原成原始的反向五元组 //本来想在这里做一个优化的,即如果还原了之后,在新的NAT配置上来之前,不再执行还原操作,然而这样会有问题, //注意本文第一节,由于不能保证其它的数据流是否做了NAT从而占据了不该占据的五元组,为了保证唯一性,这里的 //alloc_null_binding必须持续调用,唯一可以优化的地方在于可以不用每次都调用nf_ct_invert_tuplepr以及 //nf_conntrack_alter_reply,而这只需要一个flag位即可。 /* NUL mapping */ if (nf_ct_is_confirmed(ct)) { struct nf_conntrack_tuple reply; nf_ct_invert_tuplepr(&reply, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); nf_conntrack_alter_reply(ct, &reply); } ////////////////////////// ret = alloc_null_binding(ct, hooknum); } } return ret; }
说明:nf_nat_rule_find中如果没有找到规则,则判断是否是将已有规则删除了,进而恢复原始状态。
unsigned int nf_nat_setup_info(struct nf_conn *ct, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype) { ... /////////////######## //bug仅仅on BUG_ON(!test_bit(NF_FORCE_NAT_BIT, &ct->status) && nf_nat_initialized(ct, maniptype)); /////////////######## ... nf_ct_invert_tuplepr(&reply, &new_tuple); ////////////////////////// if (nf_ct_is_confirmed(ct)) { spin_lock_bh(&nf_conntrack_lock); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode); hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode); } ////////////////////////// nf_conntrack_alter_reply(ct, &reply); ////////////////////////// if (nf_ct_is_confirmed(ct)) { nf_conntrack_hash_insert(ct); spin_unlock_bh(&nf_conntrack_lock); } ////////////////////////// ... ////////////////////////// clear_bit(NF_FORCE_NAT_BIT, &ct->status); ////////////////////////// return NF_ACCEPT; }说明:在nf_nat_setup_info中判断如果是强制重新执行confirm状态的流的NAT,则重新将其修改过的反向五元组入哈希表。
反向: 源B->目标X
数据结构如下:
}