diff -u dnsmasq-2.75/debian/changelog dnsmasq-2.75/debian/changelog --- dnsmasq-2.75/debian/changelog +++ dnsmasq-2.75/debian/changelog @@ -1,3 +1,12 @@ +dnsmasq (2.75-1ubuntu0.16.04.2) xenial; urgency=medium + + * Add two upstream patches to fix binding to an interface being + destroyed and recreated. LP: #1639776. + + 2675f2061525bc954be14988d64384b74aa7bf8b + + 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d + + -- Nishanth Aravamudan Mon, 27 Mar 2017 17:22:13 -0700 + dnsmasq (2.75-1ubuntu0.16.04.1) xenial-security; urgency=medium * SECURITY UPDATE: denial of service via crafted CNAME (LP: #1581181) only in patch2: unchanged: --- dnsmasq-2.75.orig/src/dnsmasq.h +++ dnsmasq-2.75/src/dnsmasq.h @@ -492,6 +492,7 @@ int fd; union mysockaddr source_addr; char interface[IF_NAMESIZE+1]; + unsigned int ifindex, used; struct serverfd *next; }; only in patch2: unchanged: --- dnsmasq-2.75.orig/src/network.c +++ dnsmasq-2.75/src/network.c @@ -1191,6 +1191,7 @@ 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 @@ -1211,11 +1212,15 @@ 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. */ @@ -1237,11 +1242,13 @@ errno = errsave; return NULL; } - + strcpy(sfd->interface, intname); sfd->source_addr = *addr; sfd->next = daemon->sfds; + sfd->ifindex = ifindex; daemon->sfds = sfd; + return sfd; } @@ -1417,12 +1424,16 @@ { struct irec *iface; struct server *serv; + struct serverfd *sfd, *tmp, **up; int port = 0; /* interface may be new since startup */ if (!option_bool(OPT_NOWILD)) enumerate_interfaces(0); + for (sfd = daemon->sfds; sfd; sfd = sfd->next) + sfd->used = 0; + for (serv = daemon->servers; serv; serv = serv->next) { if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) @@ -1458,6 +1469,9 @@ serv->flags |= SERV_MARK; continue; } + + if (serv->sfd) + serv->sfd->used = 1; } if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS)) @@ -1490,6 +1504,20 @@ } } + /* Remove unused sfds */ + for (sfd = daemon->sfds, up = &daemon->sfds; sfd; sfd = tmp) + { + tmp = sfd->next; + if (!sfd->used) + { + *up = sfd->next; + close(sfd->fd); + free(sfd); + } + else + up = &sfd->next; + } + cleanup_servers(); }