diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-04-30 17:51:58 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-04-30 17:51:58 -0400 |
commit | de34ed91c4ffa4727964a832c46e624dd1495cf5 (patch) | |
tree | e2745c338913fade9ce5ad76cccabeea9edfcaaf /net/ipv4/udp.c | |
parent | b7b5f487ab39bc10ed0694af35651a03d9cb97ff (diff) |
[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/udp.c')
-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, | |||
203 | result = sysctl_local_port_range[0] | 203 | result = sysctl_local_port_range[0] |
204 | + ((result - sysctl_local_port_range[0]) & | 204 | + ((result - sysctl_local_port_range[0]) & |
205 | (UDP_HTABLE_SIZE - 1)); | 205 | (UDP_HTABLE_SIZE - 1)); |
206 | hash = hash_port_and_addr(result, 0); | ||
207 | if (__udp_lib_port_inuse(hash, result, | ||
208 | 0, udptable)) | ||
209 | continue; | ||
210 | if (!inet_sk(sk)->rcv_saddr) | ||
211 | break; | ||
212 | |||
206 | hash = hash_port_and_addr(result, | 213 | hash = hash_port_and_addr(result, |
207 | inet_sk(sk)->rcv_saddr); | 214 | inet_sk(sk)->rcv_saddr); |
208 | if (! __udp_lib_port_inuse(hash, result, | 215 | if (! __udp_lib_port_inuse(hash, result, |
@@ -214,18 +221,36 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
214 | gotit: | 221 | gotit: |
215 | *port_rover = snum = result; | 222 | *port_rover = snum = result; |
216 | } else { | 223 | } else { |
217 | hash = hash_port_and_addr(snum, inet_sk(sk)->rcv_saddr); | 224 | hash = hash_port_and_addr(snum, 0); |
218 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | 225 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; |
219 | 226 | ||
220 | sk_for_each(sk2, node, head) | 227 | sk_for_each(sk2, node, head) |
221 | if (sk2->sk_hash == hash && | 228 | if (sk2->sk_hash == hash && |
222 | sk2 != sk && | 229 | sk2 != sk && |
223 | inet_sk(sk2)->num == snum && | 230 | inet_sk(sk2)->num == snum && |
224 | (!sk2->sk_reuse || !sk->sk_reuse) && | 231 | (!sk2->sk_reuse || !sk->sk_reuse) && |
225 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if | 232 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || |
226 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | 233 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
227 | (*saddr_comp)(sk, sk2) ) | 234 | (*saddr_comp)(sk, sk2)) |
228 | goto fail; | 235 | goto fail; |
236 | |||
237 | if (inet_sk(sk)->rcv_saddr) { | ||
238 | hash = hash_port_and_addr(snum, | ||
239 | inet_sk(sk)->rcv_saddr); | ||
240 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | ||
241 | |||
242 | sk_for_each(sk2, node, head) | ||
243 | if (sk2->sk_hash == hash && | ||
244 | sk2 != sk && | ||
245 | inet_sk(sk2)->num == snum && | ||
246 | (!sk2->sk_reuse || !sk->sk_reuse) && | ||
247 | (!sk2->sk_bound_dev_if || | ||
248 | !sk->sk_bound_dev_if || | ||
249 | sk2->sk_bound_dev_if == | ||
250 | sk->sk_bound_dev_if) && | ||
251 | (*saddr_comp)(sk, sk2)) | ||
252 | goto fail; | ||
253 | } | ||
229 | } | 254 | } |
230 | inet_sk(sk)->num = snum; | 255 | inet_sk(sk)->num = snum; |
231 | sk->sk_hash = hash; | 256 | sk->sk_hash = hash; |