mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
26
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b72ecb3a59 | ||
|
|
c221030f89 | ||
|
|
5bbea085d0 | ||
|
|
622cf03ab9 | ||
|
|
8ce27433f8 | ||
|
|
5d894620b4 | ||
|
|
71766c0c35 | ||
|
|
da58455508 | ||
|
|
b915c9a661 | ||
|
|
424aaa0f9d | ||
|
|
c72c895869 | ||
|
|
b7156116c2 | ||
|
|
7d915a0bb9 | ||
|
|
509afcd1d2 | ||
|
|
51343bd9a2 | ||
|
|
b58276a73c | ||
|
|
f162d344c0 | ||
|
|
0003db15cb | ||
|
|
275f4a4475 | ||
|
|
12e4565fef | ||
|
|
7af26eed32 | ||
|
|
63dc6eb316 | ||
|
|
6656790f24 | ||
|
|
c8de423038 | ||
|
|
c52653f97c | ||
|
|
e24c341068 |
No files matched your search
@@ -75,6 +75,28 @@ version 2.91
|
|||||||
Fix erroneous "DNSSEC validated" state with non-DNSSEC
|
Fix erroneous "DNSSEC validated" state with non-DNSSEC
|
||||||
upstream servers. Thanks to Dominik Derigs for the bug report.
|
upstream servers. Thanks to Dominik Derigs for the bug report.
|
||||||
|
|
||||||
|
Handle queries with EDNS client subnet fields better. If dnsmasq
|
||||||
|
is configured to add an EDNS client subnet to a query, it is careful
|
||||||
|
to suppress use of the cache, since a cached answer may not be valid
|
||||||
|
for a query with a different client subnet. Extend this behaviour
|
||||||
|
to queries which arrive a dnsmasq already carrying an EDNS client
|
||||||
|
subnet.
|
||||||
|
|
||||||
|
Handle DS queries to auth zones. When dnsmasq is configured to
|
||||||
|
act as an authoritative server and has an authoritative zone
|
||||||
|
configured, and recieves a query for that zone _as_forwarder_
|
||||||
|
it answers the query directly rather than forwarding it. This
|
||||||
|
doesn't affect the answer, but it saves dnsmasq forwarding the
|
||||||
|
query to the recusor upstream, whch then bounces it back to dnsmasq
|
||||||
|
in auth mode. The exception should be when the query is for the root
|
||||||
|
of zone, for a DS RR. The answer to that has to come from the parent,
|
||||||
|
via the recursor, and will typically be a proof-of-nonexistence
|
||||||
|
since dnsmasq doesn't support signed zones. This patch suppresses
|
||||||
|
local answers and forces forwarding to the upstream recursor for such
|
||||||
|
queries. It stops breakage when a DNSSEC validating client makes
|
||||||
|
queries to dnsmasq acting as forwarder for a zone for which it is
|
||||||
|
authoritative.
|
||||||
|
|
||||||
|
|
||||||
version 2.90
|
version 2.90
|
||||||
Fix reversion in --rev-server introduced in 2.88 which
|
Fix reversion in --rev-server introduced in 2.88 which
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG
|
|||||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||||
|
|
||||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
sum?=$(shell echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
sum!=echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||||
copts_conf = .copts_$(sum)
|
copts_conf = .copts_$(sum)
|
||||||
|
|
||||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||||
|
|||||||
+1
-1
Submodule debian updated: 05f03dca94...83e05da879.
+1
-1
@@ -1429,7 +1429,7 @@ forces "simple and safe" behaviour to avoid problems in such a case.
|
|||||||
.B --dhcp-relay=<local address>[,<server address>[#<server port>]][,<interface]
|
.B --dhcp-relay=<local address>[,<server address>[#<server port>]][,<interface]
|
||||||
Configure dnsmasq to do DHCP relay. The local address is an address
|
Configure dnsmasq to do DHCP relay. The local address is an address
|
||||||
allocated to an interface on the host running dnsmasq. All DHCP
|
allocated to an interface on the host running dnsmasq. All DHCP
|
||||||
requests arriving on that interface will we relayed to a remote DHCP
|
requests arriving on that interface will be relayed to a remote DHCP
|
||||||
server at the server address. It is possible to relay from a single local
|
server at the server address. It is possible to relay from a single local
|
||||||
address to multiple remote servers by using multiple \fB--dhcp-relay\fP
|
address to multiple remote servers by using multiple \fB--dhcp-relay\fP
|
||||||
configs with the same local address and different server
|
configs with the same local address and different server
|
||||||
|
|||||||
+1
-1
@@ -513,7 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
nxdomain = 0;
|
nxdomain = 0;
|
||||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||||
{
|
{
|
||||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||||
|
|||||||
+1
-1
@@ -479,7 +479,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
|
|||||||
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
|
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
|
||||||
{
|
{
|
||||||
int rrmatch = 0;
|
int rrmatch = 0;
|
||||||
if (crecp->flags & flags & F_RR)
|
if (addr && (crecp->flags & flags & F_RR))
|
||||||
{
|
{
|
||||||
unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype;
|
unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype;
|
||||||
unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype;
|
unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype;
|
||||||
|
|||||||
@@ -362,6 +362,11 @@ HAVE_SOCKADDR_SA_LEN
|
|||||||
#define HAVE_INOTIFY
|
#define HAVE_INOTIFY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This never compiles code, it's only used by the makefile to fingerprint builds. */
|
||||||
|
#ifdef DNSMASQ_COMPILE_FLAGS
|
||||||
|
static char *compile_flags = DNSMASQ_COMPILE_FLAGS;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Define a string indicating which options are in use.
|
/* Define a string indicating which options are in use.
|
||||||
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
|
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||||
|
|
||||||
|
|||||||
+118
-52
@@ -32,6 +32,7 @@ static volatile int pipewrite;
|
|||||||
static void set_dns_listeners(void);
|
static void set_dns_listeners(void);
|
||||||
static void set_tftp_listeners(void);
|
static void set_tftp_listeners(void);
|
||||||
static void check_dns_listeners(time_t now);
|
static void check_dns_listeners(time_t now);
|
||||||
|
static void do_tcp_connection(struct listener *listener, time_t now, int slot);
|
||||||
static void sig_handler(int sig);
|
static void sig_handler(int sig);
|
||||||
static void async_event(int pipe, time_t now);
|
static void async_event(int pipe, time_t now);
|
||||||
static void fatal_event(struct event_desc *ev, char *msg);
|
static void fatal_event(struct event_desc *ev, char *msg);
|
||||||
@@ -61,6 +62,7 @@ int main (int argc, char **argv)
|
|||||||
int need_cap_net_admin = 0;
|
int need_cap_net_admin = 0;
|
||||||
int need_cap_net_raw = 0;
|
int need_cap_net_raw = 0;
|
||||||
int need_cap_net_bind_service = 0;
|
int need_cap_net_bind_service = 0;
|
||||||
|
int have_cap_chown = 0;
|
||||||
char *bound_device = NULL;
|
char *bound_device = NULL;
|
||||||
int did_bind = 0;
|
int did_bind = 0;
|
||||||
struct server *serv;
|
struct server *serv;
|
||||||
@@ -556,6 +558,8 @@ int main (int argc, char **argv)
|
|||||||
data = safe_malloc(sizeof(*data) * capsize);
|
data = safe_malloc(sizeof(*data) * capsize);
|
||||||
capget(hdr, data); /* Get current values, for verification */
|
capget(hdr, data); /* Get current values, for verification */
|
||||||
|
|
||||||
|
have_cap_chown = data->permitted & (1 << CAP_CHOWN);
|
||||||
|
|
||||||
if (need_cap_net_admin && !(data->permitted & (1 << CAP_NET_ADMIN)))
|
if (need_cap_net_admin && !(data->permitted & (1 << CAP_NET_ADMIN)))
|
||||||
fail = "NET_ADMIN";
|
fail = "NET_ADMIN";
|
||||||
else if (need_cap_net_raw && !(data->permitted & (1 << CAP_NET_RAW)))
|
else if (need_cap_net_raw && !(data->permitted & (1 << CAP_NET_RAW)))
|
||||||
@@ -869,7 +873,14 @@ int main (int argc, char **argv)
|
|||||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||||
|
|
||||||
if (chown_warn != 0)
|
if (chown_warn != 0)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
|
if (chown_warn == EPERM && !have_cap_chown)
|
||||||
|
my_syslog(LOG_INFO, "chown of PID file %s failed: please add capability CAP_CHOWN", daemon->runfile);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
|
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
if (option_bool(OPT_DBUS))
|
if (option_bool(OPT_DBUS))
|
||||||
@@ -951,8 +962,15 @@ int main (int argc, char **argv)
|
|||||||
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
||||||
daemon->resolv_files = NULL;
|
daemon->resolv_files = NULL;
|
||||||
if (!daemon->servers)
|
if (!daemon->servers)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DBUS
|
||||||
|
if (option_bool(OPT_DBUS))
|
||||||
|
my_syslog(LOG_INFO, _("no upstream servers configured - please set them from DBus"));
|
||||||
|
else
|
||||||
|
#endif
|
||||||
my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
|
my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (daemon->max_logs != 0)
|
if (daemon->max_logs != 0)
|
||||||
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
|
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
|
||||||
@@ -1466,7 +1484,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
{
|
{
|
||||||
pid_t p;
|
pid_t p;
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
int i, check = 0;
|
int wstatus, i, check = 0;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
@@ -1529,7 +1547,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
|
|
||||||
case EVENT_CHILD:
|
case EVENT_CHILD:
|
||||||
/* See Stevens 5.10 */
|
/* See Stevens 5.10 */
|
||||||
while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
|
while ((p = waitpid(-1, &wstatus, WNOHANG)) != 0)
|
||||||
if (p == -1)
|
if (p == -1)
|
||||||
{
|
{
|
||||||
if (errno != EINTR)
|
if (errno != EINTR)
|
||||||
@@ -1540,6 +1558,20 @@ static void async_event(int pipe, time_t now)
|
|||||||
if (daemon->tcp_pids[i] == p)
|
if (daemon->tcp_pids[i] == p)
|
||||||
{
|
{
|
||||||
daemon->tcp_pids[i] = 0;
|
daemon->tcp_pids[i] = 0;
|
||||||
|
|
||||||
|
if (!WIFEXITED(wstatus))
|
||||||
|
{
|
||||||
|
/* If a helper process dies, (eg with SIGSEV)
|
||||||
|
log that and attempt to patch things up so that the
|
||||||
|
parent can continue to function. */
|
||||||
|
my_syslog(LOG_WARNING, _("TCP helper process %u died unexpectedly"), (unsigned int)p);
|
||||||
|
if (daemon->tcp_pipes[i] != -1)
|
||||||
|
{
|
||||||
|
close(daemon->tcp_pipes[i]);
|
||||||
|
daemon->tcp_pipes[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
|
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
|
||||||
if (daemon->tcp_pipes[i] == -1)
|
if (daemon->tcp_pipes[i] == -1)
|
||||||
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
|
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
|
||||||
@@ -1822,22 +1854,17 @@ static void check_dns_listeners(time_t now)
|
|||||||
struct listener *listener;
|
struct listener *listener;
|
||||||
struct randfd_list *rfl;
|
struct randfd_list *rfl;
|
||||||
int i;
|
int i;
|
||||||
int pipefd[2];
|
|
||||||
|
|
||||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
/* Note that handling events here can create or destroy fds and
|
||||||
if (poll_check(serverfdp->fd, POLLIN))
|
render the result of the last poll() call invalid. Once
|
||||||
reply_query(serverfdp->fd, now);
|
we find an fd that needs service, do it, then return to go around the
|
||||||
|
poll() loop again. This avoid really, really, wierd bugs. */
|
||||||
for (i = 0; i < daemon->numrrand; i++)
|
|
||||||
if (daemon->randomsocks[i].refcount != 0 &&
|
|
||||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
|
||||||
reply_query(daemon->randomsocks[i].fd, now);
|
|
||||||
|
|
||||||
/* Check overflow random sockets too. */
|
|
||||||
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
|
||||||
if (poll_check(rfl->rfd->fd, POLLIN))
|
|
||||||
reply_query(rfl->rfd->fd, now);
|
|
||||||
|
|
||||||
|
if (!option_bool(OPT_DEBUG))
|
||||||
|
for (i = 0; i < daemon->max_procs; i++)
|
||||||
|
if (daemon->tcp_pipes[i] != -1 &&
|
||||||
|
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP))
|
||||||
|
{
|
||||||
/* Races. The child process can die before we read all of the data from the
|
/* Races. The child process can die before we read all of the data from the
|
||||||
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
|
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
|
||||||
process, and tcp_pipes to -1 and close the FD when we read the last
|
process, and tcp_pipes to -1 and close the FD when we read the last
|
||||||
@@ -1845,11 +1872,7 @@ static void check_dns_listeners(time_t now)
|
|||||||
The order of these events is indeterminate, and both are needed
|
The order of these events is indeterminate, and both are needed
|
||||||
to free the process slot. Once the child process has gone, poll()
|
to free the process slot. Once the child process has gone, poll()
|
||||||
returns POLLHUP, not POLLIN, so have to check for both here. */
|
returns POLLHUP, not POLLIN, so have to check for both here. */
|
||||||
if (!option_bool(OPT_DEBUG))
|
if (!cache_recv_insert(now, daemon->tcp_pipes[i]))
|
||||||
for (i = 0; i < daemon->max_procs; i++)
|
|
||||||
if (daemon->tcp_pipes[i] != -1 &&
|
|
||||||
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
|
|
||||||
!cache_recv_insert(now, daemon->tcp_pipes[i]))
|
|
||||||
{
|
{
|
||||||
close(daemon->tcp_pipes[i]);
|
close(daemon->tcp_pipes[i]);
|
||||||
daemon->tcp_pipes[i] = -1;
|
daemon->tcp_pipes[i] = -1;
|
||||||
@@ -1857,11 +1880,38 @@ static void check_dns_listeners(time_t now)
|
|||||||
if (daemon->tcp_pids[i] == 0)
|
if (daemon->tcp_pids[i] == 0)
|
||||||
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
|
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||||
|
if (poll_check(serverfdp->fd, POLLIN))
|
||||||
|
{
|
||||||
|
reply_query(serverfdp->fd, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < daemon->numrrand; i++)
|
||||||
|
if (daemon->randomsocks[i].refcount != 0 &&
|
||||||
|
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||||
|
{
|
||||||
|
reply_query(daemon->randomsocks[i].fd, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check overflow random sockets too. */
|
||||||
|
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
||||||
|
if (poll_check(rfl->rfd->fd, POLLIN))
|
||||||
|
{
|
||||||
|
reply_query(rfl->rfd->fd, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||||
{
|
|
||||||
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
|
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
|
||||||
|
{
|
||||||
receive_query(listener, now);
|
receive_query(listener, now);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* check to see if we have a free tcp process slot.
|
/* check to see if we have a free tcp process slot.
|
||||||
Note that we can't assume that because we had
|
Note that we can't assume that because we had
|
||||||
@@ -1872,23 +1922,39 @@ static void check_dns_listeners(time_t now)
|
|||||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
|
if (i >= 0)
|
||||||
|
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||||
|
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
|
||||||
{
|
{
|
||||||
|
do_tcp_connection(listener, now, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||||
|
{
|
||||||
int confd, client_ok = 1;
|
int confd, client_ok = 1;
|
||||||
struct irec *iface = NULL;
|
struct irec *iface = NULL;
|
||||||
pid_t p;
|
pid_t p;
|
||||||
union mysockaddr tcp_addr;
|
union mysockaddr tcp_addr;
|
||||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
|
unsigned char a = 0, *buff;
|
||||||
|
struct server *s;
|
||||||
|
int flags, auth_dns;
|
||||||
|
struct in_addr netmask;
|
||||||
|
int pipefd[2];
|
||||||
|
|
||||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
if (confd == -1)
|
if (confd == -1)
|
||||||
continue;
|
return;
|
||||||
|
|
||||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||||
{
|
{
|
||||||
|
closeconandreturn:
|
||||||
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that the interface list is up-to-date.
|
/* Make sure that the interface list is up-to-date.
|
||||||
@@ -1951,17 +2017,26 @@ static void check_dns_listeners(time_t now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!client_ok)
|
if (!client_ok)
|
||||||
|
goto closeconandreturn;
|
||||||
|
|
||||||
|
if (!option_bool(OPT_DEBUG))
|
||||||
{
|
{
|
||||||
shutdown(confd, SHUT_RDWR);
|
if (pipe(pipefd) == -1)
|
||||||
close(confd);
|
goto closeconandreturn; /* pipe failed */
|
||||||
}
|
|
||||||
else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0)
|
if ((p = fork()) == -1)
|
||||||
{
|
{
|
||||||
close(pipefd[1]); /* parent needs read pipe end. */
|
/* fork failed */
|
||||||
if (p == -1)
|
|
||||||
close(pipefd[0]);
|
close(pipefd[0]);
|
||||||
else
|
close(pipefd[1]);
|
||||||
|
goto closeconandreturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p != 0)
|
||||||
{
|
{
|
||||||
|
/* fork() done: parent side */
|
||||||
|
close(pipefd[1]); /* parent needs read pipe end. */
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
/* The child process inherits the netlink socket,
|
/* The child process inherits the netlink socket,
|
||||||
which it never uses, but when the parent (us)
|
which it never uses, but when the parent (us)
|
||||||
@@ -1977,17 +2052,16 @@ static void check_dns_listeners(time_t now)
|
|||||||
is sent by the child after it has closed the
|
is sent by the child after it has closed the
|
||||||
netlink socket. */
|
netlink socket. */
|
||||||
|
|
||||||
unsigned char a;
|
|
||||||
read_write(pipefd[0], &a, 1, RW_READ);
|
read_write(pipefd[0], &a, 1, RW_READ);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* i holds index of free slot */
|
|
||||||
daemon->tcp_pids[i] = p;
|
daemon->tcp_pids[slot] = p;
|
||||||
daemon->tcp_pipes[i] = pipefd[0];
|
daemon->tcp_pipes[slot] = pipefd[0];
|
||||||
daemon->metrics[METRIC_TCP_CONNECTIONS]++;
|
daemon->metrics[METRIC_TCP_CONNECTIONS]++;
|
||||||
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
|
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
|
||||||
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
|
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
|
||||||
}
|
|
||||||
close(confd);
|
close(confd);
|
||||||
|
|
||||||
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
|
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
|
||||||
@@ -1997,14 +2071,10 @@ static void check_dns_listeners(time_t now)
|
|||||||
if (option_bool(OPT_DNSSEC_VALID))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
daemon->log_id += daemon->limit[LIMIT_WORK];
|
daemon->log_id += daemon->limit[LIMIT_WORK];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
unsigned char *buff;
|
|
||||||
struct server *s;
|
|
||||||
int flags;
|
|
||||||
struct in_addr netmask;
|
|
||||||
int auth_dns;
|
|
||||||
|
|
||||||
if (iface)
|
if (iface)
|
||||||
{
|
{
|
||||||
@@ -2023,8 +2093,6 @@ static void check_dns_listeners(time_t now)
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
/* See comment above re: netlink socket. */
|
/* See comment above re: netlink socket. */
|
||||||
unsigned char a = 0;
|
|
||||||
|
|
||||||
close(daemon->netlinkfd);
|
close(daemon->netlinkfd);
|
||||||
read_write(pipefd[1], &a, 1, RW_WRITE);
|
read_write(pipefd[1], &a, 1, RW_WRITE);
|
||||||
#endif
|
#endif
|
||||||
@@ -2058,11 +2126,9 @@ static void check_dns_listeners(time_t now)
|
|||||||
flush_log();
|
flush_log();
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
/* If a DNSSEC query over UDP returns a truncated answer,
|
/* If a DNSSEC query over UDP returns a truncated answer,
|
||||||
we swap to the TCP path. This routine is responsible for forking
|
we swap to the TCP path. This routine is responsible for forking
|
||||||
@@ -2091,11 +2157,11 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
|||||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* No slots */
|
/* No slots or no pipe */
|
||||||
if (i < 0)
|
if (i < 0 || pipe(pipefd) != 0)
|
||||||
return STAT_ABANDONED;
|
return STAT_ABANDONED;
|
||||||
|
|
||||||
if (pipe(pipefd) == 0 && (p = fork()) != 0)
|
if ((p = fork()) != 0)
|
||||||
{
|
{
|
||||||
close(pipefd[1]); /* parent needs read pipe end. */
|
close(pipefd[1]); /* parent needs read pipe end. */
|
||||||
if (p == -1)
|
if (p == -1)
|
||||||
|
|||||||
+3
-4
@@ -772,9 +772,8 @@ struct dyndir {
|
|||||||
#define FREC_DS_QUERY 16
|
#define FREC_DS_QUERY 16
|
||||||
#define FREC_AD_QUESTION 32
|
#define FREC_AD_QUESTION 32
|
||||||
#define FREC_DO_QUESTION 64
|
#define FREC_DO_QUESTION 64
|
||||||
#define FREC_ADDED_PHEADER 128
|
#define FREC_HAS_PHEADER 128
|
||||||
#define FREC_HAS_PHEADER 256
|
#define FREC_GONE_TO_TCP 256
|
||||||
#define FREC_GONE_TO_TCP 512
|
|
||||||
|
|
||||||
struct frec {
|
struct frec {
|
||||||
struct frec_src {
|
struct frec_src {
|
||||||
@@ -1402,7 +1401,7 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
|||||||
#endif
|
#endif
|
||||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||||
struct in_addr local_addr, struct in_addr local_netmask,
|
struct in_addr local_addr, struct in_addr local_netmask,
|
||||||
time_t now, int ad_reqd, int do_bit, int *stale, int *filtered);
|
time_t now, int ad_reqd, int do_bit, int no_cache, int *stale, int *filtered);
|
||||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||||
time_t now);
|
time_t now);
|
||||||
int check_for_ignored_address(struct dns_header *header, size_t qlen);
|
int check_for_ignored_address(struct dns_header *header, size_t qlen);
|
||||||
|
|||||||
+19
-1
@@ -417,20 +417,33 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c
|
|||||||
else if (option_bool(OPT_STRIP_ECS))
|
else if (option_bool(OPT_STRIP_ECS))
|
||||||
replace = 2;
|
replace = 2;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
unsigned char *pheader;
|
||||||
|
/* If we still think the data is cacheable, and we're not
|
||||||
|
messing with EDNS client subnet ourselves, see if the client
|
||||||
|
sent a client subnet. If so, mark the data as uncacheable */
|
||||||
|
if (*cacheable &&
|
||||||
|
(pheader = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL)) &&
|
||||||
|
!check_source(header, plen, pheader, NULL))
|
||||||
|
*cacheable = 0;
|
||||||
|
|
||||||
return plen;
|
return plen;
|
||||||
|
}
|
||||||
|
|
||||||
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
|
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
||||||
{
|
{
|
||||||
/* Section 9.2, Check that subnet option in reply matches. */
|
/* Section 9.2, Check that subnet option (if any) in reply matches.
|
||||||
|
if peer == NULL, this degrades to a check for the existence of and EDNS0 client-subnet option. */
|
||||||
|
|
||||||
int len, calc_len;
|
int len, calc_len;
|
||||||
struct subnet_opt opt;
|
struct subnet_opt opt;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
int code, i, rdlen;
|
int code, i, rdlen;
|
||||||
|
|
||||||
|
if (peer)
|
||||||
calc_len = calc_subnet_opt(&opt, peer, NULL);
|
calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||||
|
|
||||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||||
@@ -448,12 +461,17 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
|||||||
GETSHORT(code, p);
|
GETSHORT(code, p);
|
||||||
GETSHORT(len, p);
|
GETSHORT(len, p);
|
||||||
if (code == EDNS0_OPTION_CLIENT_SUBNET)
|
if (code == EDNS0_OPTION_CLIENT_SUBNET)
|
||||||
|
{
|
||||||
|
if (peer)
|
||||||
{
|
{
|
||||||
/* make sure this doesn't mismatch. */
|
/* make sure this doesn't mismatch. */
|
||||||
opt.scope_netmask = p[3];
|
opt.scope_netmask = p[3];
|
||||||
if (len != calc_len || memcmp(p, &opt, len) != 0)
|
if (len != calc_len || memcmp(p, &opt, len) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (((struct subnet_opt *)p)->source_netmask != 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
p += len;
|
p += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+103
-91
@@ -163,37 +163,22 @@ static int domain_no_rebind(char *domain)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||||
union all_addr *dst_addr, unsigned int dst_iface,
|
union all_addr *dst_addr, unsigned int dst_iface,
|
||||||
struct dns_header *header, size_t plen, size_t replylimit, time_t now,
|
struct dns_header *header, size_t plen, size_t replylimit, time_t now,
|
||||||
struct frec *forward, int ad_reqd, int do_bit, int fast_retry)
|
struct frec *forward, unsigned int fwd_flags, int fast_retry)
|
||||||
{
|
{
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
unsigned int fwd_flags = 0;
|
|
||||||
int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
|
int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
|
||||||
struct server *master;
|
struct server *master;
|
||||||
unsigned int gotname;
|
unsigned int gotname;
|
||||||
int old_src = 0, old_reply = 0;
|
int old_src = 0, old_reply = 0;
|
||||||
int first, last, start = 0;
|
int first, last, start = 0;
|
||||||
int cacheable, forwarded = 0;
|
int forwarded = 0;
|
||||||
unsigned char *oph;
|
|
||||||
int ede = EDE_UNSET;
|
int ede = EDE_UNSET;
|
||||||
(void)do_bit;
|
|
||||||
unsigned short rrtype;
|
unsigned short rrtype;
|
||||||
|
|
||||||
gotname = extract_request(header, plen, daemon->namebuff, &rrtype);
|
gotname = extract_request(header, plen, daemon->namebuff, &rrtype);
|
||||||
oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (header->hb4 & HB4_CD)
|
|
||||||
fwd_flags |= FREC_CHECKING_DISABLED;
|
|
||||||
if (ad_reqd)
|
|
||||||
fwd_flags |= FREC_AD_QUESTION;
|
|
||||||
if (oph)
|
|
||||||
fwd_flags |= FREC_HAS_PHEADER;
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
if (do_bit)
|
|
||||||
fwd_flags |= FREC_DO_QUESTION;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Check for retry on existing query.
|
/* Check for retry on existing query.
|
||||||
FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||||
@@ -205,6 +190,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
{
|
{
|
||||||
old_src = 1;
|
old_src = 1;
|
||||||
old_reply = 1;
|
old_reply = 1;
|
||||||
|
fwd_flags = forward->flags;
|
||||||
}
|
}
|
||||||
else if (gotname && (forward = lookup_frec(daemon->namebuff, C_IN, (int)rrtype, -1, fwd_flags,
|
else if (gotname && (forward = lookup_frec(daemon->namebuff, C_IN, (int)rrtype, -1, fwd_flags,
|
||||||
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
|
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
|
||||||
@@ -268,7 +254,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
it's safe to wait for the reply from the first without
|
it's safe to wait for the reply from the first without
|
||||||
forwarding the second. */
|
forwarding the second. */
|
||||||
if (difftime(now, forward->time) < 2)
|
if (difftime(now, forward->time) < 2)
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use our id when resending */
|
/* use our id when resending */
|
||||||
@@ -321,11 +307,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
forward->flags = fwd_flags;
|
forward->flags = fwd_flags;
|
||||||
|
|
||||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + daemon->edns_pktsz, &forward->frec_src.source, now, &cacheable);
|
|
||||||
|
|
||||||
if (!cacheable)
|
|
||||||
forward->flags |= FREC_NO_CACHE;
|
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
||||||
{
|
{
|
||||||
@@ -338,10 +319,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If there wasn't a PH before, and there is now, we added it. */
|
|
||||||
if (!oph && find_pseudoheader(header, plen, NULL, NULL, NULL, NULL))
|
|
||||||
forward->flags |= FREC_ADDED_PHEADER;
|
|
||||||
|
|
||||||
/* Do these before saving query. */
|
/* Do these before saving query. */
|
||||||
forward->frec_src.orig_id = ntohs(header->id);
|
forward->frec_src.orig_id = ntohs(header->id);
|
||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
@@ -365,15 +342,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
forward->forwardall = 0;
|
forward->forwardall = 0;
|
||||||
if (domain_no_rebind(daemon->namebuff))
|
if (domain_no_rebind(daemon->namebuff))
|
||||||
forward->flags |= FREC_NOREBIND;
|
forward->flags |= FREC_NOREBIND;
|
||||||
if (header->hb4 & HB4_CD)
|
|
||||||
forward->flags |= FREC_CHECKING_DISABLED;
|
|
||||||
if (ad_reqd)
|
|
||||||
forward->flags |= FREC_AD_QUESTION;
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
forward->work_counter = daemon->limit[LIMIT_WORK];
|
forward->work_counter = daemon->limit[LIMIT_WORK];
|
||||||
forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
|
forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
|
||||||
if (do_bit)
|
|
||||||
forward->flags |= FREC_DO_QUESTION;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
start = first;
|
start = first;
|
||||||
@@ -403,6 +374,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
while (forward->blocking_query)
|
while (forward->blocking_query)
|
||||||
forward = forward->blocking_query;
|
forward = forward->blocking_query;
|
||||||
|
|
||||||
|
/* Don't retry if we've already sent it via TCP. */
|
||||||
|
if (forward->flags & FREC_GONE_TO_TCP)
|
||||||
|
return;
|
||||||
|
|
||||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||||
{
|
{
|
||||||
/* log_id should match previous DNSSEC query. */
|
/* log_id should match previous DNSSEC query. */
|
||||||
@@ -415,7 +390,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
/* Find suitable servers: should never fail. */
|
/* Find suitable servers: should never fail. */
|
||||||
if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
|
if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
is_dnssec = 1;
|
is_dnssec = 1;
|
||||||
forward->forwardall = 1;
|
forward->forwardall = 1;
|
||||||
@@ -531,8 +506,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
if (forwarded || is_dnssec)
|
if (forwarded || is_dnssec)
|
||||||
{
|
{
|
||||||
|
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
|
||||||
forward->forward_timestamp = dnsmasq_milliseconds();
|
forward->forward_timestamp = dnsmasq_milliseconds();
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* could not send on, prepare to return */
|
/* could not send on, prepare to return */
|
||||||
@@ -544,16 +520,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
if (udpfd != -1)
|
if (udpfd != -1)
|
||||||
{
|
{
|
||||||
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede)))
|
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede)))
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
if (oph)
|
if (fwd_flags & FREC_HAS_PHEADER)
|
||||||
{
|
{
|
||||||
u16 swap = htons((u16)ede);
|
u16 swap = htons((u16)ede);
|
||||||
|
|
||||||
if (ede != EDE_UNSET)
|
if (ede != EDE_UNSET)
|
||||||
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, 0, 0);
|
||||||
else
|
else
|
||||||
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), 0, NULL, 0, do_bit, 0);
|
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), 0, NULL, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
@@ -572,7 +548,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if any frecs need to do a retry, and action that if so.
|
/* Check if any frecs need to do a retry, and action that if so.
|
||||||
@@ -611,8 +588,7 @@ int fast_retry(time_t now)
|
|||||||
daemon->log_display_id = f->frec_src.log_id;
|
daemon->log_display_id = f->frec_src.log_id;
|
||||||
daemon->log_source_addr = NULL;
|
daemon->log_source_addr = NULL;
|
||||||
|
|
||||||
forward_query(-1, NULL, NULL, 0, header, f->stash_len, 0, now, f,
|
forward_query(-1, NULL, NULL, 0, header, f->stash_len, 0, now, f, 0, 1);
|
||||||
f->flags & FREC_AD_QUESTION, f->flags & FREC_DO_QUESTION, 1);
|
|
||||||
|
|
||||||
to_run = f->forward_delay = 2 * f->forward_delay;
|
to_run = f->forward_delay = 2 * f->forward_delay;
|
||||||
}
|
}
|
||||||
@@ -810,10 +786,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
header->ancount = htons(0);
|
header->ancount = htons(0);
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
ede = EDE_DNSSEC_BOGUS;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
else if (ad_reqd && cache_secure)
|
||||||
header->hb4 |= HB4_AD;
|
header->hb4 |= HB4_AD;
|
||||||
|
|
||||||
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||||
@@ -847,10 +822,6 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
|||||||
|
|
||||||
daemon->log_display_id = forward->frec_src.log_id;
|
daemon->log_display_id = forward->frec_src.log_id;
|
||||||
|
|
||||||
/* We've had a reply already, which we're validating. Ignore this duplicate */
|
|
||||||
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Find the original query that started it all.... */
|
/* Find the original query that started it all.... */
|
||||||
for (orig = forward; orig->dependent; orig = orig->dependent);
|
for (orig = forward; orig->dependent; orig = orig->dependent);
|
||||||
|
|
||||||
@@ -1178,22 +1149,23 @@ void reply_query(int fd, time_t now)
|
|||||||
check_for_ignored_address(header, n))
|
check_for_ignored_address(header, n))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) && forward->forwardall == 0)
|
|
||||||
/* for broken servers, attempt to send to another one. */
|
|
||||||
{
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
/* The query MAY have got a good answer, and be awaiting
|
/* The query MAY have got a good answer, and be awaiting
|
||||||
the results of further queries, in which case
|
the results of further queries, in which case
|
||||||
The Stash contains something else and we don't need to retry anyway. */
|
the stash contains something else and we don't need to retry anyway.
|
||||||
|
We may also have already got a truncated reply, and be in the process
|
||||||
|
of doing the query by TCP so can ignore further, probably truncated, UDP answers. */
|
||||||
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
|
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) && forward->forwardall == 0)
|
||||||
|
/* for broken servers, attempt to send to another one. */
|
||||||
|
{
|
||||||
/* Get the saved query back. */
|
/* Get the saved query back. */
|
||||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||||
|
|
||||||
forward_query(-1, NULL, NULL, 0, header, forward->stash_len, 0, now, forward,
|
forward_query(-1, NULL, NULL, 0, header, forward->stash_len, 0, now, forward, 0, 0);
|
||||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 0);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1275,20 +1247,25 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
|||||||
char *result, *domain = "result";
|
char *result, *domain = "result";
|
||||||
union all_addr a;
|
union all_addr a;
|
||||||
|
|
||||||
a.log.ede = ede = errflags_to_ede(status);
|
ede = errflags_to_ede(status);
|
||||||
|
|
||||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||||
{
|
{
|
||||||
result = "ABANDONED";
|
result = "ABANDONED";
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
|
if (ede == EDE_UNSET)
|
||||||
|
ede = EDE_OTHER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||||
|
|
||||||
|
|
||||||
if (STAT_ISEQUAL(status, STAT_SECURE))
|
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||||
cache_secure = 1;
|
cache_secure = 1;
|
||||||
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||||
{
|
{
|
||||||
|
if (ede == EDE_UNSET)
|
||||||
|
ede = EDE_DNSSEC_BOGUS;
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
bogusanswer = 1;
|
bogusanswer = 1;
|
||||||
|
|
||||||
@@ -1296,6 +1273,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
|||||||
domain = daemon->namebuff;
|
domain = daemon->namebuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.log.ede = ede;
|
||||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1323,7 +1301,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
|||||||
|
|
||||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||||
forward->flags & FREC_ADDED_PHEADER, &forward->frec_src.source,
|
!(forward->flags & FREC_HAS_PHEADER), &forward->frec_src.source,
|
||||||
((unsigned char *)header) + daemon->edns_pktsz, ede)))
|
((unsigned char *)header) + daemon->edns_pktsz, ede)))
|
||||||
{
|
{
|
||||||
struct frec_src *src;
|
struct frec_src *src;
|
||||||
@@ -1391,7 +1369,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
|||||||
&src->source, &src->dest, src->iface);
|
&src->source, &src->dest, src->iface);
|
||||||
|
|
||||||
#ifdef HAVE_DUMPFILE
|
#ifdef HAVE_DUMPFILE
|
||||||
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd);
|
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)new, NULL, &src->source, src->fd);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1454,9 +1432,10 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
struct in_addr netmask, dst_addr_4;
|
struct in_addr netmask, dst_addr_4;
|
||||||
size_t m;
|
size_t m;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
|
int if_index = 0, auth_dns = 0, do_bit = 0;
|
||||||
|
unsigned int fwd_flags = 0;
|
||||||
int stale = 0, filtered = 0, ede = EDE_UNSET, do_forward = 0;
|
int stale = 0, filtered = 0, ede = EDE_UNSET, do_forward = 0;
|
||||||
int metric, ad_reqd, fd;
|
int metric, fd;
|
||||||
struct blockdata *saved_question = NULL;
|
struct blockdata *saved_question = NULL;
|
||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
unsigned int mark = 0;
|
unsigned int mark = 0;
|
||||||
@@ -1712,15 +1691,27 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
&source_addr, auth_dns ? "auth" : "query", type);
|
&source_addr, auth_dns ? "auth" : "query", type);
|
||||||
|
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
/* find queries for zones we're authoritative for, and answer them directly */
|
/* Find queries for zones we're authoritative for, and answer them directly.
|
||||||
|
The exception to this is DS queries for the zone route. They
|
||||||
|
have to come from the parent zone. Since dnsmasq's auth server
|
||||||
|
can't do DNSSEC, the zone will be unsigned, and anything using
|
||||||
|
dnsmasq as a forwarder and doing validation will be expecting to
|
||||||
|
see the proof of non-existence from the parent. */
|
||||||
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||||
if (in_zone(zone, daemon->namebuff, NULL))
|
{
|
||||||
|
char *cut;
|
||||||
|
|
||||||
|
if (in_zone(zone, daemon->namebuff, &cut))
|
||||||
|
{
|
||||||
|
if (type != T_DS || cut)
|
||||||
{
|
{
|
||||||
auth_dns = 1;
|
auth_dns = 1;
|
||||||
local_auth = 1;
|
local_auth = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LOOP
|
#ifdef HAVE_LOOP
|
||||||
@@ -1734,7 +1725,8 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
{
|
{
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
|
|
||||||
have_pseudoheader = 1;
|
fwd_flags |= FREC_HAS_PHEADER;
|
||||||
|
|
||||||
GETSHORT(udp_size, pheader);
|
GETSHORT(udp_size, pheader);
|
||||||
pheader += 2; /* ext_rcode */
|
pheader += 2; /* ext_rcode */
|
||||||
GETSHORT(flags, pheader);
|
GETSHORT(flags, pheader);
|
||||||
@@ -1752,10 +1744,15 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
||||||
}
|
}
|
||||||
|
|
||||||
ad_reqd = do_bit;
|
|
||||||
/* RFC 6840 5.7 */
|
/* RFC 6840 5.7 */
|
||||||
if (header->hb4 & HB4_AD)
|
if (do_bit || (header->hb4 & HB4_AD))
|
||||||
ad_reqd = 1;
|
fwd_flags |= FREC_AD_QUESTION;
|
||||||
|
|
||||||
|
if (do_bit)
|
||||||
|
fwd_flags |= FREC_DO_QUESTION;
|
||||||
|
|
||||||
|
if (header->hb4 & HB4_CD)
|
||||||
|
fwd_flags |= FREC_CHECKING_DISABLED;
|
||||||
|
|
||||||
fd = listen->fd;
|
fd = listen->fd;
|
||||||
|
|
||||||
@@ -1790,10 +1787,16 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int cacheable;
|
||||||
|
|
||||||
|
n = add_edns0_config(header, n, ((unsigned char *)header) + daemon->edns_pktsz, &source_addr, now, &cacheable);
|
||||||
saved_question = blockdata_alloc((char *) header, (size_t)n);
|
saved_question = blockdata_alloc((char *) header, (size_t)n);
|
||||||
|
|
||||||
|
if (!cacheable)
|
||||||
|
fwd_flags |= FREC_NO_CACHE;
|
||||||
|
|
||||||
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
|
||||||
dst_addr_4, netmask, now, ad_reqd, do_bit, &stale, &filtered);
|
dst_addr_4, netmask, now, fwd_flags & FREC_AD_QUESTION, do_bit, !cacheable, &stale, &filtered);
|
||||||
|
|
||||||
metric = stale ? METRIC_DNS_STALE_ANSWERED : METRIC_DNS_LOCAL_ANSWERED;
|
metric = stale ? METRIC_DNS_STALE_ANSWERED : METRIC_DNS_LOCAL_ANSWERED;
|
||||||
|
|
||||||
@@ -1814,7 +1817,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
if (m != 0)
|
if (m != 0)
|
||||||
{
|
{
|
||||||
if (have_pseudoheader)
|
if (fwd_flags & FREC_HAS_PHEADER)
|
||||||
{
|
{
|
||||||
if (ede != EDE_UNSET)
|
if (ede != EDE_UNSET)
|
||||||
{
|
{
|
||||||
@@ -1864,11 +1867,8 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
blockdata_free(saved_question);
|
blockdata_free(saved_question);
|
||||||
saved_question = NULL;
|
saved_question = NULL;
|
||||||
|
|
||||||
if (forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n,
|
forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n,
|
||||||
udp_size, now, NULL, ad_reqd, do_bit, 0))
|
udp_size, now, NULL, fwd_flags, 0);
|
||||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
|
|
||||||
else
|
|
||||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blockdata_free(saved_question);
|
blockdata_free(saved_question);
|
||||||
@@ -2212,7 +2212,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
int local_auth = 0;
|
int local_auth = 0;
|
||||||
#endif
|
#endif
|
||||||
int checking_disabled, do_bit = 0, ad_reqd = 0, added_pheader = 0, have_pseudoheader = 0;
|
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
||||||
struct blockdata *saved_question = NULL;
|
struct blockdata *saved_question = NULL;
|
||||||
unsigned short qtype;
|
unsigned short qtype;
|
||||||
unsigned int gotname = 0;
|
unsigned int gotname = 0;
|
||||||
@@ -2284,7 +2284,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int stale = 0, ede = EDE_UNSET;
|
int cacheable = 1, stale = 0, ede = EDE_UNSET;
|
||||||
size_t m = 0;
|
size_t m = 0;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
@@ -2329,6 +2329,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (saved_question)
|
if (saved_question)
|
||||||
blockdata_free(saved_question);
|
blockdata_free(saved_question);
|
||||||
|
|
||||||
|
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
|
||||||
saved_question = blockdata_alloc((char *)header, (size_t)size);
|
saved_question = blockdata_alloc((char *)header, (size_t)size);
|
||||||
saved_size = size;
|
saved_size = size;
|
||||||
|
|
||||||
@@ -2336,15 +2337,27 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||||
|
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
/* find queries for zones we're authoritative for, and answer them directly */
|
/* Find queries for zones we're authoritative for, and answer them directly.
|
||||||
|
The exception to this is DS queries for the zone route. They
|
||||||
|
have to come from the parent zone. Since dnsmasq's auth server
|
||||||
|
can't do DNSSEC, the zone will be unsigned, and anything using
|
||||||
|
dnsmasq as a forwarder and doing validation will be expecting to
|
||||||
|
see the proof of non-existence from the parent. */
|
||||||
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
if (!auth_dns && !option_bool(OPT_LOCALISE))
|
||||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||||
if (in_zone(zone, daemon->namebuff, NULL))
|
{
|
||||||
|
char *cut;
|
||||||
|
|
||||||
|
if (in_zone(zone, daemon->namebuff, &cut))
|
||||||
|
{
|
||||||
|
if (qtype != T_DS || cut)
|
||||||
{
|
{
|
||||||
auth_dns = 1;
|
auth_dns = 1;
|
||||||
local_auth = 1;
|
local_auth = 1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
norebind = domain_no_rebind(daemon->namebuff);
|
norebind = domain_no_rebind(daemon->namebuff);
|
||||||
@@ -2395,7 +2408,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||||
dst_addr_4, netmask, now, ad_reqd, do_bit, &stale, &filtered);
|
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2406,14 +2419,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
struct server *master;
|
struct server *master;
|
||||||
int start;
|
int start;
|
||||||
int cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
|
|
||||||
blockdata_retrieve(saved_question, (size_t)saved_size, header);
|
blockdata_retrieve(saved_question, (size_t)saved_size, header);
|
||||||
size = saved_size;
|
size = saved_size;
|
||||||
|
|
||||||
/* save state of "cd" flag in query */
|
/* save state of "cd" flag in query */
|
||||||
if ((checking_disabled = header->hb4 & HB4_CD))
|
checking_disabled = header->hb4 & HB4_CD;
|
||||||
no_cache_dnssec = 1;
|
|
||||||
|
|
||||||
if (lookup_domain(daemon->namebuff, gotname, &first, &last))
|
if (lookup_domain(daemon->namebuff, gotname, &first, &last))
|
||||||
flags = is_local_answer(now, first, daemon->namebuff);
|
flags = is_local_answer(now, first, daemon->namebuff);
|
||||||
@@ -2437,8 +2449,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
else
|
else
|
||||||
start = master->last_server;
|
start = master->last_server;
|
||||||
|
|
||||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
|
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
||||||
{
|
{
|
||||||
@@ -2451,11 +2461,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Check if we added a pheader on forwarding - may need to
|
|
||||||
strip it from the reply. */
|
|
||||||
if (!have_pseudoheader && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
|
|
||||||
added_pheader = 1;
|
|
||||||
|
|
||||||
/* Loop round available servers until we succeed in connecting to one. */
|
/* Loop round available servers until we succeed in connecting to one. */
|
||||||
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
|
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
|
||||||
ede = EDE_NETERR;
|
ede = EDE_NETERR;
|
||||||
@@ -2472,7 +2477,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
/* Clear this in case we don't call tcp_key_recurse() below */
|
/* Clear this in case we don't call tcp_key_recurse() below */
|
||||||
memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
|
memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
|
||||||
|
|
||||||
if (!checking_disabled && (master->flags & SERV_DO_DNSSEC))
|
if (checking_disabled || (header->hb4 & HB4_CD))
|
||||||
|
no_cache_dnssec = 1;
|
||||||
|
else if (master->flags & SERV_DO_DNSSEC)
|
||||||
{
|
{
|
||||||
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||||
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
int validatecount = daemon->limit[LIMIT_CRYPTO];
|
||||||
@@ -2481,12 +2488,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
char *result, *domain = "result";
|
char *result, *domain = "result";
|
||||||
|
|
||||||
union all_addr a;
|
union all_addr a;
|
||||||
a.log.ede = ede = errflags_to_ede(status);
|
ede = errflags_to_ede(status);
|
||||||
|
|
||||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||||
{
|
{
|
||||||
result = "ABANDONED";
|
result = "ABANDONED";
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
|
if (ede == EDE_UNSET)
|
||||||
|
ede = EDE_OTHER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||||
@@ -2495,6 +2504,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
cache_secure = 1;
|
cache_secure = 1;
|
||||||
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||||
{
|
{
|
||||||
|
if (ede == EDE_UNSET)
|
||||||
|
ede = EDE_DNSSEC_BOGUS;
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
bogusanswer = 1;
|
bogusanswer = 1;
|
||||||
|
|
||||||
@@ -2502,6 +2513,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
domain = daemon->namebuff;
|
domain = daemon->namebuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.log.ede = ede;
|
||||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||||
|
|
||||||
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||||
@@ -2530,7 +2542,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
m = process_reply(header, now, serv, (unsigned int)m,
|
m = process_reply(header, now, serv, (unsigned int)m,
|
||||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
ad_reqd, do_bit, added_pheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
||||||
|
|
||||||
/* process_reply() adds pheader itself */
|
/* process_reply() adds pheader itself */
|
||||||
have_pseudoheader = 0;
|
have_pseudoheader = 0;
|
||||||
|
|||||||
+15
-10
@@ -1559,7 +1559,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
|||||||
return daemon->max_ttl;
|
return daemon->max_ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cache_validated(const struct crec *crecp)
|
static int cache_not_validated(const struct crec *crecp)
|
||||||
{
|
{
|
||||||
return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
|
return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
|
||||||
}
|
}
|
||||||
@@ -1567,7 +1567,7 @@ static int cache_validated(const struct crec *crecp)
|
|||||||
/* return zero if we can't answer from cache, or packet size if we can */
|
/* return zero if we can't answer from cache, or packet size if we can */
|
||||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||||
struct in_addr local_addr, struct in_addr local_netmask,
|
struct in_addr local_addr, struct in_addr local_netmask,
|
||||||
time_t now, int ad_reqd, int do_bit, int *stale, int *filtered)
|
time_t now, int ad_reqd, int do_bit, int no_cache, int *stale, int *filtered)
|
||||||
{
|
{
|
||||||
char *name = daemon->namebuff;
|
char *name = daemon->namebuff;
|
||||||
unsigned char *p, *ansp;
|
unsigned char *p, *ansp;
|
||||||
@@ -1583,6 +1583,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
int rd_bit = (header->hb3 & HB3_RD);
|
int rd_bit = (header->hb3 & HB3_RD);
|
||||||
int count = 255; /* catch loops */
|
int count = 255; /* catch loops */
|
||||||
|
|
||||||
|
/* Suppress cached answers of no_cache set. */
|
||||||
|
if (no_cache)
|
||||||
|
rd_bit = 0;
|
||||||
|
|
||||||
if (stale)
|
if (stale)
|
||||||
*stale = 0;
|
*stale = 0;
|
||||||
|
|
||||||
@@ -1656,7 +1660,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
/* If the client asked for DNSSEC don't use cached data. */
|
/* If the client asked for DNSSEC don't use cached data. */
|
||||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||||
(rd_bit && (!do_bit || cache_validated(crecp))))
|
(rd_bit && (!do_bit || cache_not_validated(crecp))))
|
||||||
{
|
{
|
||||||
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
|
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
|
||||||
ans = 1;
|
ans = 1;
|
||||||
@@ -1815,7 +1819,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
the zone is unsigned, which implies that we're doing
|
the zone is unsigned, which implies that we're doing
|
||||||
validation. */
|
validation. */
|
||||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||||
(rd_bit && (!do_bit || cache_validated(crecp)) ))
|
(rd_bit && (!do_bit || cache_not_validated(crecp)) ))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -1971,7 +1975,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
/* If the client asked for DNSSEC don't use cached data. */
|
/* If the client asked for DNSSEC don't use cached data. */
|
||||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||||
(rd_bit && (!do_bit || cache_validated(crecp)) ))
|
(rd_bit && (!do_bit || cache_not_validated(crecp)) ))
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int stale_flag = 0;
|
int stale_flag = 0;
|
||||||
@@ -2153,8 +2157,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
if (!ans)
|
if (!ans)
|
||||||
{
|
{
|
||||||
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) &&
|
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) && rd_bit)
|
||||||
rd_bit && (!do_bit || cache_validated(crecp)))
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int flags = crecp->flags;
|
int flags = crecp->flags;
|
||||||
@@ -2165,7 +2168,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
else
|
else
|
||||||
rrtype = crecp->addr.rrdata.rrtype;
|
rrtype = crecp->addr.rrdata.rrtype;
|
||||||
|
|
||||||
if ((flags & F_NXDOMAIN) || rrtype == qtype)
|
if (((flags & F_NXDOMAIN) || rrtype == qtype) &&
|
||||||
|
(!do_bit || cache_not_validated(crecp)))
|
||||||
{
|
{
|
||||||
char *rrdata = NULL;
|
char *rrdata = NULL;
|
||||||
unsigned short rrlen = 0;
|
unsigned short rrlen = 0;
|
||||||
@@ -2228,14 +2232,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (qtype != T_ANY && !ans && rr_on_list(daemon->filter_rr, qtype))
|
if (qtype != T_ANY && !ans && rr_on_list(daemon->filter_rr, qtype) && !do_bit)
|
||||||
{
|
{
|
||||||
/* We don't have a cached answer and when we get an answer from upstream we're going to
|
/* We don't have a cached answer and when we get an answer from upstream we're going to
|
||||||
filter it anyway. If we have a cached answer for the domain for another RRtype then
|
filter it anyway. If we have a cached answer for the domain for another RRtype then
|
||||||
that may be enough to tell us if the answer should be NODATA and save the round trip.
|
that may be enough to tell us if the answer should be NODATA and save the round trip.
|
||||||
Cached NXDOMAIN has already been handled, so here we look for any record for the domain,
|
Cached NXDOMAIN has already been handled, so here we look for any record for the domain,
|
||||||
since its existence allows us to return a NODATA answer. Note that we never set the AD flag,
|
since its existence allows us to return a NODATA answer. Note that we never set the AD flag,
|
||||||
since we didn't authenticate the record. */
|
since we didn't authenticate the record; this doesn't work if we want auth data, so
|
||||||
|
don't use this shortcut in that case. */
|
||||||
|
|
||||||
if (cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_RR | F_CNAME))
|
if (cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_RR | F_CNAME))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -345,9 +345,6 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
|||||||
if (old >= new+1)
|
if (old >= new+1)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (new >= 100)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
new += 5;
|
new += 5;
|
||||||
|
|
||||||
if (!(p = whine_realloc(*wkspc, new * sizeof(unsigned char *))))
|
if (!(p = whine_realloc(*wkspc, new * sizeof(unsigned char *))))
|
||||||
|
|||||||
+14
-9
@@ -767,10 +767,10 @@ int retry_send(ssize_t rc)
|
|||||||
|
|
||||||
/* rw = 0 -> write
|
/* rw = 0 -> write
|
||||||
rw = 1 -> read
|
rw = 1 -> read
|
||||||
rw = 2 -> read once
|
rw = 2 -> write once
|
||||||
rw = 3 -> write once
|
rw = 3 -> read once
|
||||||
|
|
||||||
"once" fail if all the data doesn't arrive/go in a single read/write.
|
"once" fails on EAGAIN, as this a timeout.
|
||||||
This indicates a timeout of a TCP socket.
|
This indicates a timeout of a TCP socket.
|
||||||
*/
|
*/
|
||||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||||
@@ -779,7 +779,6 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
|||||||
|
|
||||||
for (done = 0; done < size; done += n)
|
for (done = 0; done < size; done += n)
|
||||||
{
|
{
|
||||||
do {
|
|
||||||
if (rw & 1)
|
if (rw & 1)
|
||||||
n = read(fd, &packet[done], (size_t)(size - done));
|
n = read(fd, &packet[done], (size_t)(size - done));
|
||||||
else
|
else
|
||||||
@@ -788,19 +787,25 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
|||||||
if (n == 0)
|
if (n == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (n == -1 && errno == EINTR)
|
if (n == -1)
|
||||||
|
{
|
||||||
|
n = 0; /* don't mess with counter when we loop. */
|
||||||
|
|
||||||
|
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
|
{
|
||||||
/* "once" variant */
|
/* "once" variant */
|
||||||
if ((rw & 2) && n != size)
|
if (rw & 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} while (n == -1 && (errno == EINTR || errno == ENOMEM || errno == ENOBUFS ||
|
continue;
|
||||||
errno == EAGAIN || errno == EWOULDBLOCK));
|
}
|
||||||
|
|
||||||
if (n == -1)
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user