commit 64d3d2c83b30c751570faf0c5d527ff3da9f2036 Author: Beniamino Galvani Date: Sun Aug 28 20:44:05 2016 +0100 Handle binding upstream servers to an interface (--server=1.2.3.4@eth0) when the named interface is destroyed and recreated in the kernel. diff --git a/src/dbus.c b/src/dbus.c index 7379341..e56d8c7 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -161,6 +161,10 @@ static void add_update_server(union mysockaddr *addr, if (serv) { + serv->sfd = NULL; + serv->queries = 0; + serv->failed_queries = 0; + if (interface) strcpy(serv->interface, interface); else diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 69ae7a7..7b8020e 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -412,6 +412,7 @@ struct serverfd { int fd; union mysockaddr source_addr; char interface[IF_NAMESIZE+1]; + unsigned int ifindex, used; struct serverfd *next; }; diff --git a/src/network.c b/src/network.c index 792914b..d2bebcc 100644 --- a/src/network.c +++ b/src/network.c @@ -839,6 +839,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp) static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname) { struct serverfd *sfd; + unsigned int ifindex = 0; int errsave; /* when using random ports, servers which would otherwise use @@ -859,11 +860,15 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname) return NULL; #endif } + + if (intname && strlen(intname) != 0) + ifindex = if_nametoindex(intname); /* index == 0 when not binding to an interface */ /* may have a suitable one already */ for (sfd = daemon->sfds; sfd; sfd = sfd->next ) if (sockaddr_isequal(&sfd->source_addr, addr) && - strcmp(intname, sfd->interface) == 0) + strcmp(intname, sfd->interface) == 0 && + ifindex == sfd->ifindex) return sfd; /* need to make a new one. */ @@ -885,11 +890,13 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname) errno = errsave; return NULL; } - + strcpy(sfd->interface, intname); sfd->source_addr = *addr; sfd->next = daemon->sfds; + sfd->ifindex = ifindex; daemon->sfds = sfd; + return sfd; } @@ -944,12 +951,16 @@ void check_servers(void) { struct irec *iface; struct server *new, *tmp, *ret = NULL; + struct serverfd *sfd, *tmpfd, **up; int port = 0; /* interface may be new since startup */ if (!option_bool(OPT_NOWILD)) enumerate_interfaces(); + for (sfd = daemon->sfds; sfd; sfd = sfd->next) + sfd->used = 0; + for (new = daemon->servers; new; new = tmp) { tmp = new->next; @@ -987,6 +998,9 @@ void check_servers(void) free(new); continue; } + + if (new->sfd) + new->sfd->used = 1; } /* reverse order - gets it right. */ @@ -1019,6 +1033,20 @@ void check_servers(void) } } + /* Remove unused sfds */ + for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmpfd) + { + tmpfd = sfd->next; + if (!sfd->used) + { + *up = sfd->next; + close(sfd->fd); + free(sfd); + } + else + up = &sfd->next; + } + daemon->servers = ret; }