Explicitly bind IPv6 addresses first.

merge-requests/1/head
Julien BLACHE 2009-03-13 17:02:25 +00:00
rodzic 5718d5a4ed
commit f29d2ac068
2 zmienionych plików z 93 dodań i 77 usunięć

Wyświetl plik

@ -10,7 +10,9 @@
2009-03-13 Julien Blache <jb@jblache.org> 2009-03-13 Julien Blache <jb@jblache.org>
* doc/descriptions-external/epkowa.desc: update for iScan 2.18.0, * doc/descriptions-external/epkowa.desc: update for iScan 2.18.0,
from Olaf Meeuwissen. from Olaf Meeuwissen.
* frontend/saned.c: rework Ilia's changes in check_host(). * frontend/saned.c: rework Ilia's changes in
check_host(). Explicitly bind IPv6 addresses first, introduce
do_bindings_family() split off of do_bindings().
2009-03-12 Ilia Sotnikov <hostcc@gmail.com> 2009-03-12 Ilia Sotnikov <hostcc@gmail.com>
* frontend/saned.c: * frontend/saned.c:

Wyświetl plik

@ -2673,19 +2673,96 @@ read_config (void)
#ifdef SANED_USES_AF_INDEP #ifdef SANED_USES_AF_INDEP
static void
do_bindings_family (int family, int *nfds, struct pollfd **fds, struct addrinfo *res)
{
struct addrinfo *resp;
struct pollfd *fdp;
short sane_port;
int fd = -1;
int on = 1;
int i;
fdp = *fds;
for (resp = res, i = 0; resp != NULL; resp = resp->ai_next, i++)
{
/* We're not interested */
if (resp->ai_family != family)
continue;
if (resp->ai_family == AF_INET)
{
sane_port = ntohs (((struct sockaddr_in *) resp->ai_addr)->sin_port);
}
#ifdef ENABLE_IPV6
else if (resp->ai_family == AF_INET6)
{
sane_port = ntohs (((struct sockaddr_in6 *) resp->ai_addr)->sin6_port);
}
#endif /* ENABLE_IPV6 */
else
continue;
DBG (DBG_DBG, "do_bindings: [%d] socket () using IPv%d\n", i, (family == AF_INET) ? 4 : 6);
if ((fd = socket (resp->ai_family, SOCK_STREAM, 0)) < 0)
{
DBG (DBG_ERR, "do_bindings: [%d] socket failed: %s\n", i, strerror (errno));
continue;
}
DBG (DBG_DBG, "do_bindings: [%d] setsockopt ()\n", i);
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
DBG (DBG_ERR, "do_bindings: [%d] failed to put socket in SO_REUSEADDR mode (%s)\n", i, strerror (errno));
DBG (DBG_DBG, "do_bindings: [%d] bind () to port %d\n", i, sane_port);
if (bind (fd, resp->ai_addr, resp->ai_addrlen) < 0)
{
/*
* Binding a socket may fail with EADDRINUSE if we already bound
* to an IPv6 addr returned by getaddrinfo (usually the first ones)
* and we're trying to bind to an IPv4 addr now.
* It can also fail because we're trying to bind an IPv6 socket and IPv6
* is not functional on this machine.
* In any case, a bind() call returning an error is not necessarily fatal.
*/
DBG (DBG_WARN, "do_bindings: [%d] bind failed: %s\n", i, strerror (errno));
close (fd);
continue;
}
DBG (DBG_DBG, "do_bindings: [%d] listen ()\n", i);
if (listen (fd, 1) < 0)
{
DBG (DBG_ERR, "do_bindings: [%d] listen failed: %s\n", i, strerror (errno));
close (fd);
continue;
}
fdp->fd = fd;
fdp->events = POLLIN;
(*nfds)++;
fdp++;
}
*fds = fdp;
}
static void static void
do_bindings (int *nfds, struct pollfd **fds) do_bindings (int *nfds, struct pollfd **fds)
{ {
struct addrinfo *res; struct addrinfo *res;
struct addrinfo *resp; struct addrinfo *resp;
struct addrinfo hints; struct addrinfo hints;
struct pollfd *fdp = NULL; struct pollfd *fdp;
int err; int err;
int i;
short sane_port;
int family;
int fd = -1;
int on = 1;
DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getaddrinfo)\n", SANED_SERVICE_NAME); DBG (DBG_DBG, "do_bindings: trying to get port for service \"%s\" (getaddrinfo)\n", SANED_SERVICE_NAME);
@ -2721,77 +2798,14 @@ do_bindings (int *nfds, struct pollfd **fds)
bail_out (1); bail_out (1);
} }
for (resp = res, i = 0, fdp = *fds; resp != NULL; resp = resp->ai_next, i++, fdp++) fdp = *fds;
{ *nfds = 0;
if (resp->ai_family == AF_INET)
{ /* bind IPv6 first, IPv4 second */
family = 4;
sane_port = ntohs (((struct sockaddr_in *) resp->ai_addr)->sin_port);
}
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
else if (resp->ai_family == AF_INET6) do_bindings_family (AF_INET6, nfds, &fdp, res);
{ #endif
family = 6; do_bindings_family (AF_INET, nfds, &fdp, res);
sane_port = ntohs (((struct sockaddr_in6 *) resp->ai_addr)->sin6_port);
}
#endif /* ENABLE_IPV6 */
else
{
fdp--;
(*nfds)--;
continue;
}
DBG (DBG_DBG, "do_bindings: [%d] socket () using IPv%d\n", i, family);
if ((fd = socket (resp->ai_family, SOCK_STREAM, 0)) < 0)
{
DBG (DBG_ERR, "do_bindings: [%d] socket failed: %s\n", i, strerror (errno));
fdp--;
(*nfds)--;
continue;
}
DBG (DBG_DBG, "do_bindings: [%d] setsockopt ()\n", i);
if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
DBG (DBG_ERR, "do_bindings: [%d] failed to put socket in SO_REUSEADDR mode (%s)\n", i, strerror (errno));
DBG (DBG_DBG, "do_bindings: [%d] bind () to port %d\n", i, sane_port);
if (bind (fd, resp->ai_addr, resp->ai_addrlen) < 0)
{
/*
* Binding a socket may fail with EADDRINUSE if we already bound
* to an IPv6 addr returned by getaddrinfo (usually the first ones)
* and we're trying to bind to an IPv4 addr now.
* It can also fail because we're trying to bind an IPv6 socket and IPv6
* is not functional on this machine.
* In any case, a bind() call returning an error is not necessarily fatal.
*/
DBG (DBG_WARN, "do_bindings: [%d] bind failed: %s\n", i, strerror (errno));
close (fd);
fdp--;
(*nfds)--;
continue;
}
DBG (DBG_DBG, "do_bindings: [%d] listen ()\n", i);
if (listen (fd, 1) < 0)
{
DBG (DBG_ERR, "do_bindings: [%d] listen failed: %s\n", i, strerror (errno));
close (fd);
fdp--;
(*nfds)--;
continue;
}
fdp->fd = fd;
fdp->events = POLLIN;
}
resp = NULL; resp = NULL;
freeaddrinfo (res); freeaddrinfo (res);