diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-04-30 14:51:58 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-30 14:51:58 -0700 |
commit | de34ed91c4ffa4727964a832c46e624dd1495cf5 (patch) | |
tree | e2745c338913fade9ce5ad76cccabeea9edfcaaf /net/ipv4 | |
parent | b7b5f487ab39bc10ed0694af35651a03d9cb97ff (diff) | |
download | linux-de34ed91c4ffa4727964a832c46e624dd1495cf5.tar.gz linux-de34ed91c4ffa4727964a832c46e624dd1495cf5.tar.bz2 linux-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/ipv4')
-rw-r--r-- | net/ipv4/udp.c | 41 |
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; |