提交 f24d43c0 编写于 作者: E Eric Dumazet 提交者: David S. Miller

udp: complete port availability checking

While looking at UDP port randomization, I noticed it
was litle bit pessimistic, not looking at type of sockets
(IPV6/IPV4) and not looking at bound addresses if any.

We should perform same tests than when binding to a
specific port.

This permits a cleanup of udp_lib_get_port()
Signed-off-by: NEric Dumazet <dada1@cosmosbay.com>
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
上级 626e264d
...@@ -122,14 +122,23 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min); ...@@ -122,14 +122,23 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
atomic_t udp_memory_allocated; atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated); EXPORT_SYMBOL(udp_memory_allocated);
static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, static int udp_lib_lport_inuse(struct net *net, __u16 num,
const struct hlist_head udptable[]) const struct hlist_head udptable[],
struct sock *sk,
int (*saddr_comp)(const struct sock *sk1,
const struct sock *sk2))
{ {
struct sock *sk; struct sock *sk2;
struct hlist_node *node; struct hlist_node *node;
sk_for_each(sk, node, &udptable[udp_hashfn(net, num)]) sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)])
if (net_eq(sock_net(sk), net) && sk->sk_hash == num) if (net_eq(sock_net(sk2), net) &&
sk2 != sk &&
sk2->sk_hash == num &&
(!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))
return 1; return 1;
return 0; return 0;
} }
...@@ -146,9 +155,6 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -146,9 +155,6 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
const struct sock *sk2 ) ) const struct sock *sk2 ) )
{ {
struct hlist_head *udptable = sk->sk_prot->h.udp_hash; struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
struct hlist_node *node;
struct hlist_head *head;
struct sock *sk2;
int error = 1; int error = 1;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
...@@ -165,32 +171,21 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -165,32 +171,21 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
rand = net_random(); rand = net_random();
snum = first = rand % remaining + low; snum = first = rand % remaining + low;
rand |= 1; rand |= 1;
while (__udp_lib_lport_inuse(net, snum, udptable)) { while (udp_lib_lport_inuse(net, snum, udptable, sk,
saddr_comp)) {
do { do {
snum = snum + rand; snum = snum + rand;
} while (snum < low || snum > high); } while (snum < low || snum > high);
if (snum == first) if (snum == first)
goto fail; goto fail;
} }
} else { } else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp))
head = &udptable[udp_hashfn(net, snum)]; goto fail;
sk_for_each(sk2, node, head)
if (sk2->sk_hash == snum &&
sk2 != sk &&
net_eq(sock_net(sk2), net) &&
(!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; inet_sk(sk)->num = snum;
sk->sk_hash = snum; sk->sk_hash = snum;
if (sk_unhashed(sk)) { if (sk_unhashed(sk)) {
head = &udptable[udp_hashfn(net, snum)]; sk_add_node(sk, &udptable[udp_hashfn(net, snum)]);
sk_add_node(sk, head);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
} }
error = 0; error = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册