/* generate unique tuple ... */ static int gre_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_nat_range *range, enum ip_nat_manip_type maniptype, const struct ip_conntrack *conntrack) { u_int32_t min, i, range_size; u_int32_t key = 0, *keyptr; 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)) { switch (tuple->dst.u.gre.version) { case 0: DEBUGP("NATing GRE version 0 (ct=%p)\n", conntrack); min = 1; range_size = 0xffffffff; break; case GRE_VERSION_PPTP: DEBUGP("%p: NATing GRE PPTP\n", conntrack); min = 1; range_size = 0xffff; break; default: printk(KERN_WARNING "nat_gre: unknown GRE version\n"); return 0; break; } } else { min = ntohl(range->min.gre.key); range_size = ntohl(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 = htonl(min + key % range_size); if (!ip_nat_used_tuple(tuple, conntrack)) return 1; } DEBUGP("%p: no NAT mapping\n", conntrack); return 0; }
static int udp_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_nat_range *range, enum ip_nat_manip_type maniptype, const struct ip_conntrack *conntrack) { static u_int16_t port; __be16 *portptr; unsigned int range_size, min, i; 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; 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.udp.port); range_size = ntohs(range->max.udp.port) - min + 1; } /* Start from random port to avoid prediction */ 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 (!ip_nat_used_tuple(tuple, conntrack)) return 1; } return 0; }
static int icmp_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_nat_range *range, enum ip_nat_manip_type maniptype, const struct ip_conntrack *conntrack) { 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 (!ip_nat_used_tuple(tuple, conntrack)) return 1; } return 0; }
/* generate unique tuple ... */ static int gre_unique_tuple(struct ip_conntrack_tuple *tuple, const struct ip_nat_range *range, enum ip_nat_manip_type maniptype, const struct ip_conntrack *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 (!ip_nat_used_tuple(tuple, conntrack)) return 1; } DEBUGP("%p: no NAT mapping\n", conntrack); return 0; }