Commit 41f4689a authored by Eric Leblond's avatar Eric Leblond Committed by David S. Miller

[NETFILTER]: NAT: optional source port randomization support

This patch adds support to NAT to randomize source ports.
Signed-off-by: default avatarEric Leblond <eric@inl.fr>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent cdd289a2
...@@ -16,6 +16,7 @@ enum ip_nat_manip_type ...@@ -16,6 +16,7 @@ enum ip_nat_manip_type
#define IP_NAT_RANGE_MAP_IPS 1 #define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
/* NAT sequence number modifications */ /* NAT sequence number modifications */
struct ip_nat_seq { struct ip_nat_seq {
......
...@@ -16,6 +16,7 @@ enum nf_nat_manip_type ...@@ -16,6 +16,7 @@ enum nf_nat_manip_type
#define IP_NAT_RANGE_MAP_IPS 1 #define IP_NAT_RANGE_MAP_IPS 1
#define IP_NAT_RANGE_PROTO_SPECIFIED 2 #define IP_NAT_RANGE_PROTO_SPECIFIED 2
#define IP_NAT_RANGE_PROTO_RANDOM 4
/* NAT sequence number modifications */ /* NAT sequence number modifications */
struct nf_nat_seq { struct nf_nat_seq {
......
...@@ -246,8 +246,9 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple, ...@@ -246,8 +246,9 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
if (maniptype == IP_NAT_MANIP_SRC) { if (maniptype == IP_NAT_MANIP_SRC) {
if (find_appropriate_src(orig_tuple, tuple, range)) { if (find_appropriate_src(orig_tuple, tuple, range)) {
DEBUGP("get_unique_tuple: Found current src map\n"); DEBUGP("get_unique_tuple: Found current src map\n");
if (!ip_nat_used_tuple(tuple, conntrack)) if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
return; if (!ip_nat_used_tuple(tuple, conntrack))
return;
} }
} }
...@@ -261,6 +262,13 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple, ...@@ -261,6 +262,13 @@ get_unique_tuple(struct ip_conntrack_tuple *tuple,
proto = ip_nat_proto_find_get(orig_tuple->dst.protonum); 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 */ /* Only bother mapping if it's not already in range and unique */
if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
|| proto->in_range(tuple, maniptype, &range->min, &range->max)) || proto->in_range(tuple, maniptype, &range->min, &range->max))
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/random.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
...@@ -75,6 +76,10 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple, ...@@ -75,6 +76,10 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
range_size = ntohs(range->max.tcp.port) - min + 1; 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++) { for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size); *portptr = htons(min + port % range_size);
if (!ip_nat_used_tuple(tuple, conntrack)) { if (!ip_nat_used_tuple(tuple, conntrack)) {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/random.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/udp.h> #include <linux/udp.h>
...@@ -74,6 +75,10 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple, ...@@ -74,6 +75,10 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple,
range_size = ntohs(range->max.udp.port) - min + 1; 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++) { for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size); *portptr = htons(min + port % range_size);
if (!ip_nat_used_tuple(tuple, conntrack)) if (!ip_nat_used_tuple(tuple, conntrack))
......
...@@ -193,6 +193,10 @@ static int ipt_dnat_checkentry(const char *tablename, ...@@ -193,6 +193,10 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n"); printk("DNAT: multiple ranges no longer supported\n");
return 0; return 0;
} }
if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
printk("DNAT: port randomization not supported\n");
return 0;
}
return 1; return 1;
} }
......
...@@ -254,8 +254,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -254,8 +254,9 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
if (maniptype == IP_NAT_MANIP_SRC) { if (maniptype == IP_NAT_MANIP_SRC) {
if (find_appropriate_src(orig_tuple, tuple, range)) { if (find_appropriate_src(orig_tuple, tuple, range)) {
DEBUGP("get_unique_tuple: Found current src map\n"); DEBUGP("get_unique_tuple: Found current src map\n");
if (!nf_nat_used_tuple(tuple, ct)) if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
return; if (!nf_nat_used_tuple(tuple, ct))
return;
} }
} }
...@@ -269,6 +270,13 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -269,6 +270,13 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
proto = nf_nat_proto_find_get(orig_tuple->dst.protonum); 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 */ /* Only bother mapping if it's not already in range and unique */
if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) || if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
proto->in_range(tuple, maniptype, &range->min, &range->max)) && proto->in_range(tuple, maniptype, &range->min, &range->max)) &&
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/random.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
...@@ -75,6 +76,9 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -75,6 +76,9 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.tcp.port) - min + 1; 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++) { for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size); *portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct)) if (!nf_nat_used_tuple(tuple, ct))
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/random.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/udp.h> #include <linux/udp.h>
...@@ -73,6 +74,9 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple, ...@@ -73,6 +74,9 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.udp.port) - min + 1; 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++) { for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size); *portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct)) if (!nf_nat_used_tuple(tuple, ct))
......
...@@ -226,6 +226,10 @@ static int ipt_dnat_checkentry(const char *tablename, ...@@ -226,6 +226,10 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n"); printk("DNAT: multiple ranges no longer supported\n");
return 0; return 0;
} }
if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
printk("DNAT: port randomization not supported\n");
return 0;
}
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment