diff --git a/include/net/udp.h b/include/net/udp.h index 5348d80..925535e 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -111,6 +111,7 @@ extern atomic_t udp_memory_allocated; extern int sysctl_udp_mem[3]; extern int sysctl_udp_rmem_min; extern int sysctl_udp_wmem_min; +extern int sysctl_udp_port_randomization; struct sk_buff; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 7e3712c..ef811c3 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -599,6 +599,13 @@ static struct ctl_table ipv4_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &zero }, + { + .procname = "udp_port_randomization", + .data = &sysctl_udp_port_randomization, + .maxlen = sizeof(sysctl_udp_port_randomization), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + }, { } }; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 1f95348..f437d9d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -182,6 +182,9 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num, return res; } +int sysctl_udp_port_randomization = 1; +EXPORT_SYMBOL(sysctl_udp_port_randomization); + /** * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * @@ -202,6 +205,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, struct net *net = sock_net(sk); if (!snum) { + static int hint; int low, high, remaining; unsigned rand; unsigned short first, last; @@ -210,8 +214,13 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, inet_get_local_port_range(&low, &high); remaining = (high - low) + 1; - rand = net_random(); - first = (((u64)rand * remaining) >> 32) + low; + if (likely(sysctl_udp_port_randomization)) { + rand = net_random(); + first = (((u64)rand * remaining) >> 32) + low; + } else { + rand = 1; + first = hint; + } /* * force rand to be an odd multiple of UDP_HTABLE_SIZE */ @@ -233,8 +242,11 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, */ do { if (low <= snum && snum <= high && - !test_bit(snum >> udptable->log, bitmap)) + !test_bit(snum >> udptable->log, bitmap)) { + if (unlikely(!sysctl_udp_port_randomization)) + hint = snum; goto found; + } snum += rand; } while (snum != first); spin_unlock_bh(&hslot->lock);