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>
 
 #define IP_NAT_RANGE_MAP_IPS 1
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
 
 /* NAT sequence number modifications */
 struct ip_nat_seq {
 
 
 #define IP_NAT_RANGE_MAP_IPS 1
 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
+#define IP_NAT_RANGE_PROTO_RANDOM 4
 
 /* NAT sequence number modifications */
 struct nf_nat_seq {
 
        if (maniptype == IP_NAT_MANIP_SRC) {
                if (find_appropriate_src(orig_tuple, tuple, range)) {
                        DEBUGP("get_unique_tuple: Found current src map\n");
-                       if (!ip_nat_used_tuple(tuple, conntrack))
-                               return;
+                       if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+                               if (!ip_nat_used_tuple(tuple, conntrack))
+                                       return;
                }
        }
 
 
        proto = ip_nat_proto_find_get(orig_tuple->dst.protonum);
 
+       /* Change protocol info to have some randomization */
+       if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+               proto->unique_tuple(tuple, range, maniptype, conntrack);
+               ip_nat_proto_put(proto);
+               return;
+       }
+
        /* Only bother mapping if it's not already in range and unique */
        if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
             || proto->in_range(tuple, maniptype, &range->min, &range->max))
 
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
                range_size = ntohs(range->max.tcp.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)) {
 
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/netfilter.h>
 #include <linux/ip.h>
 #include <linux/udp.h>
                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))
 
                printk("DNAT: multiple ranges no longer supported\n");
                return 0;
        }
+       if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+               printk("DNAT: port randomization not supported\n");
+               return 0;
+       }
        return 1;
 }
 
 
        if (maniptype == IP_NAT_MANIP_SRC) {
                if (find_appropriate_src(orig_tuple, tuple, range)) {
                        DEBUGP("get_unique_tuple: Found current src map\n");
-                       if (!nf_nat_used_tuple(tuple, ct))
-                               return;
+                       if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
+                               if (!nf_nat_used_tuple(tuple, ct))
+                                       return;
                }
        }
 
 
        proto = nf_nat_proto_find_get(orig_tuple->dst.protonum);
 
+       /* Change protocol info to have some randomization */
+       if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
+               proto->unique_tuple(tuple, range, maniptype, ct);
+               nf_nat_proto_put(proto);
+               return;
+       }
+
        /* Only bother mapping if it's not already in range and unique */
        if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
             proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
 
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 
                range_size = ntohs(range->max.tcp.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))
 
 
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/random.h>
 #include <linux/ip.h>
 #include <linux/udp.h>
 
                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))
 
                printk("DNAT: multiple ranges no longer supported\n");
                return 0;
        }
+       if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
+               printk("DNAT: port randomization not supported\n");
+               return 0;
+       }
        return 1;
 }