* UDPv4 port allocation problem
@ 2007-08-23 7:16 Tóth László Attila
2007-08-23 17:04 ` Rick Jones
0 siblings, 1 reply; 4+ messages in thread
From: Tóth László Attila @ 2007-08-23 7:16 UTC (permalink / raw)
To: netdev
Hello,
I noticed that it is possible that the kernel allocates the same UDP
port to an application that was used and closed immediately before the
new application got it. This means that applications that do not specify
an exact port and rely on the kernel to allocate a port for them might
see traffic originally meant for another application.
Imagine that two applications want to resolve a name in DNS at about the
same time. The following happens:
* first app sends out the DNS query then closes the socket without
waiting for an answer (e.g. it got interrupted by Ctrl+C)
* second app opens an UDP socket, and gets the same port, originally
assigned to app#1, sends out the DNS query
* DNS server responds, the response goes to app#2
DNS might not be the perfect example, but you get the idea.
Applications do not expect to receive data on newly opened sockets, not
to mention the security implications.
TCP on the other hand increases the allocated port number for each new
socket, the same behaviour for UDP would add certain amount of time that
decreases this risk.
Is the current behaviour intended?
Regards,
Laszlo Attila Toth
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: UDPv4 port allocation problem
2007-08-23 7:16 UDPv4 port allocation problem Tóth László Attila
@ 2007-08-23 17:04 ` Rick Jones
2007-08-23 18:32 ` [PATCH] udp: randomize port selection Stephen Hemminger
0 siblings, 1 reply; 4+ messages in thread
From: Rick Jones @ 2007-08-23 17:04 UTC (permalink / raw)
To: panther; +Cc: netdev
Tóth László Attila wrote:
> Hello,
>
> I noticed that it is possible that the kernel allocates the same UDP
_Which_ kernel - or rather which rev? There are lots of linux kernels
potentially out there...
> port to an application that was used and closed immediately before the
> new application got it. This means that applications that do not specify
> an exact port and rely on the kernel to allocate a port for them might
> see traffic originally meant for another application.
>
> Imagine that two applications want to resolve a name in DNS at about the
> same time. The following happens:
> * first app sends out the DNS query then closes the socket without
> waiting for an answer (e.g. it got interrupted by Ctrl+C)
> * second app opens an UDP socket, and gets the same port, originally
> assigned to app#1, sends out the DNS query
> * DNS server responds, the response goes to app#2
>
> DNS might not be the perfect example, but you get the idea.
> Applications do not expect to receive data on newly opened sockets, not
> to mention the security implications.
Actually, all applications using UDP are required to cope with just about
anything since there are no guarantees with UDP of anything other than the
checksum generally protecting one from corrupt data.
In the specific case of DNS, the resolver library will (damn well better) be
checking the answer it gets against the query it sent. There will be a
transaction ID check, and IIRC a check of the returned query against the query sent.
> TCP on the other hand increases the allocated port number for each new
> socket, the same behaviour for UDP would add certain amount of time that
> decreases this risk.
Does it always? If you wait for the length of TIME_WAIT before issuing another
bind() request does the port number still increase?
While it might be nice to step through the anonymous port space in some fashion
(I suspect the argument would be made that it should be somewhat random to
preclude guessing from the outside), applications using UDP are still required
to expect the unexpected wrt data arriving on their socket.
rick jones
>
> Is the current behaviour intended?
>
> Regards,
> Laszlo Attila Toth
> -
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH] udp: randomize port selection
2007-08-23 17:04 ` Rick Jones
@ 2007-08-23 18:32 ` Stephen Hemminger
2007-08-25 6:10 ` David Miller
0 siblings, 1 reply; 4+ messages in thread
From: Stephen Hemminger @ 2007-08-23 18:32 UTC (permalink / raw)
To: Rick Jones, David S. Miller; +Cc: panther, netdev
This patch causes UDP port allocation to be randomized like TCP.
The earlier code would always choose same port (ie first empty list).
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
--- a/net/ipv4/udp.c 2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv4/udp.c 2007-08-23 11:29:02.000000000 -0700
@@ -113,9 +113,8 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_sta
struct hlist_head udp_hash[UDP_HTABLE_SIZE];
DEFINE_RWLOCK(udp_hash_lock);
-static int udp_port_rover;
-
-static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
+static inline int __udp_lib_lport_inuse(__u16 num,
+ const struct hlist_head udptable[])
{
struct sock *sk;
struct hlist_node *node;
@@ -132,11 +131,10 @@ static inline int __udp_lib_lport_inuse(
* @sk: socket struct in question
* @snum: port number to look up
* @udptable: hash list table, must be of UDP_HTABLE_SIZE
- * @port_rover: pointer to record of last unallocated port
* @saddr_comp: AF-dependent comparison of bound local IP addresses
*/
int __udp_lib_get_port(struct sock *sk, unsigned short snum,
- struct hlist_head udptable[], int *port_rover,
+ struct hlist_head udptable[],
int (*saddr_comp)(const struct sock *sk1,
const struct sock *sk2 ) )
{
@@ -146,49 +144,56 @@ int __udp_lib_get_port(struct sock *sk,
int error = 1;
write_lock_bh(&udp_hash_lock);
- if (snum == 0) {
- int best_size_so_far, best, result, i;
- if (*port_rover > sysctl_local_port_range[1] ||
- *port_rover < sysctl_local_port_range[0])
- *port_rover = sysctl_local_port_range[0];
- best_size_so_far = 32767;
- best = result = *port_rover;
- for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
- int size;
-
- head = &udptable[result & (UDP_HTABLE_SIZE - 1)];
- if (hlist_empty(head)) {
- if (result > sysctl_local_port_range[1])
- result = sysctl_local_port_range[0] +
- ((result - sysctl_local_port_range[0]) &
- (UDP_HTABLE_SIZE - 1));
+ if (!snum) {
+ int i;
+ int low = sysctl_local_port_range[0];
+ int high = sysctl_local_port_range[1];
+ unsigned rover, best, best_size_so_far;
+
+ best_size_so_far = UINT_MAX;
+ best = rover = net_random() % (high - low) + low;
+
+ /* 1st pass: look for empty (or shortest) hash chain */
+ for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+ int size = 0;
+
+ head = &udptable[rover & (UDP_HTABLE_SIZE - 1)];
+ if (hlist_empty(head))
goto gotit;
- }
- size = 0;
+
sk_for_each(sk2, node, head) {
if (++size >= best_size_so_far)
goto next;
}
best_size_so_far = size;
- best = result;
+ best = rover;
next:
- ;
+ /* fold back if end of range */
+ if (++rover > high)
+ rover = low + ((rover - low)
+ & (UDP_HTABLE_SIZE - 1));
+
+
}
- result = best;
- for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE;
- i++, result += UDP_HTABLE_SIZE) {
- if (result > sysctl_local_port_range[1])
- result = sysctl_local_port_range[0]
- + ((result - sysctl_local_port_range[0]) &
- (UDP_HTABLE_SIZE - 1));
- if (! __udp_lib_lport_inuse(result, udptable))
- break;
+
+ /* 2nd pass: find hole in shortest hash chain */
+ rover = best;
+ for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
+ if (! __udp_lib_lport_inuse(rover, udptable))
+ goto gotit;
+ rover += UDP_HTABLE_SIZE;
+ if (rover > high)
+ rover = low + ((rover - low)
+ & (UDP_HTABLE_SIZE - 1));
}
- if (i >= (1 << 16) / UDP_HTABLE_SIZE)
- goto fail;
+
+
+ /* All ports in use! */
+ goto fail;
+
gotit:
- *port_rover = snum = result;
+ snum = rover;
} else {
head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
@@ -201,6 +206,7 @@ gotit:
(*saddr_comp)(sk, sk2) )
goto fail;
}
+
inet_sk(sk)->num = snum;
sk->sk_hash = snum;
if (sk_unhashed(sk)) {
@@ -217,7 +223,7 @@ fail:
int udp_get_port(struct sock *sk, unsigned short snum,
int (*scmp)(const struct sock *, const struct sock *))
{
- return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
+ return __udp_lib_get_port(sk, snum, udp_hash, scmp);
}
int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
--- a/net/ipv4/udp_impl.h 2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv4/udp_impl.h 2007-08-23 11:26:48.000000000 -0700
@@ -9,7 +9,7 @@ extern int __udp4_lib_rcv(struct sk_bu
extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
extern int __udp_lib_get_port(struct sock *sk, unsigned short snum,
- struct hlist_head udptable[], int *port_rover,
+ struct hlist_head udptable[],
int (*)(const struct sock*,const struct sock*));
extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
--- a/net/ipv4/udplite.c 2007-08-23 09:44:22.000000000 -0700
+++ b/net/ipv4/udplite.c 2007-08-23 11:25:33.000000000 -0700
@@ -16,12 +16,11 @@
DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly;
struct hlist_head udplite_hash[UDP_HTABLE_SIZE];
-static int udplite_port_rover;
int udplite_get_port(struct sock *sk, unsigned short p,
int (*c)(const struct sock *, const struct sock *))
{
- return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c);
+ return __udp_lib_get_port(sk, p, udplite_hash, c);
}
static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] udp: randomize port selection
2007-08-23 18:32 ` [PATCH] udp: randomize port selection Stephen Hemminger
@ 2007-08-25 6:10 ` David Miller
0 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2007-08-25 6:10 UTC (permalink / raw)
To: shemminger; +Cc: rick.jones2, panther, netdev
From: Stephen Hemminger <shemminger@linux-foundation.org>
Date: Thu, 23 Aug 2007 11:32:26 -0700
> This patch causes UDP port allocation to be randomized like TCP.
> The earlier code would always choose same port (ie first empty list).
>
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Applied to net-2.6.24, thanks Stephen.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2007-08-25 6:10 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-23 7:16 UDPv4 port allocation problem Tóth László Attila
2007-08-23 17:04 ` Rick Jones
2007-08-23 18:32 ` [PATCH] udp: randomize port selection Stephen Hemminger
2007-08-25 6:10 ` David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).