Compare commits

..
Author SHA1 Message Date
Simon Kelley a458c2bfb0 Tidy up pipe-to-parent code in DNS TCP path. 2025-04-23 12:14:00 +01:00
Simon Kelley 9e67099ce7 Tidy up replies to non-QUERY DNS opcodes in auth mode. 2025-04-22 18:07:24 +01:00
Rob Gill cfa1313e1f Log format error from upstream as 'FORMERR'
Signed-off-by: Rob Gill <rrobgill@protonmail.com>

At the moment if a misformatted query is reported by the upstream server
it is not clear from the log.
Other error codes from RFC1035 (server failure, not implemented,
refused) are logged with text, but format error is logged merely as "1".

Such that an upstream reporting a format error is presently logged as eg:
Apr 20 12:01:55 dnsmasq[3023]: reply error is 1

After this patch they are logged informatively, eg:
Apr 20 12:48:40 dnsmasq[3023]: reply error is FORMERR

This is a two line fix, FORMERR is already defined in dns-protocol.h.
2025-04-20 22:38:43 +01:00
Simon Kelley e3a2c8dadf Add --log-queries=auth option. 2025-04-20 22:20:52 +01:00
Simon Kelley 95b74a7acf Fix copy 'n paste error in DBUS server-statistics code. 2025-04-18 23:50:46 +01:00
8 changed files with 253 additions and 191 deletions

No files matched your search

+2 -1
View File
@@ -134,7 +134,8 @@ only, to stop dnsmasq daemonising in production, use
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
.B --log-queries=extra .B --log-queries=extra
then the log has extra information at the start of each line. then the log has extra information at the start of each line.
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor. If the argument "proto" is supplied, this shows everything that "extra" does and also the network protocol used to communicate the queries. This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor. If the argument "proto" is supplied, this shows everything that "extra" does and also the network protocol used to communicate the queries. Logging of only queries to the authoritative server can be configured with
.B --log-queries=auth
.TP .TP
.B \-8, --log-facility=<facility> .B \-8, --log-facility=<facility>
Set the facility to which dnsmasq will send syslog entries, this Set the facility to which dnsmasq will send syslog entries, this
+47 -34
View File
@@ -103,9 +103,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
unsigned char *p, *ansp; unsigned char *p, *ansp;
int qtype, qclass, rc; int qtype, qclass, rc;
int nameoffset, axfroffset = 0; int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0; int anscount = 0, authcount = 0;
struct crec *crecp; struct crec *crecp;
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0; int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0, notimp = 0;
struct auth_zone *zone = NULL; struct auth_zone *zone = NULL;
struct addrlist *subnet = NULL; struct addrlist *subnet = NULL;
char *cut; char *cut;
@@ -116,18 +116,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
union all_addr addr; union all_addr addr;
struct cname *a, *candidate; struct cname *a, *candidate;
unsigned int wclen; unsigned int wclen;
unsigned int log_flags = local_query ? 0 : F_NOERR;
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY ) if (ntohs(header->qdcount) != 1)
return 0; return 0;
/* determine end of question section (we put answers there) */ /* determine end of question section (we put answers there) */
if (!(ansp = skip_questions(header, qlen))) if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */ return 0; /* bad packet */
/* now process each question, answers go in RRs after the question */
p = (unsigned char *)(header+1); p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--) if (OPCODE(header) != QUERY)
notimp = 1;
else
{ {
unsigned int flag = 0; unsigned int flag = 0;
int found = 0; int found = 0;
@@ -147,7 +149,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
auth = 0; auth = 0;
out_of_zone = 1; out_of_zone = 1;
continue; goto done;
} }
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) && if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
@@ -162,7 +164,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
out_of_zone = 1; out_of_zone = 1;
auth = 0; auth = 0;
continue; goto done;
} }
else if (qtype == T_SOA) else if (qtype == T_SOA)
soa = 1, found = 1; soa = 1, found = 1;
@@ -210,7 +212,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (local_query || in_zone(zone, intr->name, NULL)) if (local_query || in_zone(zone, intr->name, NULL))
{ {
found = 1; found = 1;
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0); log_query(log_flags | flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name)) T_PTR, C_IN, "d", intr->name))
@@ -234,7 +236,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
strcat(name, "."); strcat(name, ".");
strcat(name, zone->domain); strcat(name, zone->domain);
} }
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0); log_query(log_flags | flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
found = 1; found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, daemon->auth_ttl, NULL,
@@ -243,7 +245,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL))) else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
{ {
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0); log_query(log_flags | (crecp->flags & ~F_FORWARD), name, &addr, record_source(crecp->uid), 0);
found = 1; found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, daemon->auth_ttl, NULL,
@@ -257,7 +259,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL))) if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
{ {
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0); log_query(log_flags | F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
found = 1; found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
@@ -269,9 +271,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (found) if (found)
nxdomain = 0; nxdomain = 0;
else else
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0); log_query(log_flags | flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
continue; goto done;
} }
cname_restart: cname_restart:
@@ -288,7 +290,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
out_of_zone = 1; out_of_zone = 1;
auth = 0; auth = 0;
continue; goto done;
} }
} }
@@ -300,7 +302,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_MX) if (rc == 2 && qtype == T_MX)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0); log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", rec->weight, rec->target)) NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
anscount++; anscount++;
@@ -315,7 +317,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_SRV) if (rc == 2 && qtype == T_SRV)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0); log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd", NULL, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target)) rec->priority, rec->weight, rec->srvport, rec->target))
@@ -349,7 +351,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && txt->class == qtype) if (rc == 2 && txt->class == qtype)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class); log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt)) NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++; anscount++;
@@ -363,7 +365,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_TXT) if (rc == 2 && qtype == T_TXT)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0); log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", txt->len, txt->txt)) NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
anscount++; anscount++;
@@ -377,7 +379,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (rc == 2 && qtype == T_NAPTR) if (rc == 2 && qtype == T_NAPTR)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0); log_query(log_flags | F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd", NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace)) na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
@@ -407,7 +409,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
continue; continue;
found = 1; found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0); log_query(log_flags | F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 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", &addrlist->addr)) qtype == T_A ? "4" : "6", &addrlist->addr))
@@ -419,7 +421,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
nxdomain = 0; nxdomain = 0;
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0); log_query(log_flags | F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 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, qtype == T_A ? "4" : "6", &addr)) daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
anscount++; anscount++;
@@ -432,7 +434,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (qtype == T_SOA) if (qtype == T_SOA)
{ {
auth = soa = 1; /* inhibits auth section */ auth = soa = 1; /* inhibits auth section */
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0); log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
} }
else if (qtype == T_AXFR) else if (qtype == T_AXFR)
{ {
@@ -468,13 +470,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
ns = 1; /* ensure we include NS records! */ ns = 1; /* ensure we include NS records! */
axfr = 1; axfr = 1;
axfroffset = nameoffset; axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0); log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
} }
else if (qtype == T_NS) else if (qtype == T_NS)
{ {
auth = 1; auth = 1;
ns = 1; /* inhibits auth section */ ns = 1; /* inhibits auth section */
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0); log_query(log_flags | F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
} }
} }
@@ -492,7 +494,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
(local_query || filter_zone(zone, flag, &(crecp->addr)))) (local_query || filter_zone(zone, flag, &(crecp->addr))))
{ {
*cut = '.'; /* restore domain part */ *cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0); log_query(log_flags | crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
*cut = 0; /* remove domain part */ *cut = 0; /* remove domain part */
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,
@@ -513,7 +515,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 & ~F_REVERSE, name, &crecp->addr, record_source(crecp->uid), 0); log_query(log_flags | (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))
@@ -560,7 +562,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (candidate) if (candidate)
{ {
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0); log_query(log_flags | F_CONFIG | F_CNAME, name, NULL, NULL, 0);
strcpy(name, candidate->target); strcpy(name, candidate->target);
if (!strchr(name, '.')) if (!strchr(name, '.'))
{ {
@@ -578,10 +580,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
else if (cache_find_non_terminal(name, now)) else if (cache_find_non_terminal(name, now))
nxdomain = 0; nxdomain = 0;
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0); log_query(log_flags | flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
} }
} }
done:
/* Add auth section */ /* Add auth section */
if (auth && zone) if (auth && zone)
@@ -873,7 +877,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (!(ansp = skip_questions(header, qlen))) if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */ return 0; /* bad packet */
anscount = authcount = 0; anscount = authcount = 0;
log_query(F_AUTH, "reply", NULL, "truncated", 0); log_query(log_flags | F_AUTH, "reply", NULL, "truncated", 0);
} }
if ((auth || local_query) && nxdomain) if ((auth || local_query) && nxdomain)
@@ -885,14 +889,23 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
header->nscount = htons(authcount); header->nscount = htons(authcount);
header->arcount = htons(0); header->arcount = htons(0);
if (!local_query && out_of_zone) if ((!local_query && out_of_zone) || notimp)
{ {
SET_RCODE(header, REFUSED); if (out_of_zone)
{
addr.log.rcode = REFUSED;
addr.log.ede = EDE_NOT_AUTH;
}
else
{
addr.log.rcode = NOTIMP;
addr.log.ede = EDE_UNSET;
}
SET_RCODE(header, addr.log.rcode);
header->ancount = htons(0); header->ancount = htons(0);
header->nscount = htons(0); header->nscount = htons(0);
addr.log.rcode = REFUSED; log_query(log_flags | F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
addr.log.ede = EDE_NOT_AUTH;
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0); return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
} }
+174 -143
View File
@@ -799,14 +799,16 @@ void cache_end_insert(void)
char *name = cache_get_name(new_chain); char *name = cache_get_name(new_chain);
ssize_t m = strlen(name); ssize_t m = strlen(name);
unsigned int flags = new_chain->flags; unsigned int flags = new_chain->flags;
unsigned char op = PIPE_OP_RR;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
u16 class = new_chain->uid; u16 class = new_chain->uid;
#endif #endif
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)name, m, RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), RW_WRITE);
if (flags & F_RR) if (flags & F_RR)
@@ -838,27 +840,29 @@ void cache_end_insert(void)
/* signal end of cache insert in master process */ /* signal end of cache insert in master process */
if (daemon->pipe_to_parent != -1) if (daemon->pipe_to_parent != -1)
{ {
ssize_t m = -1; unsigned char op = PIPE_OP_END;
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
#ifdef HAVE_DNSSEC
/* Sneak out possibly updated crypto HWM values. */
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_CRYPTO_HWM],
sizeof(daemon->metrics[METRIC_CRYPTO_HWM]), RW_WRITE);
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_SIG_FAIL_HWM],
sizeof(daemon->metrics[METRIC_SIG_FAIL_HWM]), RW_WRITE);
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_WORK_HWM],
sizeof(daemon->metrics[METRIC_WORK_HWM]), RW_WRITE);
#endif
} }
new_chain = NULL;
} }
#ifdef HAVE_DNSSEC
void cache_update_hwm(void)
{
/* Sneak out possibly updated crypto HWM values. */
unsigned char op = PIPE_OP_STATS;
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_CRYPTO_HWM],
sizeof(daemon->metrics[METRIC_CRYPTO_HWM]), RW_WRITE);
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_SIG_FAIL_HWM],
sizeof(daemon->metrics[METRIC_SIG_FAIL_HWM]), RW_WRITE);
read_write(daemon->pipe_to_parent,
(unsigned char *)&daemon->metrics[METRIC_WORK_HWM],
sizeof(daemon->metrics[METRIC_WORK_HWM]), RW_WRITE);
}
#endif
/* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */ /* A marshalled cache entry arrives on fd, read, unmarshall and insert into cache of master process. */
int cache_recv_insert(time_t now, int fd) int cache_recv_insert(time_t now, int fd)
@@ -869,139 +873,150 @@ int cache_recv_insert(time_t now, int fd)
time_t ttd; time_t ttd;
unsigned int flags; unsigned int flags;
struct crec *crecp = NULL; struct crec *crecp = NULL;
unsigned char op;
cache_start_insert(); cache_start_insert();
while (1) while (1)
{ {
if (!read_write(fd, &op, sizeof(op), RW_READ))
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
return 0; return 0;
if (m == -1) switch (op)
{ {
#ifdef HAVE_DNSSEC case PIPE_OP_END:
/* Sneak in possibly updated crypto HWM. */
unsigned int val;
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
return 0;
if (val > daemon->metrics[METRIC_CRYPTO_HWM])
daemon->metrics[METRIC_CRYPTO_HWM] = val;
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
return 0;
if (val > daemon->metrics[METRIC_SIG_FAIL_HWM])
daemon->metrics[METRIC_SIG_FAIL_HWM] = val;
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
return 0;
if (val > daemon->metrics[METRIC_WORK_HWM])
daemon->metrics[METRIC_WORK_HWM] = val;
#endif
cache_end_insert(); cache_end_insert();
return 1; return 1;
}
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* UDP validation moved to TCP to avoid truncation. case PIPE_OP_STATS:
Restart UDP validation process with the returned result. */ {
if (m == -2) /* Sneak in possibly updated crypto HWM. */
{ unsigned int val;
int status, uid, keycount, validatecount;
int *keycountp, *validatecountp; if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
size_t ret_len; return 0;
if (val > daemon->metrics[METRIC_CRYPTO_HWM])
daemon->metrics[METRIC_CRYPTO_HWM] = val;
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
return 0;
if (val > daemon->metrics[METRIC_SIG_FAIL_HWM])
daemon->metrics[METRIC_SIG_FAIL_HWM] = val;
if (!read_write(fd, (unsigned char *)&val, sizeof(val), RW_READ))
return 0;
if (val > daemon->metrics[METRIC_WORK_HWM])
daemon->metrics[METRIC_WORK_HWM] = val;
return 1;
}
struct frec *forward; case PIPE_OP_RESULT:
{
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ)) /* UDP validation moved to TCP to avoid truncation.
return 0; Restart UDP validation process with the returned result. */
if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ)) int status, uid, keycount, validatecount;
return 0; int *keycountp, *validatecountp;
if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ)) size_t ret_len;
return 0;
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ)) struct frec *forward;
return 0;
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ)) if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ))
return 0; return 0;
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ)) if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ))
return 0; return 0;
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ)) if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ))
return 0; return 0;
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ)) if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ))
return 0; return 0;
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ)) if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
return 0; return 0;
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ))
/* There's a tiny chance that the frec may have been freed return 0;
and reused before the TCP process returns. Detect that with if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ))
the uid field which is unique modulo 2^32 for each use. */ return 0;
if (uid == forward->uid) if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ))
{ return 0;
/* repatriate the work counters from the child process. */ if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
*keycountp = keycount; return 0;
*validatecountp = validatecount;
/* There's a tiny chance that the frec may have been freed
if (!forward->dependent) and reused before the TCP process returns. Detect that with
return_reply(now, forward, (struct dns_header *)daemon->packet, ret_len, status); the uid field which is unique modulo 2^32 for each use. */
else if (uid == forward->uid)
pop_and_retry_query(forward, status, now); {
} /* repatriate the work counters from the child process. */
*keycountp = keycount;
return 1; *validatecountp = validatecount;
}
if (!forward->dependent)
return_reply(now, forward, (struct dns_header *)daemon->packet, ret_len, status);
else
pop_and_retry_query(forward, status, now);
}
return 1;
}
#endif #endif
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, RW_READ) || case PIPE_OP_RR:
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), RW_READ) || if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ) ||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) || !read_write(fd, (unsigned char *)daemon->namebuff, m, RW_READ) ||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ)) !read_write(fd, (unsigned char *)&ttd, sizeof(ttd), RW_READ) ||
return 0; !read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
daemon->namebuff[m] = 0; return 0;
ttl = difftime(ttd, now); daemon->namebuff[m] = 0;
if (flags & F_CNAME) ttl = difftime(ttd, now);
{
struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags); if (flags & F_CNAME)
/* This relies on the fact that the target of a CNAME immediately precedes
it because of the order of extraction in extract_addresses, and
the order reversal on the new_chain. */
if (newc)
{ {
newc->addr.cname.is_name_ptr = 0; struct crec *newc = really_insert(daemon->namebuff, NULL, C_IN, now, ttl, flags);
/* This relies on the fact that the target of a CNAME immediately precedes
if (!crecp) it because of the order of extraction in extract_addresses, and
newc->addr.cname.target.cache = NULL; the order reversal on the new_chain. */
else if (newc)
{ {
next_uid(crecp); newc->addr.cname.is_name_ptr = 0;
newc->addr.cname.target.cache = crecp;
newc->addr.cname.uid = crecp->uid; if (!crecp)
newc->addr.cname.target.cache = NULL;
else
{
next_uid(crecp);
newc->addr.cname.target.cache = crecp;
newc->addr.cname.uid = crecp->uid;
}
} }
} }
} else
else {
{ unsigned short class = C_IN;
unsigned short class = C_IN;
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG) && !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen))) return 0;
return 0;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (flags & F_DNSKEY) if (flags & F_DNSKEY)
{ {
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) || if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen))) !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
return 0; return 0;
} }
else if (flags & F_DS) else if (flags & F_DS)
{ {
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) || if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))) (!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
return 0; return 0;
} }
#endif #endif
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags); crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
}
/* loop reading RRs, since we don't want to go back to the poll() loop
and start processing other queries which might pollute the insertion
chain. The child will never block between the first OP_RR and the OP_END */
continue;
} }
} }
} }
@@ -2180,12 +2195,17 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
char *extra = ""; char *extra = "";
char *gap = " "; char *gap = " ";
char portstring[7]; /* space for #<portnum> */ char portstring[7]; /* space for #<portnum> */
char opcodestring[3]; /* maximum is 15 */
if (!option_bool(OPT_LOG)) if (!option_bool(OPT_LOG))
return; return;
/* F_NOERR is reused here to indicate logs arrising from auth queries */
if (!(flags & F_NOERR) && option_bool(OPT_AUTH_LOG))
return;
/* build query type string if requested */ /* build query type string if requested */
if (!(flags & (F_SERVER | F_IPSET)) && type > 0) if (!(flags & (F_SERVER | F_IPSET | F_QUERY)) && type > 0)
arg = querystr(arg, type); arg = querystr(arg, type);
dest = arg; dest = arg;
@@ -2218,6 +2238,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
dest = "SERVFAIL"; dest = "SERVFAIL";
else if (rcode == REFUSED) else if (rcode == REFUSED)
dest = "REFUSED"; dest = "REFUSED";
else if (rcode == FORMERR)
dest = "FORMERR";
else if (rcode == NOTIMP) else if (rcode == NOTIMP)
dest = "not implemented"; dest = "not implemented";
else else
@@ -2276,6 +2298,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = arg; source = arg;
else if (flags & F_UPSTREAM) else if (flags & F_UPSTREAM)
source = "reply"; source = "reply";
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_SECSTAT) else if (flags & F_SECSTAT)
{ {
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG)) if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
@@ -2286,8 +2310,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "validation"; source = "validation";
dest = arg; dest = arg;
} }
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_DNSSEC) else if (flags & F_DNSSEC)
{ {
source = arg; source = arg;
@@ -2298,11 +2320,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "forwarded"; source = "forwarded";
verb = "to"; verb = "to";
} }
else if (flags & F_QUERY)
{
source = arg;
verb = "from";
}
else if (flags & F_IPSET) else if (flags & F_IPSET)
{ {
source = type ? "ipset add" : "nftset add"; source = type ? "ipset add" : "nftset add";
@@ -2314,7 +2331,21 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = "cached-stale"; source = "cached-stale";
else else
source = "cached"; source = "cached";
if (flags & F_QUERY)
{
if (flags & F_CONFIG)
{
sprintf(opcodestring, "%u", type & 0xf);
source = "non-query opcode";
name = opcodestring;
}
else if (!(flags & F_AUTH))
source = "query";
verb = "from";
}
if (!name) if (!name)
gap = name = ""; gap = name = "";
else if (!name[0]) else if (!name[0])
+4 -4
View File
@@ -768,10 +768,10 @@ static DBusMessage *dbus_get_server_metrics(DBusMessage* message)
add_dict_entry(&dict_array, "address", daemon->namebuff); add_dict_entry(&dict_array, "address", daemon->namebuff);
add_dict_int(&dict_array, "port", port); add_dict_int(&dict_array, "port", port);
add_dict_int(&dict_array, "queries", serv->queries); add_dict_int(&dict_array, "queries", queries);
add_dict_int(&dict_array, "failed_queries", serv->failed_queries); add_dict_int(&dict_array, "failed_queries", failed_queries);
add_dict_int(&dict_array, "nxdomain", serv->nxdomain_replies); add_dict_int(&dict_array, "nxdomain", nxdomain_replies);
add_dict_int(&dict_array, "retries", serv->retrys); add_dict_int(&dict_array, "retries", retrys);
add_dict_int(&dict_array, "latency", sigma_latency/count_latency); add_dict_int(&dict_array, "latency", sigma_latency/count_latency);
dbus_message_iter_close_container(&server_array, &dict_array); dbus_message_iter_close_container(&server_array, &dict_array);
+9 -2
View File
@@ -2124,6 +2124,10 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
if (!option_bool(OPT_DEBUG)) if (!option_bool(OPT_DEBUG))
{ {
#ifdef HAVE_DNSSEC
cache_update_hwm(); /* Sneak out possibly updated crypto HWM values. */
#endif
close(daemon->pipe_to_parent); close(daemon->pipe_to_parent);
flush_log(); flush_log();
_exit(0); _exit(0);
@@ -2229,10 +2233,10 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
if (!option_bool(OPT_DEBUG)) if (!option_bool(OPT_DEBUG))
{ {
ssize_t m = -2; unsigned char op = PIPE_OP_RESULT;
/* tell our parent we're done, and what the result was then exit. */ /* tell our parent we're done, and what the result was then exit. */
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE); read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&status, sizeof(status), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&status, sizeof(status), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)plen, sizeof(*plen), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)plen, sizeof(*plen), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)header, *plen, RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)header, *plen, RW_WRITE);
@@ -2242,6 +2246,9 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
read_write(daemon->pipe_to_parent, (unsigned char *)&keycount, sizeof(keycount), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&keycount, sizeof(keycount), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)validatecount, sizeof(*validatecount), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)validatecount, sizeof(*validatecount), RW_WRITE);
read_write(daemon->pipe_to_parent, (unsigned char *)&validatecount, sizeof(validatecount), RW_WRITE); read_write(daemon->pipe_to_parent, (unsigned char *)&validatecount, sizeof(validatecount), RW_WRITE);
cache_update_hwm(); /* Sneak out possibly updated crypto HWM values. */
close(daemon->pipe_to_parent); close(daemon->pipe_to_parent);
flush_log(); flush_log();
+9 -1
View File
@@ -281,7 +281,8 @@ struct event_desc {
#define OPT_LOG_PROTO 73 #define OPT_LOG_PROTO 73
#define OPT_NO_0x20 74 #define OPT_NO_0x20 74
#define OPT_DO_0x20 75 #define OPT_DO_0x20 75
#define OPT_LAST 76 #define OPT_AUTH_LOG 76
#define OPT_LAST 77
#define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -536,6 +537,10 @@ struct crec {
#define SRC_HOSTS 2 #define SRC_HOSTS 2
#define SRC_AH 3 #define SRC_AH 3
#define PIPE_OP_RR 1 /* Resource record */
#define PIPE_OP_END 2 /* Cache entry complete: commit */
#define PIPE_OP_RESULT 3 /* validation result. */
#define PIPE_OP_STATS 4 /* Update parent's stats */
/* struct sockaddr is not large enough to hold any address, /* struct sockaddr is not large enough to hold any address,
and specifically not big enough to hold an IPv6 address. and specifically not big enough to hold an IPv6 address.
@@ -1353,6 +1358,9 @@ void cache_end_insert(void);
void cache_start_insert(void); void cache_start_insert(void);
unsigned int cache_remove_uid(const unsigned int uid); unsigned int cache_remove_uid(const unsigned int uid);
int cache_recv_insert(time_t now, int fd); int cache_recv_insert(time_t now, int fd);
#ifdef HAVE_DNSSEC
void cache_update_hwm(void);
#endif
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class, struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
time_t now, unsigned long ttl, unsigned int flags); time_t now, unsigned long ttl, unsigned int flags);
void cache_reload(void); void cache_reload(void);
+6 -6
View File
@@ -1816,14 +1816,14 @@ void receive_query(struct listener *listen, time_t now)
#endif #endif
if (OPCODE(header) != QUERY) if (OPCODE(header) != QUERY)
log_query_mysockaddr(F_QUERY | F_FORWARD, "opcode", &source_addr, "non-query", 0); log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD | F_CONFIG, NULL, &source_addr, NULL, OPCODE(header));
else if (extract_request(header, (size_t)n, daemon->namebuff, &type, NULL)) else if (extract_request(header, (size_t)n, daemon->namebuff, &type, NULL))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
struct auth_zone *zone; struct auth_zone *zone;
#endif #endif
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff, log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff,
&source_addr, auth_dns ? "auth" : "query", type); &source_addr, NULL, 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.
@@ -2459,7 +2459,7 @@ unsigned char *tcp_request(int confd, time_t now,
if (OPCODE(header) != QUERY) if (OPCODE(header) != QUERY)
{ {
log_query_mysockaddr(F_QUERY | F_FORWARD, "opcode", &peer_addr, "non-query", 0); log_query_mysockaddr((auth_dns ? F_NOERR : 0) | F_QUERY | F_FORWARD | F_CONFIG, NULL, &peer_addr, NULL, OPCODE(header));
gotname = 0; gotname = 0;
flags = F_RCODE; flags = F_RCODE;
} }
@@ -2488,8 +2488,8 @@ unsigned char *tcp_request(int confd, time_t now,
saved_question = blockdata_alloc((char *)header, (size_t)size); saved_question = blockdata_alloc((char *)header, (size_t)size);
saved_size = size; saved_size = size;
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff, log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
&peer_addr, auth_dns ? "auth" : "query", qtype); &peer_addr, NULL, 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.
+2
View File
@@ -3435,6 +3435,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
set_option_bool(OPT_EXTRALOG); set_option_bool(OPT_EXTRALOG);
set_option_bool(OPT_LOG_PROTO); set_option_bool(OPT_LOG_PROTO);
} }
else if (strcmp(arg, "auth") == 0)
set_option_bool(OPT_AUTH_LOG);
} }
break; break;