免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3096 | 回复: 1
打印 上一主题 下一主题

Iptables NAT的基本工作原理(转) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2003-05-08 20:09 |只看该作者 |倒序浏览
Iptables NAT的基本工作原理
(1) IP地址转换过滤器(CONFIG_IP_NF_NAT)用来实现各种IP续接. 当主机之间不能直接进行IP寻径时,通过双方都能寻径的代理主机的IP地址转换器进行相互翻译,形成一个透明的IP回路。常见的地址转换类型有IP伪装(IP MASQUERADE), 端口转发(PORT FORWARDING),IP重定向(IP REDIRECT).

(2) IP伪装可以使内网中的主机共享网关主机在外网中的地址来与外网主机通信, 当内网主机的IP包要传送到外网主机时, 网关的地址转换器将IP包的源地址和端口置换成自已的地址传递到外网目的主机, 当目的主机应答时, 网关再将应答包的目的地址和端口恢复成内网主机的IP地址和端口.

(3) 当外网主机首先与内网网关主机建立连接时, 网关的地址转换器可以将不同端口的IP包转接到不同的内网主机中, 这就是端口转发. 网关修改外网IP包的源地址和目的地址以及端口传递到相应的内网主机中, 内网主机的应答包再被网关恢复其源地址和目的地址及其端口发送回外网主机.

(4) 通过网关的IP包可以被网关将其目的地址替换为本地地址, 把通过网关的外部连接定向到主机本身, 这就是IP重定向, 可以用来实现IP透明代理.

(5) IP地址变换器建立在IP轨迹跟踪的基础上, IP轨迹可看成主机与主机之间的IP回路在网关主机内产生的映象. 当IP包从内网主机通过网关主机向外网主机发出初次请求时, 就在网关主机内产生了一条请求轨迹, 当外网主机通过网关向内网主机发出应答时, 通过网关主机的应答包就被IP轨迹跟踪器绑定在对应的请求轨迹上. 每条轨迹具有正向地址元和逆向地址元分别与请求IP包地址与应答IP包地址匹配. 在正常的网关路由过程中, 轨迹的正向请求与逆向应答地址元是对称的, 当引入了地址转换操作以后, 轨迹的正向与逆向地址元的对称性被破坏, 成为转移轨迹, 绑定在转移轨迹上的IP包通过地址转换过滤器后, IP包的地址将发生变化, 即请求包的地址被置换为转移轨迹逆向应答地址元的逆地址, 应答包的地址被置换为转移轨迹前向请求地址元的逆地址. 由此可见, 标准的IP寻径操作可以看成IP地址转换操作的一种特例.

(6) IP地址变换器是IP轨迹跟踪器的后级过滤器, 它有3个过滤端. IP包的地址转换并不是一次完成的, IP包目的地址转换在路由前端或本地输出端完成, IP包的源地址转换在路由后端完成, 地址变换器输出注入到IP轨迹跟踪器的未端输出. ip_nat_info描述轨迹的地址转换信息, 它是IP轨迹结构(ip_conntrack)的一部分. 对于新建轨迹, 转换器将从地址转换规则表(nat_table)建立轨迹的地址转换信息, ip_nat_info结构中的ip_nat_info_manip结构用于完成IP包地址的映射和逆映射.

  1. /* Worst case: local-out manip + 1 post-routing, and reverse dirn. */ #define IP_NAT_MAX_MANIPS (2*3) /* 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_info_manip { /* The direction. */ u_int8_t direction; /* Which hook the manipulation happens on. */ u_int8_t hooknum; /* The manipulation type. */ u_int8_t maniptype; /* Manipulations to occur at each conntrack in this dirn. */ struct ip_conntrack_manip manip; }; /* Hashes for by-source and IP/protocol. */ struct ip_nat_hash { struct list_head list; /* conntrack we're embedded in: NULL if not in hash. */ struct ip_conntrack *conntrack; }; /* A range consists of an array of 1 or more ip_nat_range */ struct ip_nat_multi_range 建立地址转换信息的规则表的参数结构 { unsigned int rangesize; /* hangs off end. */ struct ip_nat_range range[1]; }; /* Single range specification. */ struct ip_nat_range { /* Set to OR of flags above. */ unsigned int flags; /* Inclusive: network order. */ u_int32_t min_ip, max_ip; /* Inclusive: network order */ union ip_conntrack_manip_proto min, max; }; /* Return conntrack and conntrack_info a given skb */ inline struct ip_conntrack * ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo) 取包缓冲所绑定的轨迹 { if (skb->;nfct) { struct ip_conntrack *ct = (struct ip_conntrack *)skb->;nfct->;master; /* ctinfo is the index of the nfct inside the conntrack */ *ctinfo = skb->;nfct - ct->;infos; IP_NF_ASSERT(*ctinfo >;= 0 && *ctinfo < IP_CT_NUMBER); return ct; } return NULL; } extern inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1, const struct ip_conntrack_tuple *t2) { return t1->;src.ip == t2->;src.ip && t1->;src.u.all == t2->;src.u.all; } extern inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1, const struct ip_conntrack_tuple *t2) { return t1->;dst.ip == t2->;dst.ip && t1->;dst.u.all == t2->;dst.u.all && t1->;dst.protonum == t2->;dst.protonum; } enum ip_nat_manip_type { IP_NAT_MANIP_SRC, IP_NAT_MANIP_DST }; /* SRC manip occurs only on POST_ROUTING */ #define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING) #define CTINFO2DIR(ctinfo) ((ctinfo) >;= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) ; net/ipv4/netfilter/ip_nat_standalone.c: ----------------------------------------- * We must be after connection tracking and before packet filtering. */ /* Before packet filtering, change destination */ static struct nf_hook_ops ip_nat_in_ops 路由前IP输入地址转换器 = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST }; /* After packet filtering, change source */ static struct nf_hook_ops ip_nat_out_ops 路由后IP输出地址转换器 = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC}; /* Before packet filtering, change destination */ static struct nf_hook_ops ip_nat_local_out_ops 本地输出地址转换器 = { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST }; static int init_or_cleanup(int init) 地址转换模块初始化 { int ret = 0; if (!init) goto cleanup; ret = ip_nat_rule_init(); 地址转规则表初始化 if (ret < 0) { printk("ip_nat_init: can't setup rules.\n"); goto cleanup_nothing; } ret = ip_nat_init(); 地址转换器初始化 if (ret < 0) { printk("ip_nat_init: can't setup rules.\n"); goto cleanup_rule_init; } ret = nf_register_hook(&ip_nat_in_ops); if (ret < 0) { printk("ip_nat_init: can't register in hook.\n"); goto cleanup_nat; } ret = nf_register_hook(&ip_nat_out_ops); if (ret < 0) { printk("ip_nat_init: can't register out hook.\n"); goto cleanup_inops; } ret = nf_register_hook(&ip_nat_local_out_ops); if (ret < 0) { printk("ip_nat_init: can't register local out hook.\n"); goto cleanup_outops; } if (ip_conntrack_module) __MOD_INC_USE_COUNT(ip_conntrack_module); return ret; cleanup: if (ip_conntrack_module) __MOD_DEC_USE_COUNT(ip_conntrack_module); nf_unregister_hook(&ip_nat_local_out_ops); cleanup_outops: nf_unregister_hook(&ip_nat_out_ops); cleanup_inops: nf_unregister_hook(&ip_nat_in_ops); cleanup_nat: ip_nat_cleanup(); cleanup_rule_init: ip_nat_rule_cleanup(); cleanup_nothing: MUST_BE_READ_WRITE_UNLOCKED(&ip_nat_lock); return ret; } static unsigned int ip_nat_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 地址转换器入口 { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; struct ip_nat_info *info; /* maniptype == SRC for postrouting. */ enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum); 取本过滤端所能进行地址转换的类型 /* We never see fragments: conntrack defrags on pre-routing and local-out, and ip_nat_out protects post-routing. */ IP_NF_ASSERT(!((*pskb)->;nh.iph->;frag_off & __constant_htons(IP_MF|IP_OFFSET))); (*pskb)->;nfcache |= NFC_UNKNOWN; /* If we had a hardware checksum before, it's now invalid */ if ((*pskb)->;pkt_type != PACKET_LOOPBACK) (*pskb)->;ip_summed = CHECKSUM_NONE; ct = ip_conntrack_get(*pskb, &ctinfo); 取包轨迹 /* Can't track? Maybe out of memory: this would make NAT unreliable. */ if (!ct) { if (net_ratelimit()) printk(KERN_DEBUG "NAT: %u dropping untracked packet %p %u %u.%u.%u.%u ->; %u.%u.%u.%u\n", hooknum, *pskb, (*pskb)->;nh.iph->;protocol, NIPQUAD((*pskb)->;nh.iph->;saddr), NIPQUAD((*pskb)->;nh.iph->;daddr)); return NF_DROP; } switch (ctinfo) { case IP_CT_RELATED: case IP_CT_RELATED+IP_CT_IS_REPLY: if ((*pskb)->;nh.iph->;protocol == IPPROTO_ICMP) { return icmp_reply_translation(*pskb, ct, hooknum, CTINFO2DIR(ctinfo)); } /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */ case IP_CT_NEW: 对于跟踪到的新轨迹 info = &ct->;nat.info; WRITE_LOCK(&ip_nat_lock); /* Seen it before? This can happen for loopback, retrans, or local packets.. */ if (!(info->;initialized & (1 << maniptype))) { int in_hashes = info->;initialized; unsigned int ret; ret = ip_nat_rule_find(pskb, hooknum, in, out, ct, info); 建立轨迹的地址转换信息 if (ret != NF_ACCEPT) { WRITE_UNLOCK(&ip_nat_lock); return ret; } if (in_hashes) { IP_NF_ASSERT(info->;bysource.conntrack); replace_in_hashes(ct, info); } else { place_in_hashes(ct, info); 对转换轨迹进行索引 } } else DEBUGP("Already setup manip %s for ct %p\n", maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", ct); WRITE_UNLOCK(&ip_nat_lock); break; default: /* ESTABLISHED */ IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED || ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)); info = &ct->;nat.info; } IP_NF_ASSERT(info); return do_bindings(ct, ctinfo, info, hooknum, pskb); 进行包的地址转换 } static unsigned int ip_nat_out(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 路由后输出转换器 { /* root is playing with raw sockets. */ if ((*pskb)->;len < sizeof(struct iphdr) || (*pskb)->;nh.iph->;ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; /* We can hit fragment here; forwarded packets get defragmented by connection tracking coming in, then fragmented (grr) by the forward code. In future: If we have nfct != NULL, AND we have NAT initialized, AND there is no helper, then we can do full NAPT on the head, and IP-address-only NAT on the rest. I'm starting to have nightmares about fragments. */ if ((*pskb)->;nh.iph->;frag_off & __constant_htons(IP_MF|IP_OFFSET)) { *pskb = ip_ct_gather_frags(*pskb); if (!*pskb) return NF_STOLEN; } return ip_nat_fn(hooknum, pskb, in, out, okfn); } static unsigned int ip_nat_local_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) 本地输出转换器 { u_int32_t saddr, daddr; unsigned int ret; /* root is playing with raw sockets. */ if ((*pskb)->;len < sizeof(struct iphdr) || (*pskb)->;nh.iph->;ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; saddr = (*pskb)->;nh.iph->;saddr; daddr = (*pskb)->;nh.iph->;daddr; ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && ((*pskb)->;nh.iph->;saddr != saddr || (*pskb)->;nh.iph->;daddr != daddr)) 如果转换器输出包的IP地址发生变化, return route_me_harder(*pskb) == 0 ? ret : NF_DROP; 重新绑定输出包路由 return ret; } /* FIXME: change in oif may mean change in hh_len. Check and realloc --RR */ static int route_me_harder(struct sk_buff *skb) { struct iphdr *iph = skb->;nh.iph; struct rtable *rt; struct rt_key key = { dst:iph->;daddr, src:iph->;saddr, oif:skb->;sk ? skb->;sk->;bound_dev_if : 0, tos:RT_TOS(iph->;tos)|RTO_CONN, #ifdef CONFIG_IP_ROUTE_FWMARK fwmark:skb->;nfmark #endif }; if (ip_route_output_key(&rt, &key) != 0) { printk("route_me_harder: No more route.\n"); return -EINVAL; } /* Drop old route. */ dst_release(skb->;dst); skb->;dst = &rt->;u.dst; return 0; } ; net/ipv4/netfilter/ip_nat_core.c: ----------------------------------- #define IP_NAT_HTABLE_SIZE 64 static struct list_head bysource[IP_NAT_HTABLE_SIZE]; 按转移轨迹源地址和协议索引的散列表 static struct list_head byipsproto[IP_NAT_HTABLE_SIZE]; 接转移轨迹IP地址和协议进行索引的散列表 LIST_HEAD(protos); 传输协议地址转换器 static LIST_HEAD(helpers); LIST_HEAD(nat_expect_list); int __init ip_nat_init(void) { size_t i; /* Sew in builtin protocols. */ WRITE_LOCK(&ip_nat_lock); list_append(&protos, &ip_nat_protocol_tcp); list_append(&protos, &ip_nat_protocol_udp); list_append(&protos, &ip_nat_protocol_icmp); WRITE_UNLOCK(&ip_nat_lock); for (i = 0; i < IP_NAT_HTABLE_SIZE; i++) { INIT_LIST_HEAD(&bysource[ i ]); INIT_LIST_HEAD(&byipsproto[ i ]); } /* FIXME: Man, this is a hack. */ IP_NF_ASSERT(ip_conntrack_destroyed == NULL); ip_conntrack_destroyed = &ip_nat_cleanup_conntrack; return 0; } /* Do packet manipulations according to binding. */ unsigned int do_bindings(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, struct ip_nat_info *info, unsigned int hooknum, struct sk_buff **pskb) 完成地址转换 { unsigned int i; struct ip_nat_helper *helper; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); /* Need nat lock to protect against modification, but neither conntrack (referenced) and helper (deleted with synchronize_bh()) can vanish. */ READ_LOCK(&ip_nat_lock); for (i = 0; i < info->;num_manips; i++) { if (info->;manips[ i ].direction == dir && info->;manips[ i ].hooknum == hooknum) { 对于特定的转换方向和过滤端 DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n", *pskb, info->;manips[ i ].maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST", NIPQUAD(info->;manips[ i ].manip.ip), htons(info->;manips[ i ].manip.u.all)); manip_pkt((*pskb)->;nh.iph->;protocol, (*pskb)->;nh.iph, (*pskb)->;len, &info->;manips[ i ].manip, info->;manips[ i ].maniptype, &(*pskb)->;nfcache); } } helper = info->;helper; READ_UNLOCK(&ip_nat_lock); if (helper) { /* Always defragged for helpers */ IP_NF_ASSERT(!((*pskb)->;nh.iph->;frag_off & __constant_htons(IP_MF|IP_OFFSET))); return helper->;help(ct, info, ctinfo, hooknum, pskb); } else return NF_ACCEPT; } static void manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len, const struct ip_conntrack_manip *manip, enum ip_nat_manip_type maniptype, __u32 *nfcache) { *nfcache |= NFC_ALTERED; find_nat_proto(proto)->;manip_pkt(iph, len, manip, maniptype); 转换传输层地址元 if (maniptype == IP_NAT_MANIP_SRC) { 如果为源地址转换 iph->;check = ip_nat_cheat_check(~iph->;saddr, manip->;ip, iph->;check); iph->;saddr = manip->;ip; 置换IP包的源地址 } else { 否则为目标地址转换 iph->;check = ip_nat_cheat_check(~iph->;daddr, manip->;ip, iph->;check); iph->;daddr = manip->;ip; 置换IP包的目的地址 } #if 0 if (ip_fast_csum((u8 *)iph, iph->;ihl) != 0) DEBUGP("IP: checksum on packet bad.\n"); if (proto == IPPROTO_TCP) { void *th = (u_int32_t *)iph + iph->;ihl; if (tcp_v4_check(th, len - 4*iph->;ihl, iph->;saddr, iph->;daddr, csum_partial((char *)th, len-4*iph->;ihl, 0))) DEBUGP("TCP: checksum on packet bad\n"); } #endif } 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) 从NAT规则表中建立轨迹的地址转换信息 { int ret; /* Master won't vanish while this ctrack still alive */ if (ct->;master.master) { 如果该轨迹是从属于master的轨迹 struct ip_conntrack *master; master = (struct ip_conntrack *)ct->;master.master; if (LIST_FIND(&nat_expect_list, call_expect, struct ip_nat_expect *, pskb, hooknum, ct, info, master, &master->;nat.info, &ret)) return ret; } ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL); 运行地址转换规则表 if (ret == NF_ACCEPT) { if (!(info->;initialized & (1 << HOOK2MANIP(hooknum)))) /* NUL mapping */ ret = alloc_null_binding(ct, info, hooknum); 建立空转换信息 } return ret; } static inline unsigned int alloc_null_binding(struct ip_conntrack *conntrack, struct ip_nat_info *info, unsigned int hooknum) { /* Force range to this IP; let proto decide mapping for per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). Use reply in case it's already been mangled (eg local packet). */ u_int32_t ip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ? conntrack->;tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip : conntrack->;tuplehash[IP_CT_DIR_REPLY].tuple.src.ip); struct ip_nat_multi_range mr = { 1, { { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } } } }; DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack, NIPQUAD(ip)); return ip_nat_setup_info(conntrack, &mr, hooknum); } /* Where to manip the reply packets (will be reverse manip). */ static unsigned int opposite_hook[NF_IP_NUMHOOKS] = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING, [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING, [NF_IP_LOCAL_OUT] = NF_IP_POST_ROUTING }; unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack, const struct ip_nat_multi_range *mr, unsigned int hooknum) 建立地址转换信息 { struct ip_conntrack_tuple new_tuple, inv_tuple, reply; struct ip_conntrack_tuple orig_tp; struct ip_nat_info *info = &conntrack->;nat.info; 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 < IP_NAT_MAX_MANIPS); /* 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) */ 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 < mr->;rangesize; i++) { DEBUGP("%u:%s%s%s %u.%u.%u.%u - %u.%u.%u.%u %u - %u\n", i, (mr->;range[ i ].flags & IP_NAT_RANGE_MAP_IPS) ? " MAP_IPS" : "", (mr->;range[ i ].flags & IP_NAT_RANGE_PROTO_SPECIFIED) ? " PROTO_SPECIFIED" : "", (mr->;range[ i ].flags & IP_NAT_RANGE_FULL) ? " FULL" : "", NIPQUAD(mr->;range[ i ].min_ip), NIPQUAD(mr->;range[ i ].max_ip), mr->;range[ i ].min.all, mr->;range[ i ].max.all); } } #endif do { 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) %p\n", 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): 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') */ invert_tuplepr(&reply, &new_tuple); 求新目标地址元的反向应答元 /* Alter conntrack table so it recognizes replies. If fail this race (reply tuple now used), repeat. */ } 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?. */ if (!ip_ct_tuple_src_equal(&new_tuple, &orig_tp)) { 如果新目标地址元和原目标地址元源地址不等 /* In this direction, a source manip. */ 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 < IP_NAT_MAX_MANIPS); /* In the reverse direction, a destination manip. */ info->;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 <= IP_NAT_MAX_MANIPS); } /* Has destination changed? */ if (!ip_ct_tuple_dst_equal(&new_tuple, &orig_tp)) { 如果新目标地址元和旧目标地址元目的地址不等 /* In this direction, a destination manip */ info->;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 < IP_NAT_MAX_MANIPS); /* In the reverse direction, a source manip. */ info->;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 <= IP_NAT_MAX_MANIPS); } /* If there's a helper, assign it; based on new tuple. */ info->;helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, &reply); /* It's done. */ info->;initialized |= (1 << HOOK2MANIP(hooknum)); 过滤端初始化标记 return NF_ACCEPT; } int invert_tuplepr(struct ip_conntrack_tuple *inverse, const struct ip_conntrack_tuple *orig) { return invert_tuple(inverse, orig, find_proto(orig->;dst.protonum)); } /* If it's really a local destination manip, it may need to do a source manip too. */ static int do_extra_mangle(u_int32_t var_ip, u_int32_t *other_ipp) { struct rtable *rt; /* FIXME: IPTOS_TOS(iph->;tos) --RR */ if (ip_route_output(&rt, var_ip, 0, 0, 0) != 0) { DEBUGP("do_extra_mangle: Can't get route to %u.%u.%u.%u\n", NIPQUAD(var_ip)); return 0; } *other_ipp = rt->;rt_src; ip_rt_put(rt); return 1; } /* Alter reply tuple (maybe alter helper). If it's already taken, return 0 and don't do alteration. */ int ip_conntrack_alter_reply(struct ip_conntrack *conntrack, const struct ip_conntrack_tuple *newreply) { unsigned int newindex = hash_conntrack(newreply); WRITE_LOCK(&ip_conntrack_lock); if (__ip_conntrack_find(newreply, conntrack)) { WRITE_UNLOCK(&ip_conntrack_lock); return 0; } DEBUGP("Altering reply tuple of %p to ", conntrack); DUMP_TUPLE(newreply); LIST_DELETE(&ip_conntrack_hash [hash_conntrack(&conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple)], &conntrack->;tuplehash[IP_CT_DIR_REPLY]); conntrack->;tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; list_prepend(&ip_conntrack_hash[newindex], &conntrack->;tuplehash[IP_CT_DIR_REPLY]); conntrack->;helper = LIST_FIND(&helpers, helper_cmp, struct ip_conntrack_helper *, newreply); WRITE_UNLOCK(&ip_conntrack_lock); return 1; } /* We do checksum mangling, so if they were wrong before they're still * wrong. Also works for incomplete packets (eg. ICMP dest * unreachables.) */ u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) { u_int32_t diffs[] = { oldvalinv, newval }; return csum_fold(csum_partial((char *)diffs, sizeof(diffs), oldcheck^0xFFFF)); } static inline int call_expect(const struct ip_nat_expect *i, struct sk_buff **pskb, unsigned int hooknum, struct ip_conntrack *ct, struct ip_nat_info *info, struct ip_conntrack *master, struct ip_nat_info *masterinfo, unsigned int *verdict) { return i->;expect(pskb, hooknum, ct, info, master, masterinfo, verdict); } void replace_in_hashes(struct ip_conntrack *conntrack, struct ip_nat_info *info) { /* Source has changed, so replace in hashes. */ unsigned int srchash = hash_by_src(&conntrack->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.src, conntrack->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.protonum); /* We place packet as seen OUTGOUNG in byips_proto hash (ie. reverse dst and src of reply packet. */ unsigned int ipsprotohash = hash_by_ipsproto(conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.ip, conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.src.ip, conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.protonum); IP_NF_ASSERT(info->;bysource.conntrack == conntrack); MUST_BE_WRITE_LOCKED(&ip_nat_lock); list_del(&info->;bysource.list); list_del(&info->;byipsproto.list); list_prepend(&bysource[srchash], &info->;bysource); list_prepend(&byipsproto[ipsprotohash], &info->;byipsproto); } void place_in_hashes(struct ip_conntrack *conntrack, struct ip_nat_info *info) { unsigned int srchash = hash_by_src(&conntrack->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.src, conntrack->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.protonum); /* We place packet as seen OUTGOUNG in byips_proto hash (ie. reverse dst and src of reply packet. */ unsigned int ipsprotohash = hash_by_ipsproto(conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.ip, conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.src.ip, conntrack->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.protonum); IP_NF_ASSERT(!info->;bysource.conntrack); MUST_BE_WRITE_LOCKED(&ip_nat_lock); info->;byipsproto.conntrack = conntrack; info->;bysource.conntrack = conntrack; list_prepend(&bysource[srchash], &info->;bysource); list_prepend(&byipsproto[ipsprotohash], &info->;byipsproto); } static inline size_t hash_by_src(const struct ip_conntrack_manip *manip, u_int16_t proto) 按源地址和源端口索引 { /* Original src, to ensure we map it consistently if poss. */ return (manip->;ip + manip->;u.all + proto) % IP_NAT_HTABLE_SIZE; } /* We keep extra hashes for each conntrack, for fast searching. */ static inline size_t hash_by_ipsproto(u_int32_t src, u_int32_t dst, u_int16_t proto) 按IP地址索引 { /* Modified src and dst, to ensure we don't create two identical streams. */ return (src + dst + proto) % IP_NAT_HTABLE_SIZE; } /* Noone using conntrack by the time this called. */ static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn) { struct ip_nat_info *info = &conn->;nat.info; if (!info->;initialized) return; IP_NF_ASSERT(info->;bysource.conntrack); IP_NF_ASSERT(info->;byipsproto.conntrack); WRITE_LOCK(&ip_nat_lock); LIST_DELETE(&bysource[hash_by_src(&conn->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.src, conn->;tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.protonum)], &info->;bysource); LIST_DELETE(&byipsproto [hash_by_ipsproto(conn->;tuplehash[IP_CT_DIR_REPLY] .tuple.src.ip, conn->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.ip, conn->;tuplehash[IP_CT_DIR_REPLY] .tuple.dst.protonum)], &info->;byipsproto); WRITE_UNLOCK(&ip_nat_lock); }
复制代码

论坛徽章:
0
2 [报告]
发表于 2003-05-08 23:17 |只看该作者

Iptables NAT的基本工作原理(转)

[quote]原帖由 "w8u8"][/quote 发表:


老大可以再整理一下吗?简直就象是密文了。

谢谢!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP