Skip to content

Commit

Permalink
inet: set IP_FREEBIND before binding socket to an ipv6 address (v2)
Browse files Browse the repository at this point in the history
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: Ross Boucher <boucher@gmail.com>
Signed-off-by: Andrew Vagin <avagin@virtuozzo.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
  • Loading branch information
avagin authored and xemul committed Nov 23, 2015
1 parent c9a61a2 commit 73a739b
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions sk-inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit 73a739b

Please sign in to comment.