Commit 73a739b8 authored by Andrew Vagin's avatar Andrew Vagin Committed by Pavel Emelyanov

inet: set IP_FREEBIND before binding socket to an ipv6 address (v2)

When we restore ipv6 addresses, they go through a “tentative” phase
and sockets could not be bound to them in this moment.

v2: add more comments in code
Reported-by: 's avatarRoss Boucher <boucher@gmail.com>
Signed-off-by: 's avatarAndrew Vagin <avagin@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent c9a61a20
......@@ -634,17 +634,50 @@ static int restore_sockaddr(union sockaddr_inet *sa,
int inet_bind(int sk, struct inet_sk_info *ii)
{
bool rst_freebind = false;
union sockaddr_inet addr;
int addr_size;
addr_size = restore_sockaddr(&addr, ii->ie->family,
ii->ie->src_port, ii->ie->src_addr);
/*
* ipv6 addresses go through a “tentative” phase and
* sockets could not be bound to them in this moment
* without setting IP_FREEBIND.
*/
if (ii->ie->family == AF_INET6) {
int yes = 1;
if (restore_opt(sk, SOL_IP, IP_FREEBIND, &yes))
return -1;
if (ii->ie->ip_opts && ii->ie->ip_opts->freebind)
/*
* The right value is already set, so
* don't need to restore it in restore_ip_opts()
*/
ii->ie->ip_opts->has_freebind = false;
else
rst_freebind = true;
}
if (bind(sk, (struct sockaddr *)&addr, addr_size) == -1) {
pr_perror("Can't bind inet socket");
return -1;
}
if (rst_freebind) {
int no = 0;
/*
* The "no" value is default, so it will not be
* restore in restore_ip_opts()
*/
if (restore_opt(sk, SOL_IP, IP_FREEBIND, &no))
return -1;
}
return 0;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment