Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2731

kernel-2.6.18-238.el5.src.rpm

From: Vitaly Mayatskikh <vmayatsk@redhat.com>
Date: Tue, 10 Feb 2009 17:06:29 +0100
Subject: [net] improve udp port randomization
Message-id: m3k57yuvi2.wl%vmayatsk@redhat.com
O-Subject: [RHEL-5.4 patch] bz480951 Improve udp port randomization
Bugzilla: 480951
RH-Acked-by: Neil Horman <nhorman@redhat.com>
RH-Acked-by: David Miller <davem@redhat.com>
RH-Acked-by: Anton Arapov <aarapov@redhat.com>

Description:
============
Recently we have applied udp randomization patch to help BIND with
dns cache poisoning. However, the quality of random ports numbers
distribution was not so good, because kernel is trying to optimize
hash chains and, thus, reduces results of random numbers generator
work. The other problem we killed performance of "bind socket to
random port" operation. Upstream has solved both problems recently
(and greatly improved performance even over pre-randomization kernel),
but the code base was change significantly. As for me, it's not a
good idea to port these changes to RHEL-4 and even -5.

This patch skips hash optimization part for good (free) port numbers.
Also it improves the speed of bind(0) operation in compare with plain
RHEL-5.3 kernel.

Upstream status:
================
Upstream code uses the same idea, but has more fine grained locks
around hash table. Therefore, it was decided not to port all changes to
RHEL kernels.

Test status:
============
Was tested extensively, no regressions were observed.

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 953cf99..3e9d21a 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -147,6 +147,9 @@ static int udp_v4_get_port(struct sock *sk, unsigned short snum)
 		best_size_so_far = UINT_MAX;
 		best = rover = net_random() % remaining + low;
 
+		if (!udp_lport_inuse(rover))
+			goto gotit;
+
 		/* 1st pass: look for empty (or shortest) hash chain */
 		for (i = 0; i < UDP_HTABLE_SIZE; i++) {
 			struct hlist_head *list;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index bdbf323..f6d36e0 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -80,6 +80,9 @@ static int udp_v6_get_port(struct sock *sk, unsigned short snum)
 		best_size_so_far = UINT_MAX;
 		best = rover = net_random() % remaining + low;
 
+		if (!udp_lport_inuse(rover))
+			goto gotit;
+
 		/* 1st pass: look for empty (or shortest) hash chain */
 		for (i = 0; i < UDP_HTABLE_SIZE; i++) {
 			int size = 0;