static void icmp_unique_tuple(const struct nf_nat_l3proto *l3proto, struct nf_conntrack_tuple *tuple, const struct nf_nat_range2 *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { static u_int16_t id; unsigned int range_size; unsigned int i; range_size = ntohs(range->max_proto.icmp.id) - ntohs(range->min_proto.icmp.id) + 1; /* If no range specified... */ if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) range_size = 0xFFFF; for (i = 0; ; ++id) { tuple->src.u.icmp.id = htons(ntohs(range->min_proto.icmp.id) + (id % range_size)); if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) return; } return; }
/* generate unique tuple ... */ static int gre_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *conntrack) { static u_int16_t key; __be16 *keyptr; unsigned int min, i, range_size; if (maniptype == IP_NAT_MANIP_SRC) keyptr = &tuple->src.u.gre.key; else keyptr = &tuple->dst.u.gre.key; if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { DEBUGP("%p: NATing GRE PPTP\n", conntrack); min = 1; range_size = 0xffff; } else { min = ntohs(range->min.gre.key); range_size = ntohs(range->max.gre.key) - min + 1; } DEBUGP("min = %u, range_size = %u\n", min, range_size); for (i = 0; i < range_size; i++, key++) { *keyptr = htons(min + key % range_size); if (!nf_nat_used_tuple(tuple, conntrack)) return 1; } DEBUGP("%p: no NAT mapping\n", conntrack); return 0; }
void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct, u16 *rover) { unsigned int range_size, min, i; __be16 *portptr; u_int16_t off; if (maniptype == NF_NAT_MANIP_SRC) portptr = &tuple->src.u.all; else portptr = &tuple->dst.u.all; /* If no range specified... */ if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == NF_NAT_MANIP_DST) return; if (ntohs(*portptr) < 1024) { /* Loose convention: >> 512 is credential passing */ if (ntohs(*portptr) < 512) { min = 1; range_size = 511 - min + 1; } else { min = 600; range_size = 1023 - min + 1; } } else { min = 1024; range_size = 65535 - 1024 + 1; } } else { min = ntohs(range->min_proto.all); range_size = ntohs(range->max_proto.all) - min + 1; } if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { off = l3proto->secure_port(tuple, maniptype == NF_NAT_MANIP_SRC ? tuple->dst.u.all : tuple->src.u.all); } else if (range->flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) { off = prandom_u32(); } else { off = *rover; } for (i = 0; ; ++off) { *portptr = htons(min + off % range_size); if (++i != range_size && nf_nat_used_tuple(tuple, ct)) continue; if (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) *rover = off; return; } }
bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct, u_int16_t *rover) { unsigned int range_size, min, i; __be16 *portptr; u_int16_t off; if (maniptype == IP_NAT_MANIP_SRC) portptr = &tuple->src.u.all; else portptr = &tuple->dst.u.all; /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == IP_NAT_MANIP_DST) return false; if (ntohs(*portptr) < 1024) { /* Loose convention: >> 512 is credential passing */ if (ntohs(*portptr) < 512) { min = 1; range_size = 511 - min + 1; } else { min = 600; range_size = 1023 - min + 1; } } else { min = 1024; range_size = 65535 - 1024 + 1; } } else { min = ntohs(range->min.all); range_size = ntohs(range->max.all) - min + 1; } if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip, maniptype == IP_NAT_MANIP_SRC ? tuple->dst.u.all : tuple->src.u.all); else off = *rover; for (i = 0; i < range_size; i++, off++) { *portptr = htons(min + off % range_size); if (nf_nat_used_tuple(tuple, ct)) continue; if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) *rover = off; return true; } return false; }
static int tcp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { static u_int16_t port; __be16 *portptr; unsigned int range_size, min, i; if (maniptype == IP_NAT_MANIP_SRC) portptr = &tuple->src.u.tcp.port; else portptr = &tuple->dst.u.tcp.port; /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == IP_NAT_MANIP_DST) return 0; /* Map privileged onto privileged. */ if (ntohs(*portptr) < 1024) { /* Loose convention: >> 512 is credential passing */ if (ntohs(*portptr)<512) { min = 1; range_size = 511 - min + 1; } else { min = 600; range_size = 1023 - min + 1; } } else { min = 1024; range_size = 65535 - 1024 + 1; } } else { min = ntohs(range->min.tcp.port); range_size = ntohs(range->max.tcp.port) - min + 1; } if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) port = net_random(); for (i = 0; ; ++port) { *portptr = htons(min + port % range_size); if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) return 1; } return 0; }
/* generate unique tuple ... */ static void gre_unique_tuple(const struct nf_nat_l3proto *l3proto, struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { static u_int16_t key; __be16 *keyptr; unsigned int min, i, range_size; /* If there is no master conntrack we are not PPTP, do not change tuples */ if (!ct->master) return; if (maniptype == NF_NAT_MANIP_SRC) keyptr = &tuple->src.u.gre.key; else keyptr = &tuple->dst.u.gre.key; if (!(range->flags & NF_NAT_RANGE_PROTO_SPECIFIED)) { pr_debug("%p: NATing GRE PPTP\n", ct); min = 1; range_size = 0xffff; } else { min = ntohs(range->min_proto.gre.key); range_size = ntohs(range->max_proto.gre.key) - min + 1; } pr_debug("min = %u, range_size = %u\n", min, range_size); for (i = 0; ; ++key) { *keyptr = htons(min + key % range_size); if (++i == range_size || !nf_nat_used_tuple(tuple, ct)) return; } pr_debug("%p: no NAT mapping\n", ct); return; }
static int icmp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { static u_int16_t id; unsigned int range_size; unsigned int i; range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1; /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) range_size = 0xFFFF; for (i = 0; i < range_size; i++, id++) { tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + (id % range_size)); if (!nf_nat_used_tuple(tuple, ct)) return 1; } return 0; }
int udp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { static u_int16_t port; __be16 *portptr; unsigned int range_size = 0; unsigned int min = 0; unsigned int i = 0; if (maniptype == IP_NAT_MANIP_SRC) portptr = &tuple->src.u.udp.port; else portptr = &tuple->dst.u.udp.port; /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == IP_NAT_MANIP_DST) return 0; } else { min = ntohs(range->min.udp.port); range_size = ntohs(range->max.udp.port) - min + 1; } //if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) port = net_random(); for (i = 0; i < range_size; i++, port++) { *portptr = htons(min + port % range_size); if (!nf_nat_used_tuple(tuple, ct)) return 1; } return 0; }
/* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING, * we change the source to map into the range. For NF_INET_PRE_ROUTING * and NF_INET_LOCAL_OUT, we change the destination to map into the * range. It might not be possible to get a unique tuple, but we try. * At worst (or if we race), we will end up with a final duplicate in * __ip_conntrack_confirm and drop the packet. */ static void get_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *orig_tuple, const struct nf_nat_range *range, struct nf_conn *ct, enum nf_nat_manip_type maniptype) { const struct nf_conntrack_zone *zone; const struct nf_nat_l3proto *l3proto; const struct nf_nat_l4proto *l4proto; struct net *net = nf_ct_net(ct); zone = nf_ct_zone(ct); rcu_read_lock(); l3proto = __nf_nat_l3proto_find(orig_tuple->src.l3num); l4proto = __nf_nat_l4proto_find(orig_tuple->src.l3num, orig_tuple->dst.protonum); /* 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 (maniptype == NF_NAT_MANIP_SRC && !(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { /* try the original tuple first */ if (in_range(l3proto, l4proto, orig_tuple, range)) { if (!nf_nat_used_tuple(orig_tuple, ct)) { *tuple = *orig_tuple; goto out; } } else if (find_appropriate_src(net, zone, l3proto, l4proto, orig_tuple, tuple, range)) { pr_debug("get_unique_tuple: Found current src map\n"); if (!nf_nat_used_tuple(tuple, ct)) goto out; } } /* 2) Select the least-used IP/proto combination in the given range */ *tuple = *orig_tuple; find_best_ips_proto(zone, tuple, range, ct, maniptype); /* 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 (!(range->flags & NF_NAT_RANGE_PROTO_RANDOM_ALL)) { if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { if (l4proto->in_range(tuple, maniptype, &range->min_proto, &range->max_proto) && (range->min_proto.all == range->max_proto.all || !nf_nat_used_tuple(tuple, ct))) goto out; } else if (!nf_nat_used_tuple(tuple, ct)) { goto out; } } /* Last change: get protocol to try to obtain unique tuple. */ l4proto->unique_tuple(l3proto, tuple, range, maniptype, ct); out: rcu_read_unlock(); }
bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, const struct nf_conn *ct, u_int16_t *rover) { unsigned int range_size, min, i; __be16 *portptr; u_int16_t off; #if defined (CONFIG_RTL_HARDWARE_NAT) && defined (CONFIG_RTL_INBOUND_COLLISION_AVOIDANCE) unsigned int tryCnt=0; rtl865x_napt_entry rtl865xNaptEntry; unsigned int asicNaptHashScore=0; unsigned int highestScore=0; unsigned int lowestScore=0; __be16 bestCandidatePort=0; __be16 newOff=0; #endif if (maniptype == IP_NAT_MANIP_SRC) portptr = &tuple->src.u.all; else portptr = &tuple->dst.u.all; /* If no range specified... */ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == IP_NAT_MANIP_DST) return false; if (ntohs(*portptr) < 1024) { /* Loose convention: >> 512 is credential passing */ if (ntohs(*portptr) < 512) { min = 1; range_size = 511 - min + 1; } else { min = 600; range_size = 1023 - min + 1; } } else { min = 1024; range_size = 65535 - 1024 + 1; } } else { min = ntohs(range->min.all); range_size = ntohs(range->max.all) - min + 1; } if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip, maniptype == IP_NAT_MANIP_SRC ? tuple->dst.u.all : tuple->src.u.all); else off = *rover; #if defined (CONFIG_RTL_HARDWARE_NAT) && defined (CONFIG_RTL_INBOUND_COLLISION_AVOIDANCE) if(ct->master || (ct->status & IPS_EXPECTED)){ for (i = 0; i < range_size; i++, off++) { *portptr = htons(min + off % range_size); if (nf_nat_used_tuple(tuple, ct)) continue; if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) *rover = off; return true; } }else { for (i = 0; i < range_size; i++) { if((gHwNatEnabled) && (maniptype==IP_NAT_MANIP_SRC)) { rtl865x_optimizeExtPort(off++, range_size, &newOff); *portptr = htons(min + newOff % range_size); } else { *portptr = htons(min + off % range_size); off++; } if (nf_nat_used_tuple(tuple, ct)) continue; if((gHwNatEnabled) && (maniptype==IP_NAT_MANIP_SRC)) { /* outbound flow */ rtl865xNaptEntry.protocol = (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum==IPPROTO_TCP)? 1: 0; rtl865xNaptEntry.intIp = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; rtl865xNaptEntry.remIp = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip; rtl865xNaptEntry.extIp = tuple->src.u3.ip; rtl865xNaptEntry.intPort = rtl865xNaptEntry.protocol?ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port:ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port; rtl865xNaptEntry.remPort = rtl865xNaptEntry.protocol?ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port:ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.udp.port; rtl865xNaptEntry.extPort= rtl865xNaptEntry.protocol?tuple->src.u.tcp.port:tuple->src.u.udp.port; rtl865x_getAsicNaptHashScore(&rtl865xNaptEntry,&asicNaptHashScore); if(asicNaptHashScore==100) { highestScore=asicNaptHashScore; lowestScore=asicNaptHashScore; bestCandidatePort=*portptr; } else { /*otherwise use the best cadidate port*/ if(bestCandidatePort==0) { bestCandidatePort=*portptr; highestScore=asicNaptHashScore; lowestScore=asicNaptHashScore; } if(asicNaptHashScore>highestScore) { highestScore=asicNaptHashScore; bestCandidatePort=*portptr; } if(asicNaptHashScore<lowestScore) { lowestScore=asicNaptHashScore; } if(tryCnt++<=MAX_EXTPORT_TRY_CNT) { continue; } else { *portptr=bestCandidatePort; } } rtl865xNaptEntry.extPort=*portptr; rtl865x_preReserveConn(&rtl865xNaptEntry); } /* printk("%s:%d:maniptype is %d, %s (%u.%u.%u.%u:%u -> %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u) ,lowestScore is %d,highestScore is %d\n\n\n", __FUNCTION__,__LINE__,maniptype, rtl865xNaptEntry.protocol?"tcp":"udp", NIPQUAD(rtl865xNaptEntry.intIp), rtl865xNaptEntry.intPort, NIPQUAD(rtl865xNaptEntry.extIp), rtl865xNaptEntry.extPort, NIPQUAD(rtl865xNaptEntry.remIp), rtl865xNaptEntry.remPort,lowestScore, highestScore); */ if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) *rover = off; return true; } } #else for (i = 0; i < range_size; i++, off++) { *portptr = htons(min + off % range_size); if (nf_nat_used_tuple(tuple, ct)) continue; if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) *rover = off; return true; } #endif return false; }