?? ip_nat_core.c
字號:
best.score = score; best.tuple = *tuple; best.range = &mr->range[i]; } } } *tuple = best.tuple; /* Discard const. */ return (struct ip_nat_range *)best.range;}/* Fast version doesn't iterate through hash chains, but only handles common case of single IP address (null NAT, masquerade) */static struct ip_nat_range *find_best_ips_proto_fast(struct ip_conntrack_tuple *tuple, const struct ip_nat_multi_range *mr, const struct ip_conntrack *conntrack, unsigned int hooknum){ if (mr->rangesize != 1 || (mr->range[0].flags & IP_NAT_RANGE_FULL) || ((mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) && mr->range[0].min_ip != mr->range[0].max_ip)) return find_best_ips_proto(tuple, mr, conntrack, hooknum); if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) { if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) tuple->src.ip = mr->range[0].min_ip; else { /* Only do extra mangle when required (breaks socket binding) */#ifdef CONFIG_IP_NF_NAT_LOCAL if (tuple->dst.ip != mr->range[0].min_ip && hooknum == NF_IP_LOCAL_OUT && !do_extra_mangle(mr->range[0].min_ip, &tuple->src.ip)) return NULL;#endif tuple->dst.ip = mr->range[0].min_ip; } } /* Discard const. */ return (struct ip_nat_range *)&mr->range[0];}static intget_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack_tuple *orig_tuple, const struct ip_nat_multi_range *mrr, struct ip_conntrack *conntrack, unsigned int hooknum){ struct ip_nat_protocol *proto = find_nat_proto(orig_tuple->dst.protonum); struct ip_nat_range *rptr; unsigned int i; int ret; /* We temporarily use flags for marking full parts, but we always clean up afterwards */ struct ip_nat_multi_range *mr = (void *)mrr; /* 1) If this srcip/proto/src-proto-part is currently mapped, and that same mapping gives a unique tuple within the given range, use that. This is only required for source (ie. NAT/masq) mappings. So far, we don't do local source mappings, so multiple manips not an issue. */ if (hooknum == NF_IP_POST_ROUTING) { struct ip_conntrack_manip *manip; manip = find_appropriate_src(orig_tuple, mr); if (manip) { /* Apply same source manipulation. */ *tuple = ((struct ip_conntrack_tuple) { *manip, orig_tuple->dst }); DEBUGP("get_unique_tuple: Found current src map\n"); if (!ip_nat_used_tuple(tuple, conntrack)) return 1; } } /* 2) Select the least-used IP/proto combination in the given range. */ *tuple = *orig_tuple; while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) != NULL) { DEBUGP("Found best for "); DUMP_TUPLE(tuple); /* 3) The per-protocol part of the manip is made to map into the range to make a unique tuple. */ /* Only bother mapping if it's not already in range and unique */ if ((!(rptr->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || proto->in_range(tuple, HOOK2MANIP(hooknum), &rptr->min, &rptr->max)) && !ip_nat_used_tuple(tuple, conntrack)) { ret = 1; goto clear_fulls; } else { if (proto->unique_tuple(tuple, rptr, HOOK2MANIP(hooknum), conntrack)) { /* Must be unique. */ IP_NF_ASSERT(!ip_nat_used_tuple(tuple, conntrack)); ret = 1; goto clear_fulls; } else if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { /* Try implicit source NAT; protocol may be able to play with ports to make it unique. */ struct ip_nat_range r = { IP_NAT_RANGE_MAP_IPS, tuple->src.ip, tuple->src.ip, { 0 }, { 0 } }; DEBUGP("Trying implicit mapping\n"); if (proto->unique_tuple(tuple, &r, IP_NAT_MANIP_SRC, conntrack)) { /* Must be unique. */ IP_NF_ASSERT(!ip_nat_used_tuple (tuple, conntrack)); ret = 1; goto clear_fulls; } } DEBUGP("Protocol can't get unique tuple %u.\n", hooknum); } /* Eliminate that from range, and try again. */ rptr->flags |= IP_NAT_RANGE_FULL; *tuple = *orig_tuple; } ret = 0; clear_fulls: /* Clear full flags. */ IP_NF_ASSERT(mr->rangesize >= 1); for (i = 0; i < mr->rangesize; i++) mr->range[i].flags &= ~IP_NAT_RANGE_FULL; return ret;}static inline inthelper_cmp(const struct ip_nat_helper *helper, const struct ip_conntrack_tuple *tuple){ return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);}/* 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,#ifdef CONFIG_IP_NF_NAT_LOCAL [NF_IP_LOCAL_OUT] = NF_IP_LOCAL_IN, [NF_IP_LOCAL_IN] = NF_IP_LOCAL_OUT,#endif};unsigned intip_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; 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_IN || hooknum == NF_IP_LOCAL_OUT); IP_NF_ASSERT(info->num_manips < IP_NAT_MAX_MANIPS); IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); /* 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. */ if (!conntrack->master) info->helper = LIST_FIND(&helpers, helper_cmp, struct ip_nat_helper *, &reply); /* It's done. */ info->initialized |= (1 << HOOK2MANIP(hooknum)); if (in_hashes) { IP_NF_ASSERT(info->bysource.conntrack); replace_in_hashes(conntrack, info); } else { place_in_hashes(conntrack, info); } return NF_ACCEPT;}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,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -