aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-04-30 17:51:58 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-30 17:51:58 -0400
commitde34ed91c4ffa4727964a832c46e624dd1495cf5 (patch)
treee2745c338913fade9ce5ad76cccabeea9edfcaaf
parentb7b5f487ab39bc10ed0694af35651a03d9cb97ff (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>
-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,
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,
214gotit: 221gotit:
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;