mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.59.tar.gz
This commit is contained in:
@@ -184,7 +184,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
if (!((*callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
(int)if_nametoindex(ifr->ifr_name), 0,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.58"
|
||||
#define VERSION "2.59"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -74,7 +74,6 @@
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
#define LOG_MAX 5 /* log-queue length */
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||
|
||||
/* DBUS interface specifics */
|
||||
|
||||
@@ -190,7 +190,7 @@ int main (int argc, char **argv)
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
daemon->listeners = create_bound_listeners();
|
||||
create_bound_listeners(1);
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
@@ -204,7 +204,7 @@ int main (int argc, char **argv)
|
||||
}
|
||||
}
|
||||
else
|
||||
daemon->listeners = create_wildcard_listeners();
|
||||
create_wildcard_listeners();
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
@@ -397,11 +397,17 @@ int main (int argc, char **argv)
|
||||
|
||||
if (ent_pw && ent_pw->pw_uid != 0)
|
||||
{
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
||||
if (is_dad_listeners())
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||
else
|
||||
data->effective = data->permitted = data->inheritable =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
|
||||
/* Tell kernel to not clear capabilities when dropping root */
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||
@@ -443,8 +449,12 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
if (is_dad_listeners())
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||
else
|
||||
data->effective = data->permitted =
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||
data->inheritable = 0;
|
||||
|
||||
/* lose the setuid and setgid capbilities */
|
||||
@@ -605,6 +615,13 @@ int main (int argc, char **argv)
|
||||
t.tv_usec = 250000;
|
||||
tp = &t;
|
||||
}
|
||||
/* Wake every second whilst waiting for DAD to complete */
|
||||
else if (is_dad_listeners())
|
||||
{
|
||||
t.tv_sec = 1;
|
||||
t.tv_usec = 0;
|
||||
tp = &t;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||
@@ -659,6 +676,15 @@ int main (int argc, char **argv)
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
/* Check the interfaces to see if any have exited DAD state
|
||||
and if so, bind the address. */
|
||||
if (is_dad_listeners())
|
||||
{
|
||||
enumerate_interfaces();
|
||||
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
|
||||
@@ -363,7 +363,7 @@ struct server {
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
int tftp_ok, mtu;
|
||||
int tftp_ok, mtu, done, dad;
|
||||
char *name;
|
||||
struct irec *next;
|
||||
};
|
||||
@@ -829,8 +829,9 @@ void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
struct listener *create_wildcard_listeners(void);
|
||||
struct listener *create_bound_listeners(void);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
|
||||
int fix_fd(int fd);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
|
||||
@@ -222,7 +222,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
|
||||
if (addrp)
|
||||
if (!((*callback)(addrp, ifa->ifa_scope, ifa->ifa_index, parm)))
|
||||
if (!((*callback)(addrp, ifa->ifa_index,
|
||||
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
105
src/network.c
105
src/network.c
@@ -187,7 +187,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
union mysockaddr *addr, struct in_addr netmask)
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
struct irec *iface;
|
||||
int fd, mtu = 0, loopback;
|
||||
@@ -202,8 +202,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
we call this routine multiple times. */
|
||||
for (iface = *irecp; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
return 1;
|
||||
|
||||
{
|
||||
iface->dad = dad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
@@ -283,6 +286,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
iface->netmask = netmask;
|
||||
iface->tftp_ok = tftp_ok;
|
||||
iface->mtu = mtu;
|
||||
iface->dad = dad;
|
||||
iface->done = 0;
|
||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
strcpy(iface->name, ifr.ifr_name);
|
||||
iface->next = *irecp;
|
||||
@@ -296,7 +301,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static int iface_allowed_v6(struct in6_addr *local,
|
||||
int scope, int if_index, void *vparam)
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* dummy */
|
||||
@@ -312,7 +317,7 @@ static int iface_allowed_v6(struct in6_addr *local,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = scope;
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -330,7 +335,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||
}
|
||||
|
||||
int enumerate_interfaces(void)
|
||||
@@ -355,13 +360,10 @@ int fix_fd(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int make_sock(union mysockaddr *addr, int type)
|
||||
static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||
{
|
||||
int family = addr->sa.sa_family;
|
||||
int fd, rc, opt = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
#endif
|
||||
|
||||
if ((fd = socket(family, type, 0)) == -1)
|
||||
{
|
||||
@@ -374,11 +376,16 @@ static int make_sock(union mysockaddr *addr, int type)
|
||||
return -1;
|
||||
|
||||
err:
|
||||
port = prettyprint_addr(addr, daemon->namebuff);
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
sprintf(daemon->namebuff, "port %d", port);
|
||||
die(_("failed to create listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
if (dienow)
|
||||
{
|
||||
port = prettyprint_addr(addr, daemon->namebuff);
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
sprintf(daemon->namebuff, "port %d", port);
|
||||
die(_("failed to create listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||
@@ -389,27 +396,7 @@ static int make_sock(union mysockaddr *addr, int type)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) != -1)
|
||||
break;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
||||
before failing. */
|
||||
if (family == AF_INET6 &&
|
||||
(errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
||||
dad_count++ < DAD_WAIT)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1)
|
||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
|
||||
goto err;
|
||||
|
||||
if (type == SOCK_STREAM)
|
||||
@@ -462,15 +449,15 @@ static int make_sock(union mysockaddr *addr, int type)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||
{
|
||||
struct listener *l = NULL;
|
||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
fd = make_sock(addr, SOCK_DGRAM);
|
||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
||||
fd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
tcpfd = make_sock(addr, SOCK_STREAM, dienow);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
@@ -481,7 +468,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
/* port must be restored to DNS port for TCP code */
|
||||
short save = addr->in.sin_port;
|
||||
addr->in.sin_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
addr->in.sin_port = save;
|
||||
}
|
||||
# ifdef HAVE_IPV6
|
||||
@@ -489,7 +476,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
{
|
||||
short save = addr->in6.sin6_port;
|
||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||
addr->in6.sin6_port = save;
|
||||
}
|
||||
# endif
|
||||
@@ -509,7 +496,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_wildcard_listeners(void)
|
||||
void create_wildcard_listeners(void)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
struct listener *l;
|
||||
@@ -523,7 +510,7 @@ struct listener *create_wildcard_listeners(void)
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
l = create_listeners(&addr, tftp_enabled, 1);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@@ -535,31 +522,41 @@ struct listener *create_wildcard_listeners(void)
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
|
||||
if (l)
|
||||
l->next = create_listeners(&addr, tftp_enabled);
|
||||
l->next = create_listeners(&addr, tftp_enabled, 1);
|
||||
else
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
l = create_listeners(&addr, tftp_enabled, 1);
|
||||
#endif
|
||||
|
||||
return l;
|
||||
daemon->listeners = l;
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(void)
|
||||
void create_bound_listeners(int dienow)
|
||||
{
|
||||
struct listener *new, *listeners = NULL;
|
||||
struct listener *new;
|
||||
struct irec *iface;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
||||
if (!iface->done && !iface->dad &&
|
||||
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
|
||||
int is_dad_listeners(void)
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dad && !iface->done)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||
occupied port nos and reserved ones. */
|
||||
int random_sock(int family)
|
||||
|
||||
Reference in New Issue
Block a user