summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-04-30 14:51:58 -0700
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-30 14:51:58 -0700
commitde34ed91c4ffa4727964a832c46e624dd1495cf5 (patch)
treee2745c338913fade9ce5ad76cccabeea9edfcaaf /net
parentb7b5f487ab39bc10ed0694af35651a03d9cb97ff (diff)
downloadlwn-de34ed91c4ffa4727964a832c46e624dd1495cf5.tar.gz
lwn-de34ed91c4ffa4727964a832c46e624dd1495cf5.zip
[UDP]: Do not allow specific bind when wildcard bind exists.
When allocating local ports, do not allow a bind to a port with a specific local address when a bind to that port with a wildcard local address already exists. Noticed by Linus. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/udp.c41
1 files changed, 33 insertions, 8 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index db313d964884..113e0c4c8a92 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -203,6 +203,13 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1));
+ hash = hash_port_and_addr(result, 0);
+ if (__udp_lib_port_inuse(hash, result,
+ 0, udptable))
+ continue;
+ if (!inet_sk(sk)->rcv_saddr)
+ break;
+
hash = hash_port_and_addr(result,
inet_sk(sk)->rcv_saddr);
if (! __udp_lib_port_inuse(hash, result,
@@ -214,18 +221,36 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
gotit:
*port_rover = snum = result;
} else {
- hash = hash_port_and_addr(snum, inet_sk(sk)->rcv_saddr);
+ hash = hash_port_and_addr(snum, 0);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head)
- if (sk2->sk_hash == hash &&
- sk2 != sk &&
- inet_sk(sk2)->num == snum &&
- (!sk2->sk_reuse || !sk->sk_reuse) &&
- (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
- || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
- (*saddr_comp)(sk, sk2) )
+ if (sk2->sk_hash == hash &&
+ sk2 != sk &&
+ inet_sk(sk2)->num == snum &&
+ (!sk2->sk_reuse || !sk->sk_reuse) &&
+ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
+ sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (*saddr_comp)(sk, sk2))
goto fail;
+
+ if (inet_sk(sk)->rcv_saddr) {
+ hash = hash_port_and_addr(snum,
+ inet_sk(sk)->rcv_saddr);
+ head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+
+ sk_for_each(sk2, node, head)
+ if (sk2->sk_hash == hash &&
+ sk2 != sk &&
+ inet_sk(sk2)->num == snum &&
+ (!sk2->sk_reuse || !sk->sk_reuse) &&
+ (!sk2->sk_bound_dev_if ||
+ !sk->sk_bound_dev_if ||
+ sk2->sk_bound_dev_if ==
+ sk->sk_bound_dev_if) &&
+ (*saddr_comp)(sk, sk2))
+ goto fail;
+ }
}
inet_sk(sk)->num = snum;
sk->sk_hash = hash;