Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[NETFILTER]: NAT: optional source port randomization support

This patch adds support to NAT to randomize source ports.

Signed-off-by: Eric Leblond <eric@inl.fr>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Leblond and committed by
David S. Miller
41f4689a cdd289a2

+48 -4
+1
include/linux/netfilter_ipv4/ip_nat.h
··· 16 16 17 17 #define IP_NAT_RANGE_MAP_IPS 1 18 18 #define IP_NAT_RANGE_PROTO_SPECIFIED 2 19 + #define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */ 19 20 20 21 /* NAT sequence number modifications */ 21 22 struct ip_nat_seq {
+1
include/net/netfilter/nf_nat.h
··· 16 16 17 17 #define IP_NAT_RANGE_MAP_IPS 1 18 18 #define IP_NAT_RANGE_PROTO_SPECIFIED 2 19 + #define IP_NAT_RANGE_PROTO_RANDOM 4 19 20 20 21 /* NAT sequence number modifications */ 21 22 struct nf_nat_seq {
+10 -2
net/ipv4/netfilter/ip_nat_core.c
··· 246 246 if (maniptype == IP_NAT_MANIP_SRC) { 247 247 if (find_appropriate_src(orig_tuple, tuple, range)) { 248 248 DEBUGP("get_unique_tuple: Found current src map\n"); 249 - if (!ip_nat_used_tuple(tuple, conntrack)) 250 - return; 249 + if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) 250 + if (!ip_nat_used_tuple(tuple, conntrack)) 251 + return; 251 252 } 252 253 } 253 254 ··· 261 260 the range to make a unique tuple. */ 262 261 263 262 proto = ip_nat_proto_find_get(orig_tuple->dst.protonum); 263 + 264 + /* Change protocol info to have some randomization */ 265 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { 266 + proto->unique_tuple(tuple, range, maniptype, conntrack); 267 + ip_nat_proto_put(proto); 268 + return; 269 + } 264 270 265 271 /* Only bother mapping if it's not already in range and unique */ 266 272 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
+5
net/ipv4/netfilter/ip_nat_proto_tcp.c
··· 8 8 9 9 #include <linux/types.h> 10 10 #include <linux/init.h> 11 + #include <linux/random.h> 11 12 #include <linux/netfilter.h> 12 13 #include <linux/ip.h> 13 14 #include <linux/tcp.h> ··· 75 74 min = ntohs(range->min.tcp.port); 76 75 range_size = ntohs(range->max.tcp.port) - min + 1; 77 76 } 77 + 78 + /* Start from random port to avoid prediction */ 79 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) 80 + port = net_random(); 78 81 79 82 for (i = 0; i < range_size; i++, port++) { 80 83 *portptr = htons(min + port % range_size);
+5
net/ipv4/netfilter/ip_nat_proto_udp.c
··· 8 8 9 9 #include <linux/types.h> 10 10 #include <linux/init.h> 11 + #include <linux/random.h> 11 12 #include <linux/netfilter.h> 12 13 #include <linux/ip.h> 13 14 #include <linux/udp.h> ··· 74 73 min = ntohs(range->min.udp.port); 75 74 range_size = ntohs(range->max.udp.port) - min + 1; 76 75 } 76 + 77 + /* Start from random port to avoid prediction */ 78 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) 79 + port = net_random(); 77 80 78 81 for (i = 0; i < range_size; i++, port++) { 79 82 *portptr = htons(min + port % range_size);
+4
net/ipv4/netfilter/ip_nat_rule.c
··· 193 193 printk("DNAT: multiple ranges no longer supported\n"); 194 194 return 0; 195 195 } 196 + if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) { 197 + printk("DNAT: port randomization not supported\n"); 198 + return 0; 199 + } 196 200 return 1; 197 201 } 198 202
+10 -2
net/ipv4/netfilter/nf_nat_core.c
··· 254 254 if (maniptype == IP_NAT_MANIP_SRC) { 255 255 if (find_appropriate_src(orig_tuple, tuple, range)) { 256 256 DEBUGP("get_unique_tuple: Found current src map\n"); 257 - if (!nf_nat_used_tuple(tuple, ct)) 258 - return; 257 + if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) 258 + if (!nf_nat_used_tuple(tuple, ct)) 259 + return; 259 260 } 260 261 } 261 262 ··· 269 268 the range to make a unique tuple. */ 270 269 271 270 proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); 271 + 272 + /* Change protocol info to have some randomization */ 273 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) { 274 + proto->unique_tuple(tuple, range, maniptype, ct); 275 + nf_nat_proto_put(proto); 276 + return; 277 + } 272 278 273 279 /* Only bother mapping if it's not already in range and unique */ 274 280 if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
+4
net/ipv4/netfilter/nf_nat_proto_tcp.c
··· 8 8 9 9 #include <linux/types.h> 10 10 #include <linux/init.h> 11 + #include <linux/random.h> 11 12 #include <linux/ip.h> 12 13 #include <linux/tcp.h> 13 14 ··· 75 74 min = ntohs(range->min.tcp.port); 76 75 range_size = ntohs(range->max.tcp.port) - min + 1; 77 76 } 77 + 78 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) 79 + port = net_random(); 78 80 79 81 for (i = 0; i < range_size; i++, port++) { 80 82 *portptr = htons(min + port % range_size);
+4
net/ipv4/netfilter/nf_nat_proto_udp.c
··· 8 8 9 9 #include <linux/types.h> 10 10 #include <linux/init.h> 11 + #include <linux/random.h> 11 12 #include <linux/ip.h> 12 13 #include <linux/udp.h> 13 14 ··· 73 72 min = ntohs(range->min.udp.port); 74 73 range_size = ntohs(range->max.udp.port) - min + 1; 75 74 } 75 + 76 + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) 77 + port = net_random(); 76 78 77 79 for (i = 0; i < range_size; i++, port++) { 78 80 *portptr = htons(min + port % range_size);
+4
net/ipv4/netfilter/nf_nat_rule.c
··· 226 226 printk("DNAT: multiple ranges no longer supported\n"); 227 227 return 0; 228 228 } 229 + if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) { 230 + printk("DNAT: port randomization not supported\n"); 231 + return 0; 232 + } 229 233 return 1; 230 234 } 231 235