mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-03 13:38:32 +00:00
Compare commits
40
Commits
v2.91rc2
...
v2.92test6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98189ff988 | ||
|
|
e86d53c438 | ||
|
|
e127a972d1 | ||
|
|
a458c2bfb0 | ||
|
|
9e67099ce7 | ||
|
|
cfa1313e1f | ||
|
|
e3a2c8dadf | ||
|
|
95b74a7acf | ||
|
|
ae57f84061 | ||
|
|
0620309b73 | ||
|
|
942a35f517 | ||
|
|
83658efbf4 | ||
|
|
b0b4d90b6a | ||
|
|
bdce03f928 | ||
|
|
d390dc0338 | ||
|
|
105c25e561 | ||
|
|
67e07b7fe8 | ||
|
|
f5659b406b | ||
|
|
484fea238a | ||
|
|
1e587bec57 | ||
|
|
581c201aa8 | ||
|
|
5487f6979e | ||
|
|
99f12e3541 | ||
|
|
7c1212e3d1 | ||
|
|
0ccbdf8087 | ||
|
|
57f0489f38 | ||
|
|
3e659bd4ec | ||
|
|
9af15871e6 | ||
|
|
5897e79d05 | ||
|
|
fc9135ca9f | ||
|
|
e427d4b0e6 | ||
|
|
9df1bd0cc1 | ||
|
|
5990074ab0 | ||
|
|
dbb69bd192 | ||
|
|
d17581c4c6 | ||
|
|
2c9ed7f425 | ||
|
|
717ff6adc3 | ||
|
|
f9f8d19bf5 | ||
|
|
535be2f5d3 | ||
|
|
bceab45dbe |
No files matched your search
@@ -1,3 +1,25 @@
|
||||
version 2.92
|
||||
Redesign the interaction between DNSSEC validation and per-domain
|
||||
servers, specified as --server=/<domain>/<ip-address>. This should
|
||||
just work in all cases now. If the normal chain-of-trust exists into
|
||||
the delegated domain then whether the domain is signed or not, DNSSEC
|
||||
validation will function normally. In the case the delegated domain
|
||||
is an "overlay" on top of the global DNS and no NS and/or DS records
|
||||
exist connecting it to the global dns, then if the domain is
|
||||
unsigned the situation will be handled by synthesising a
|
||||
proof-of-non-existence-of-DS for the domain and queries will be
|
||||
answered unvalidated; this action will be logged. A signed domain
|
||||
without chain-of-trust can be validated if a suitable trust-anchor
|
||||
is provided using --trust-anchor. This change should be backwards
|
||||
compatible for all existing working configurations; it extends the
|
||||
space of possible configurations which are functional.
|
||||
|
||||
Fix a couple of problems with DNSSEC validation and DNAME. One
|
||||
could cause validation failure on correct domains, and the other
|
||||
would fail to spot an invalid domain. Thanks to Graham Clinch
|
||||
for spotting the problem.
|
||||
|
||||
|
||||
version 2.91
|
||||
Fix spurious "resource limit exceeded messages". Thanks to
|
||||
Dominik Derigs for the bug report.
|
||||
@@ -113,11 +135,13 @@ version 2.91
|
||||
badly with rare broken DNS servers which don't preserve the case
|
||||
of the query in their reply. The first time a reply is returned
|
||||
which matches the query in all respects except case, a warning
|
||||
will be logged. If this coincides with DNS not functioning, it
|
||||
is necessary to disable bit 0x20 encoding with --no-0x20-encode.
|
||||
|
||||
will be logged. In this release, 0x020-encoding is default-off
|
||||
and must be explicitly enabled with --do-0x20-encoding. In future
|
||||
releases it may default on. You can avoid a future release
|
||||
changing the behaviour of an installation with --no-x20-encode.
|
||||
|
||||
Fix a long-standing problem when two queries which are identical
|
||||
in every repect _except_ case, get combined by dnsmasq. If
|
||||
in every respect _except_ case, get combined by dnsmasq. If
|
||||
dnsmasq gets eg, two queries for example.com and Example.com
|
||||
in quick succession it will get the answer for example.com from
|
||||
upstream and send that answer to both requestors. This means that
|
||||
@@ -135,7 +159,7 @@ version 2.90
|
||||
for a particular domain. Thanks to Daniel Danzberger for
|
||||
spotting this bug.
|
||||
|
||||
Set the default maximum DNS UDP packet sice to 1232. This
|
||||
Set the default maximum DNS UDP packet size to 1232. This
|
||||
has been the recommended value since 2020 because it's the
|
||||
largest value that avoid fragmentation, and fragmentation
|
||||
is just not reliable on the modern internet, especially
|
||||
@@ -143,14 +167,14 @@ version 2.90
|
||||
--edns-packet-max for special circumstances.
|
||||
|
||||
Add --no-dhcpv4-interface and --no-dhcpv6-interface for
|
||||
better control over which inetrfaces are providing DHCP service.
|
||||
better control over which interfaces are providing DHCP service.
|
||||
|
||||
Fix issue with stale caching: After replying with stale data,
|
||||
dnsmasq sends the query upstream to refresh the cache asynchronously
|
||||
and sometimes sends the wrong packet: packet length can be wrong,
|
||||
and if an EDE marking stale data is added to the answer that can
|
||||
end up in the query also. This bug only seems to cause problems
|
||||
when the usptream server is a DOH/DOT proxy. Thanks to Justin He
|
||||
when the upstream server is a DOH/DOT proxy. Thanks to Justin He
|
||||
for the bug report.
|
||||
|
||||
Add configurable caching for arbitrary RR-types.
|
||||
@@ -188,7 +212,7 @@ version 2.90
|
||||
Applied Cybersecurity ATHENE for finding this vulnerability.
|
||||
|
||||
CVE 2023-50387 and CVE 2023-50868 apply.
|
||||
Note that the is a security vulnerablity only when DNSSEC validation
|
||||
Note that this a security vulnerability only when DNSSEC validation
|
||||
is enabled.
|
||||
|
||||
Fix memory-leak when attempting to cache SRV records with zero TTL.
|
||||
@@ -274,7 +298,7 @@ version 2.88
|
||||
upstream servers from /etc/resolv.conf or other sources that
|
||||
can change dnsmasq tries to avoid memory fragmentation by re-using
|
||||
existing records that are being re-read unchanged. This involves
|
||||
seaching all the server records for each new one installed.
|
||||
searching all the server records for each new one installed.
|
||||
During startup this search is pointless, and can cause long
|
||||
start times with thousands of --server options because the work
|
||||
needed is O(n^2). Handle this case more intelligently.
|
||||
@@ -337,7 +361,7 @@ version 2.87
|
||||
|
||||
Enhance --domain to accept, for instance,
|
||||
--domain=net2.thekelleys.org.uk,eth2 so that hosts get a domain
|
||||
which relects the interface they are attached to in a way which
|
||||
which reflects the interface they are attached to in a way which
|
||||
doesn't require hard-coding addresses. Thanks to Sten Spans for
|
||||
the idea.
|
||||
|
||||
@@ -711,22 +735,22 @@ version 2.80
|
||||
but those which used the default of no checking will need to be
|
||||
altered to explicitly select no checking. The new default is
|
||||
because switching off checking for unsigned replies is
|
||||
inherently dangerous. Not only does it open the possiblity of forged
|
||||
inherently dangerous. Not only does it open the possibility of forged
|
||||
replies, but it allows everything to appear to be working even
|
||||
when the upstream namesevers do not support DNSSEC, and in this
|
||||
case no DNSSEC validation at all is occuring.
|
||||
case no DNSSEC validation at all is occurring.
|
||||
|
||||
Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip
|
||||
are set. Thanks to Daniel Miess for help with this.
|
||||
|
||||
Add a facilty to store DNS packets sent/recieved in a
|
||||
Add a facility to store DNS packets sent/received in a
|
||||
pcap-format file for later debugging. The file location
|
||||
is given by the --dumpfile option, and a bitmap controlling
|
||||
which packets should be dumped is given by the --dumpmask
|
||||
option.
|
||||
|
||||
Handle the case of both standard and constructed dhcp-ranges on the
|
||||
same interface better. We don't now contruct a dhcp-range if there's
|
||||
same interface better. We don't now construct a dhcp-range if there's
|
||||
already one specified. This allows the specified interface to
|
||||
have different parameters and avoids advertising the same
|
||||
prefix twice. Thanks to Luis Marsano for spotting this case.
|
||||
@@ -1196,7 +1220,7 @@ version 2.73
|
||||
|
||||
Use inotify for checking on updates to /etc/resolv.conf and
|
||||
friends under Linux. This fixes race conditions when the files are
|
||||
updated rapidly and saves CPU by noy polling. To build
|
||||
updated rapidly and saves CPU by not polling. To build
|
||||
a binary that runs on old Linux kernels without inotify,
|
||||
use make COPTS=-DNO_INOTIFY
|
||||
|
||||
@@ -1536,7 +1560,7 @@ version 2.68
|
||||
are dynamic and works much better than the previous
|
||||
work-around which exempted constructed DHCP ranges from the
|
||||
IP address filtering. As a consequence, that work-around
|
||||
is removed. Under certain circumstances, this change wil
|
||||
is removed. Under certain circumstances, this change will
|
||||
break existing configuration: if you're relying on the
|
||||
constructed-range exception, you need to change --auth-zone
|
||||
to specify the same interface as is used to construct your
|
||||
|
||||
+18
-13
@@ -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
|
||||
.B --log-queries=extra
|
||||
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
|
||||
.B \-8, --log-facility=<facility>
|
||||
Set the facility to which dnsmasq will send syslog entries, this
|
||||
@@ -498,10 +499,7 @@ xxx.internal.thekelleys.org.uk at 192.168.1.1 then giving the flag
|
||||
.B --server=/internal.thekelleys.org.uk/192.168.1.1
|
||||
will send all queries for
|
||||
internal machines to that nameserver, everything else will go to the
|
||||
servers in /etc/resolv.conf. DNSSEC validation is turned off for such
|
||||
private nameservers, UNLESS a
|
||||
.B --trust-anchor
|
||||
is specified for the domain in question. An empty domain specification,
|
||||
servers in /etc/resolv.conf. An empty domain specification,
|
||||
.B //
|
||||
has the special meaning of "unqualified names only" ie names without any
|
||||
dots in them. A non-standard port may be specified as
|
||||
@@ -852,13 +850,17 @@ name on successive queries, for load-balancing. This turns off that
|
||||
behaviour, so that the records are always returned in the order
|
||||
that they are received from upstream.
|
||||
.TP
|
||||
.B --no-0x20-encode
|
||||
By default, dnsmasq scrambles the case of letters in DNS queries it sends upstream as a security feature.
|
||||
.B --do-0x20-encode, --no-0x20-encode
|
||||
Dnsmasq can scramble the case of letters in DNS queries it sends upstream as a security feature.
|
||||
This technique can interact badly with rare broken DNS servers which don't preserve the case
|
||||
of the query in their reply. The first time a reply is returned
|
||||
which matches the query in all respects except case, a warning
|
||||
will be logged. If this coincides with DNS not functioning, it
|
||||
is necessary to disable this scrambling with --no-0x20-encode.
|
||||
is necessary to disable the feature. As at version 2.91, 0x20 encoding
|
||||
is disabled by default, and must be enabled with --do-0x20-encode. The default
|
||||
may change in the future, so to be sure of its status after an upgrade, set --do-0x20-encode
|
||||
or --no-0x20-encode in your config. --no-0x20-encode overrides --do-x20-encode or a future default
|
||||
0x20-encode enable.
|
||||
.TP
|
||||
.B --use-stale-cache[=<max TTL excess in s>]
|
||||
When set, if a DNS name exists in the cache, but its time-to-live has expired, dnsmasq will return the data anyway. (It attempts to refresh the
|
||||
@@ -872,7 +874,7 @@ Set the maximum number of concurrent DNS queries. The default value is
|
||||
150, which should be fine for most setups. The only known situation
|
||||
where this needs to be increased is when using web-server log file
|
||||
resolvers, which can generate large numbers of concurrent queries. This
|
||||
parameter actually controls the number of concurrent queries per server group, where a server group is the set of server(s) associated with a single domain. So if a domain has it's own server via --server=/example.com/1.2.3.4 and 1.2.3.4 is not responding, but queries for *.example.com cannot go elsewhere, then other queries will not be affected. On configurations with many such server groups and tight resources, this value may need to be reduced.
|
||||
parameter actually controls the number of concurrent queries per server group, where a server group is the set of server(s) associated with a single domain. So if a domain has its own server via --server=/example.com/1.2.3.4 and 1.2.3.4 is not responding, but queries for *.example.com cannot go elsewhere, then other queries will not be affected. On configurations with many such server groups and tight resources, this value may need to be reduced.
|
||||
.TP
|
||||
.B --dnssec
|
||||
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
|
||||
@@ -890,12 +892,15 @@ ie capable of returning DNSSEC records with data. If they are not,
|
||||
then dnsmasq will not be able to determine the trusted status of
|
||||
answers and this means that DNS service will be entirely broken.
|
||||
.TP
|
||||
.B --trust-anchor=<domain>,[<class>,]<key-tag>,<algorithm>,<digest-type>,<digest>
|
||||
.B --trust-anchor=<domain>,[<class>,][<key-tag>,<algorithm>,<digest-type>,<digest>]
|
||||
Provide DS records to act a trust anchors for DNSSEC
|
||||
validation. Typically these will be the DS record(s) for Key Signing
|
||||
validation. The class defaults to IN. Typically these will be the DS record(s) for Key Signing
|
||||
key(s) (KSK) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
but trust anchors for limited domains are also possible.
|
||||
A negative trust anchor (ie. proof that a DS record doesn't exist) may be configured be specifying
|
||||
only the name or only the name and class. This can be useful for forcing dnsmasq to treat zones delegated
|
||||
using \fB--server=/<domain>/<ip-address>\fP as unsigned. The current
|
||||
root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned[=no]
|
||||
As a default, dnsmasq checks that unsigned DNS replies are
|
||||
|
||||
+47
-34
@@ -103,9 +103,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass, rc;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
int anscount = 0, authcount = 0;
|
||||
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 addrlist *subnet = NULL;
|
||||
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;
|
||||
struct cname *a, *candidate;
|
||||
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;
|
||||
|
||||
/* determine end of question section (we put answers there) */
|
||||
if (!(ansp = skip_questions(header, qlen)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
/* now process each question, answers go in RRs after the question */
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
if (OPCODE(header) != QUERY)
|
||||
notimp = 1;
|
||||
else
|
||||
{
|
||||
unsigned int flag = 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;
|
||||
out_of_zone = 1;
|
||||
continue;
|
||||
goto done;
|
||||
}
|
||||
|
||||
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;
|
||||
auth = 0;
|
||||
continue;
|
||||
goto done;
|
||||
}
|
||||
else if (qtype == T_SOA)
|
||||
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))
|
||||
{
|
||||
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,
|
||||
daemon->auth_ttl, NULL,
|
||||
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, 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;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
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)))
|
||||
{
|
||||
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;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
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)))
|
||||
{
|
||||
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;
|
||||
|
||||
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)
|
||||
nxdomain = 0;
|
||||
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:
|
||||
@@ -288,7 +290,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
{
|
||||
out_of_zone = 1;
|
||||
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)
|
||||
{
|
||||
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,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
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)
|
||||
{
|
||||
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,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
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)
|
||||
{
|
||||
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,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
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)
|
||||
{
|
||||
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,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
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)
|
||||
{
|
||||
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,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
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;
|
||||
|
||||
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,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
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;
|
||||
|
||||
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,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -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! */
|
||||
axfr = 1;
|
||||
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)
|
||||
{
|
||||
auth = 1;
|
||||
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))))
|
||||
{
|
||||
*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 */
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
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;
|
||||
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,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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))
|
||||
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 */
|
||||
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)))
|
||||
return 0; /* bad packet */
|
||||
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)
|
||||
@@ -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->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->nscount = htons(0);
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
log_query(log_flags | F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,112 +126,110 @@ int iface_enumerate(int family, void *parm, callback_t callback)
|
||||
|
||||
for (addrs = head; addrs; addrs = addrs->ifa_next)
|
||||
{
|
||||
if (addrs->ifa_addr->sa_family == family)
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (iface_index == 0 || !addrs->ifa_addr ||
|
||||
addrs->ifa_addr->sa_family != family ||
|
||||
(!addrs->ifa_netmask && family != AF_LINK))
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
int iface_index = if_nametoindex(addrs->ifa_name);
|
||||
|
||||
if (iface_index == 0 || !addrs->ifa_addr ||
|
||||
(!addrs->ifa_netmask && family != AF_LINK))
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
|
||||
continue;
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
|
||||
continue;
|
||||
#endif
|
||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||
if (addrs->ifa_broadaddr)
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!callback.af_inet(addr, iface_index, NULL, netmask, broadcast, parm))
|
||||
goto err;
|
||||
}
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
|
||||
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
|
||||
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
|
||||
int i, j, prefix = 0;
|
||||
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
||||
int flags = 0;
|
||||
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
|
||||
if (addrs->ifa_broadaddr)
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!callback.af_inet(addr, iface_index, NULL, netmask, broadcast, parm))
|
||||
goto err;
|
||||
}
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
|
||||
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
|
||||
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
|
||||
int i, j, prefix = 0;
|
||||
u32 valid = 0xffffffff, preferred = 0xffffffff;
|
||||
int flags = 0;
|
||||
#ifdef HAVE_BSD_NETWORK
|
||||
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
|
||||
continue;
|
||||
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
|
||||
continue;
|
||||
#endif
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
|
||||
{
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
|
||||
{
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
|
||||
flags |= IFACE_TENTATIVE;
|
||||
|
||||
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
|
||||
flags |= IFACE_DEPRECATED;
|
||||
|
||||
#ifdef IN6_IFF_TEMPORARY
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef IN6_IFF_PRIVACY
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
|
||||
flags |= IFACE_PERMANENT;
|
||||
#endif
|
||||
}
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
|
||||
{
|
||||
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
|
||||
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
|
||||
}
|
||||
}
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
|
||||
{
|
||||
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
|
||||
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
|
||||
if (netmask[i] != 0xff)
|
||||
break;
|
||||
|
||||
if (i != IN6ADDRSZ && netmask[i])
|
||||
for (j = 7; j > 0; j--, prefix++)
|
||||
if ((netmask[i] & (1 << j)) == 0)
|
||||
break;
|
||||
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
if (!callback.af_inet6(addr, prefix, scope_id, iface_index, flags,
|
||||
(unsigned int) preferred, (unsigned int)valid, parm))
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (family == AF_LINK)
|
||||
{
|
||||
/* Assume ethernet again here */
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
|
||||
if (sdl->sdl_alen != 0 &&
|
||||
!callback.af_local(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
|
||||
if (netmask[i] != 0xff)
|
||||
break;
|
||||
|
||||
if (i != IN6ADDRSZ && netmask[i])
|
||||
for (j = 7; j > 0; j--, prefix++)
|
||||
if ((netmask[i] & (1 << j)) == 0)
|
||||
break;
|
||||
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
|
||||
if (!callback.af_inet6(addr, prefix, scope_id, iface_index, flags,
|
||||
(unsigned int) preferred, (unsigned int)valid, parm))
|
||||
goto err;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
else if (family == AF_LINK)
|
||||
{
|
||||
/* Assume ethernet again here */
|
||||
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
|
||||
if (sdl->sdl_alen != 0 &&
|
||||
!callback.af_local(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
|
||||
err:
|
||||
errsave = errno;
|
||||
freeifaddrs(head);
|
||||
|
||||
+224
-138
@@ -799,14 +799,16 @@ void cache_end_insert(void)
|
||||
char *name = cache_get_name(new_chain);
|
||||
ssize_t m = strlen(name);
|
||||
unsigned int flags = new_chain->flags;
|
||||
unsigned char op = PIPE_OP_RR;
|
||||
#ifdef HAVE_DNSSEC
|
||||
u16 class = new_chain->uid;
|
||||
#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 *)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 *)&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);
|
||||
|
||||
if (flags & F_RR)
|
||||
@@ -838,24 +840,39 @@ void cache_end_insert(void)
|
||||
/* signal end of cache insert in master process */
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
{
|
||||
ssize_t m = -1;
|
||||
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Sneak out possibly updated crypto HWM values. */
|
||||
m = daemon->metrics[METRIC_CRYPTO_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
m = daemon->metrics[METRIC_SIG_FAIL_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
m = daemon->metrics[METRIC_WORK_HWM];
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&m, sizeof(m), RW_WRITE);
|
||||
#endif
|
||||
unsigned char op = PIPE_OP_END;
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#if defined(HAVE_IPSET) || defined(HAVE_NFTSET)
|
||||
void cache_send_ipset(unsigned char op, struct ipsets *sets, int flags, union all_addr *addr)
|
||||
{
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&sets, sizeof(sets), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)addr, sizeof(*addr), RW_WRITE);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
@@ -866,137 +883,184 @@ int cache_recv_insert(time_t now, int fd)
|
||||
time_t ttd;
|
||||
unsigned int flags;
|
||||
struct crec *crecp = NULL;
|
||||
unsigned char op;
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
if (!read_write(fd, &op, sizeof(op), RW_READ))
|
||||
return 0;
|
||||
|
||||
if (m == -1)
|
||||
switch (op)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Sneak in possibly updated crypto HWM. */
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = m;
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_SIG_FAIL_HWM])
|
||||
daemon->metrics[METRIC_SIG_FAIL_HWM] = m;
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ))
|
||||
return 0;
|
||||
if (m > daemon->metrics[METRIC_WORK_HWM])
|
||||
daemon->metrics[METRIC_WORK_HWM] = m;
|
||||
#endif
|
||||
case PIPE_OP_END:
|
||||
cache_end_insert();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* UDP validation moved to TCP to avoid truncation.
|
||||
Restart UDP validation process with the returned result. */
|
||||
if (m == -2)
|
||||
{
|
||||
int status, uid, keycount, validatecount;
|
||||
int *keycountp, *validatecountp;
|
||||
size_t ret_len;
|
||||
case PIPE_OP_STATS:
|
||||
{
|
||||
/* 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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct frec *forward;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
and reused before the TCP process returns. Detect that with
|
||||
the uid field which is unique modulo 2^32 for each use. */
|
||||
if (uid == forward->uid)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*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;
|
||||
}
|
||||
case PIPE_OP_RESULT:
|
||||
{
|
||||
/* UDP validation moved to TCP to avoid truncation.
|
||||
Restart UDP validation process with the returned result. */
|
||||
int status, uid, keycount, validatecount;
|
||||
int *keycountp, *validatecountp;
|
||||
size_t ret_len;
|
||||
|
||||
struct frec *forward;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&status, sizeof(status), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ))
|
||||
return 0;
|
||||
if (!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
and reused before the TCP process returns. Detect that with
|
||||
the uid field which is unique modulo 2^32 for each use. */
|
||||
if (uid == forward->uid)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*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
|
||||
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
daemon->namebuff[m] = 0;
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
if (flags & F_CNAME)
|
||||
{
|
||||
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
|
||||
it because of the order of extraction in extract_addresses, and
|
||||
the order reversal on the new_chain. */
|
||||
if (newc)
|
||||
|
||||
case PIPE_OP_RR:
|
||||
if (!read_write(fd, (unsigned char *)&m, sizeof(m), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)daemon->namebuff, m, RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
daemon->namebuff[m] = 0;
|
||||
|
||||
ttl = difftime(ttd, now);
|
||||
|
||||
if (flags & F_CNAME)
|
||||
{
|
||||
newc->addr.cname.is_name_ptr = 0;
|
||||
|
||||
if (!crecp)
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
else
|
||||
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
|
||||
it because of the order of extraction in extract_addresses, and
|
||||
the order reversal on the new_chain. */
|
||||
if (newc)
|
||||
{
|
||||
next_uid(crecp);
|
||||
newc->addr.cname.target.cache = crecp;
|
||||
newc->addr.cname.uid = crecp->uid;
|
||||
newc->addr.cname.is_name_ptr = 0;
|
||||
|
||||
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
|
||||
{
|
||||
unsigned short class = C_IN;
|
||||
|
||||
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
||||
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
unsigned short class = C_IN;
|
||||
|
||||
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
||||
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
||||
return 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
|
||||
return 0;
|
||||
if (flags & F_DNSKEY)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
!(addr.key.keydata = blockdata_read(fd, addr.key.keylen)))
|
||||
return 0;
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
||||
}
|
||||
else if (flags & F_DS)
|
||||
|
||||
/* 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;
|
||||
|
||||
#if defined(HAVE_IPSET) || defined(HAVE_NFTSET)
|
||||
case PIPE_OP_IPSET:
|
||||
case PIPE_OP_NFTSET:
|
||||
{
|
||||
if (!read_write(fd, (unsigned char *)&class, sizeof(class), RW_READ) ||
|
||||
(!(flags & F_NEG) && !(addr.key.keydata = blockdata_read(fd, addr.key.keylen))))
|
||||
struct ipsets *sets;
|
||||
char **sets_cur;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)&sets, sizeof(sets), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&addr, sizeof(addr), RW_READ))
|
||||
return 0;
|
||||
|
||||
for (sets_cur = sets->sets; *sets_cur; sets_cur++)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (op == PIPE_OP_IPSET)
|
||||
rc = add_to_ipset(*sets_cur, &addr, flags, 0);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (op == PIPE_OP_NFTSET)
|
||||
rc = add_to_nftset(*sets_cur, &addr, flags, 0);
|
||||
#endif
|
||||
|
||||
if (rc == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, sets->domain, &addr, *sets_cur, op == PIPE_OP_IPSET);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1448,11 +1512,17 @@ void cache_reload(void)
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
cache->ttd = daemon->local_ttl;
|
||||
cache->name.namep = ds->name;
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
cache->addr.ds.keytag = ds->keytag;
|
||||
cache->addr.ds.digest = ds->digest_type;
|
||||
cache->uid = ds->class;
|
||||
if (ds->digestlen != 0)
|
||||
{
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
cache->addr.ds.keytag = ds->keytag;
|
||||
cache->addr.ds.digest = ds->digest_type;
|
||||
}
|
||||
else
|
||||
cache->flags |= F_NEG | F_DNSSECOK | F_NO_RR;
|
||||
|
||||
cache_hash(cache);
|
||||
make_non_terminals(cache);
|
||||
}
|
||||
@@ -2169,12 +2239,17 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
char *extra = "";
|
||||
char *gap = " ";
|
||||
char portstring[7]; /* space for #<portnum> */
|
||||
|
||||
char opcodestring[3]; /* maximum is 15 */
|
||||
|
||||
if (!option_bool(OPT_LOG))
|
||||
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 */
|
||||
if (!(flags & (F_SERVER | F_IPSET)) && type > 0)
|
||||
if (!(flags & (F_SERVER | F_IPSET | F_QUERY)) && type > 0)
|
||||
arg = querystr(arg, type);
|
||||
|
||||
dest = arg;
|
||||
@@ -2207,6 +2282,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
dest = "SERVFAIL";
|
||||
else if (rcode == REFUSED)
|
||||
dest = "REFUSED";
|
||||
else if (rcode == FORMERR)
|
||||
dest = "FORMERR";
|
||||
else if (rcode == NOTIMP)
|
||||
dest = "not implemented";
|
||||
else
|
||||
@@ -2265,6 +2342,8 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = arg;
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_SECSTAT)
|
||||
{
|
||||
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
||||
@@ -2275,8 +2354,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = "validation";
|
||||
dest = arg;
|
||||
}
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_DNSSEC)
|
||||
{
|
||||
source = arg;
|
||||
@@ -2287,11 +2364,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = "forwarded";
|
||||
verb = "to";
|
||||
}
|
||||
else if (flags & F_QUERY)
|
||||
{
|
||||
source = arg;
|
||||
verb = "from";
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = type ? "ipset add" : "nftset add";
|
||||
@@ -2303,7 +2375,21 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
source = "cached-stale";
|
||||
else
|
||||
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)
|
||||
gap = name = "";
|
||||
else if (!name[0])
|
||||
|
||||
+8
-3
@@ -26,6 +26,7 @@
|
||||
#define DNSSEC_LIMIT_SIG_FAIL 20 /* Number of signature that can fail to validate in one answer */
|
||||
#define DNSSEC_LIMIT_CRYPTO 200 /* max no. of crypto operations to validate one query. */
|
||||
#define DNSSEC_LIMIT_NSEC3_ITERS 150 /* Max. number if iterations allowed in NSEC3 record. */
|
||||
#define DNSSEC_ASSUMED_DS_TTL 3600 /* TTL for negative DS records implied by server=/domain/ */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define SMALL_PORT_RANGE 30 /* If DNS port range is smaller than this, use different allocation. */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
@@ -152,6 +153,7 @@ NO_AUTH
|
||||
NO_DUMPFILE
|
||||
NO_LOOP
|
||||
NO_INOTIFY
|
||||
NO_IPSET
|
||||
these are available to explicitly disable compile time options which would
|
||||
otherwise be enabled automatically or which are enabled by default
|
||||
in the distributed source tree. Building dnsmasq
|
||||
@@ -286,7 +288,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#define HAVE_BSD_NETWORK
|
||||
#define HAVE_GETOPT_LONG
|
||||
#define HAVE_SOCKADDR_SA_LEN
|
||||
#define NO_IPSET
|
||||
/* Define before sys/socket.h is included so we get socklen_t */
|
||||
#define _BSD_SOCKLEN_T_
|
||||
/* Select the RFC_3542 version of the IPv6 socket API.
|
||||
@@ -296,7 +297,6 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#ifndef SOL_TCP
|
||||
# define SOL_TCP IPPROTO_TCP
|
||||
#endif
|
||||
#define NO_IPSET
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#define HAVE_BSD_NETWORK
|
||||
@@ -346,6 +346,11 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_IPSET
|
||||
#undef HAVE_NFTSET
|
||||
#endif
|
||||
|
||||
#if defined(NO_IPSET)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
@@ -459,4 +464,4 @@ static char *compile_opts =
|
||||
#endif
|
||||
"dumpfile";
|
||||
|
||||
#endif /* defined(HAVE_DHCP) */
|
||||
#endif /* defined(DNSMASQ_COMPILE_OPTS) */
|
||||
+4
-4
@@ -768,10 +768,10 @@ static DBusMessage *dbus_get_server_metrics(DBusMessage* message)
|
||||
add_dict_entry(&dict_array, "address", daemon->namebuff);
|
||||
|
||||
add_dict_int(&dict_array, "port", port);
|
||||
add_dict_int(&dict_array, "queries", serv->queries);
|
||||
add_dict_int(&dict_array, "failed_queries", serv->failed_queries);
|
||||
add_dict_int(&dict_array, "nxdomain", serv->nxdomain_replies);
|
||||
add_dict_int(&dict_array, "retries", serv->retrys);
|
||||
add_dict_int(&dict_array, "queries", queries);
|
||||
add_dict_int(&dict_array, "failed_queries", failed_queries);
|
||||
add_dict_int(&dict_array, "nxdomain", nxdomain_replies);
|
||||
add_dict_int(&dict_array, "retries", retrys);
|
||||
add_dict_int(&dict_array, "latency", sigma_latency/count_latency);
|
||||
|
||||
dbus_message_iter_close_container(&server_array, &dict_array);
|
||||
|
||||
+1
-1
@@ -812,7 +812,7 @@ void dhcp_construct_contexts(time_t now)
|
||||
{
|
||||
if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
|
||||
{
|
||||
/* previously constructed context has gone. advertise it's demise */
|
||||
/* previously constructed context has gone; advertise its demise */
|
||||
context->flags |= CONTEXT_OLD;
|
||||
context->address_lost_time = now;
|
||||
/* Apply same ceiling of configured lease time as in radv.c */
|
||||
|
||||
+14
-6
@@ -133,6 +133,7 @@ int main (int argc, char **argv)
|
||||
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
||||
presentation format would be twice as long as the spec. */
|
||||
daemon->keyname = safe_malloc((MAXDNAME * 2) + 1);
|
||||
daemon->cname = safe_malloc((MAXDNAME * 2) + 1);
|
||||
/* one char flag per possible RR in answer section (may get extended). */
|
||||
daemon->rr_status_sz = 64;
|
||||
daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz);
|
||||
@@ -930,7 +931,8 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
|
||||
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
my_syslog(LOG_INFO, _("configured with trust anchor for %s keytag %u"),
|
||||
my_syslog(LOG_INFO,
|
||||
ds->digestlen == 0 ? _("configured with negative trust anchor for %s") : _("configured with trust anchor for %s keytag %u"),
|
||||
ds->name[0] == 0 ? "<root>" : ds->name, ds->keytag);
|
||||
}
|
||||
#endif
|
||||
@@ -2122,6 +2124,10 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
cache_update_hwm(); /* Sneak out possibly updated crypto HWM values. */
|
||||
#endif
|
||||
|
||||
close(daemon->pipe_to_parent);
|
||||
flush_log();
|
||||
_exit(0);
|
||||
@@ -2140,7 +2146,7 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
cache_recv_insert() calls pop_and_retry_query() after the result
|
||||
arrives via the pipe to the parent. */
|
||||
int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header *header,
|
||||
ssize_t *plen, int class, struct server *server, int *keycount, int *validatecount)
|
||||
ssize_t *plen, char *name, int class, struct server *server, int *keycount, int *validatecount)
|
||||
{
|
||||
struct server *s;
|
||||
|
||||
@@ -2214,8 +2220,7 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
}
|
||||
}
|
||||
|
||||
status = tcp_from_udp(now, status, header, plen, class, daemon->namebuff, daemon->keyname,
|
||||
server, keycount, validatecount);
|
||||
status = tcp_from_udp(now, status, header, plen, class, name, server, keycount, validatecount);
|
||||
|
||||
/* close upstream connections. */
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
@@ -2228,10 +2233,10 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
|
||||
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. */
|
||||
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 *)plen, sizeof(*plen), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)header, *plen, RW_WRITE);
|
||||
@@ -2241,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 *)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);
|
||||
|
||||
flush_log();
|
||||
|
||||
+24
-9
@@ -280,7 +280,9 @@ struct event_desc {
|
||||
#define OPT_LOCALHOST_SERVICE 72
|
||||
#define OPT_LOG_PROTO 73
|
||||
#define OPT_NO_0x20 74
|
||||
#define OPT_LAST 75
|
||||
#define OPT_DO_0x20 75
|
||||
#define OPT_AUTH_LOG 76
|
||||
#define OPT_LAST 77
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -535,6 +537,12 @@ struct crec {
|
||||
#define SRC_HOSTS 2
|
||||
#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 */
|
||||
#define PIPE_OP_IPSET 5 /* Update IPset */
|
||||
#define PIPE_OP_NFTSET 6 /* Update NFTset */
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -552,9 +560,9 @@ union mysockaddr {
|
||||
|
||||
|
||||
/* The actual values here matter, since we sort on them to get records in the order
|
||||
IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
|
||||
#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */
|
||||
IPv6 addr, IPv4 addr, all zero return, no-data return, resolvconf servers, upstream server */
|
||||
#define SERV_USE_RESOLV 1 /* forward this domain in the normal way */
|
||||
#define SERV_LITERAL_ADDRESS 2 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
|
||||
#define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */
|
||||
#define SERV_4ADDR 8 /* addr is IPv4 */
|
||||
#define SERV_6ADDR 16 /* addr is IPv6 */
|
||||
@@ -1247,7 +1255,7 @@ extern struct daemon {
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
char *workspacename;
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *keyname, *cname; /* MAXDNAME size buffer */
|
||||
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
||||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
@@ -1352,6 +1360,13 @@ void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
unsigned int cache_remove_uid(const unsigned int uid);
|
||||
int cache_recv_insert(time_t now, int fd);
|
||||
#ifdef HAVE_DNSSEC
|
||||
void cache_update_hwm(void);
|
||||
#endif
|
||||
#if defined(HAVE_IPSET) || defined(HAVE_NFTSET)
|
||||
void cache_send_ipset(unsigned char op, struct ipsets *sets,
|
||||
int flags, union all_addr *addr);
|
||||
#endif
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned int flags);
|
||||
void cache_reload(void);
|
||||
@@ -1392,8 +1407,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
unsigned short *typep, unsigned short *classp);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
||||
@@ -1529,7 +1544,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
||||
#ifdef HAVE_DNSSEC
|
||||
void pop_and_retry_query(struct frec *forward, int status, time_t now);
|
||||
int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *n,
|
||||
int class, char *name, char *keyname, struct server *server,
|
||||
int class, char *name, struct server *server,
|
||||
int *keycount, int *validatecount);
|
||||
#endif
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
@@ -1653,7 +1668,7 @@ void send_event(int fd, int event, int data, char *msg);
|
||||
void clear_cache_and_reload(time_t now);
|
||||
#ifdef HAVE_DNSSEC
|
||||
int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header *header,
|
||||
ssize_t *plen, int class, struct server *server, int *keycount, int *validatecount);
|
||||
ssize_t *plen, char *name, int class, struct server *server, int *keycount, int *validatecount);
|
||||
#endif
|
||||
|
||||
/* netlink.c */
|
||||
|
||||
+204
-67
@@ -997,49 +997,57 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
unsigned long ttl;
|
||||
union all_addr a;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
!(p = skip_name(p, header, plen, 4)))
|
||||
return STAT_BOGUS;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DS || qclass != class)
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* A SERVFAIL answer has been seen to a DS query not at start of authority,
|
||||
/* A SERVFAIL answer has been seen to a DS query not at start of authority,
|
||||
so treat it as such and continue to search for a DS or proof of no existence
|
||||
further down the tree. */
|
||||
if (RCODE(header) == SERVFAIL)
|
||||
servfail = neganswer = nons = 1;
|
||||
else
|
||||
{
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl, validate_counter);
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl, validate_counter);
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
!extract_name(header, plen, &p, name, EXTR_NAME_EXTRACT, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DS || qclass != class)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (!servfail)
|
||||
{
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
if (!extract_name(header, plen, &p, name, EXTR_NAME_EXTRACT, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
p += 4; /* qtype, qclass */
|
||||
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
else
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
|
||||
return STAT_BOGUS;
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
{
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!neganswer)
|
||||
@@ -1129,9 +1137,19 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
/* We only cache validated DS records, DNSSECOK flag hijacked
|
||||
to store presence/absence of NS. */
|
||||
if (nons)
|
||||
flags &= ~F_DNSSECOK;
|
||||
{
|
||||
if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Negative DS reply without NS record received for %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
nons = 0;
|
||||
}
|
||||
else
|
||||
/* We only cache validated DS records, DNSSECOK flag hijacked
|
||||
to store presence/absence of NS. */
|
||||
flags &= ~F_DNSSECOK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
/* Use TTL from NSEC for negative cache entries */
|
||||
@@ -1236,6 +1254,7 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
p += 8; /* class, type, TTL */
|
||||
GETSHORT(rdlen, p);
|
||||
psave = p;
|
||||
|
||||
if (!extract_name(header, plen, &p, workspace2, EXTR_NAME_EXTRACT, 0))
|
||||
return DNSSEC_FAIL_BADPACKET;
|
||||
|
||||
@@ -1258,7 +1277,22 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
workspace1--;
|
||||
*workspace1 = '*';
|
||||
}
|
||||
|
||||
|
||||
rdlen -= p - psave;
|
||||
/* rdlen is now length of type map, and p points to it
|
||||
packet checked to be as long as rdlen implies in prove_non_existence() */
|
||||
|
||||
/* check that the first typemap is complete. */
|
||||
if (rdlen < 2 || rdlen < p[1] + 2)
|
||||
return DNSSEC_FAIL_BADPACKET;
|
||||
|
||||
/* RFC 6672 5.3.4.1. */
|
||||
#define DNAME_OFFSET (T_DNAME >> 3)
|
||||
#define DNAME_MASK (0x80 >> (T_DNAME & 0x07))
|
||||
if (p[0] == 0 && (p[1] >= DNAME_OFFSET + 1) && (p[2 + DNAME_OFFSET] & DNAME_MASK) != 0 &&
|
||||
hostname_issubdomain(name, workspace1) == 1)
|
||||
return DNSSEC_FAIL_NONSEC;
|
||||
|
||||
rc = hostname_cmp(workspace1, name);
|
||||
|
||||
if (rc == 0)
|
||||
@@ -1269,16 +1303,12 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
|
||||
/* NSEC with the same name as the RR we're testing, check
|
||||
that the type in question doesn't appear in the type map */
|
||||
rdlen -= p - psave;
|
||||
/* rdlen is now length of type map, and p points to it
|
||||
packet checked to be as long as rdlen implies in prove_non_existence() */
|
||||
|
||||
/* If we can prove that there's no NS record, return that information. */
|
||||
if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) != 0)
|
||||
*nons = 0;
|
||||
|
||||
if (rdlen >= 2 && p[0] == 0)
|
||||
if (p[0] == 0 && p[1] >= 1)
|
||||
{
|
||||
/* If we can prove that there's no NS record, return that information. */
|
||||
if (nons && (p[2] & (0x80 >> T_NS)) != 0)
|
||||
*nons = 0;
|
||||
|
||||
/* A CNAME answer would also be valid, so if there's a CNAME is should
|
||||
have been returned. */
|
||||
if ((p[2] & (0x80 >> T_CNAME)) != 0)
|
||||
@@ -1290,10 +1320,10 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
return DNSSEC_FAIL_NONSEC;
|
||||
}
|
||||
|
||||
while (rdlen >= 2)
|
||||
|
||||
while (rdlen > 0)
|
||||
{
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
if (rdlen < 2 || rdlen < p[1] + 2)
|
||||
return DNSSEC_FAIL_BADPACKET;
|
||||
|
||||
if (p[0] == type >> 8)
|
||||
@@ -1433,7 +1463,11 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
|
||||
p += hash_len; /* skip next-domain hash */
|
||||
rdlen -= p - psave;
|
||||
|
||||
if (rdlen >= 2 && p[0] == 0)
|
||||
/* check that the first typemap is complete. */
|
||||
if (rdlen < 2 || rdlen < p[1] + 2)
|
||||
return DNSSEC_FAIL_BADPACKET;
|
||||
|
||||
if (p[0] == 0 && p[1] >= 1)
|
||||
{
|
||||
/* If we can prove that there's no NS record, return that information. */
|
||||
if (nons && (p[2] & (0x80 >> T_NS)) != 0)
|
||||
@@ -1451,8 +1485,11 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (rdlen >= 2)
|
||||
while (rdlen > 0)
|
||||
{
|
||||
if (rdlen < 2 || rdlen < p[1] + 2)
|
||||
return DNSSEC_FAIL_BADPACKET;
|
||||
|
||||
if (p[0] == type >> 8)
|
||||
{
|
||||
/* Does the NSEC3 say our type exists? */
|
||||
@@ -1924,11 +1961,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
static unsigned char **targets = NULL;
|
||||
static int target_sz = 0;
|
||||
|
||||
unsigned char *ans_start, *p1, *p2;
|
||||
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
int i, j, rc = STAT_INSECURE;
|
||||
unsigned char *ans_start, *p1, *p2, *p3;
|
||||
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx, gotdname;
|
||||
int i, j, k, rc = STAT_INSECURE;
|
||||
int secure = STAT_SECURE;
|
||||
int rc_nsec;
|
||||
unsigned long ttl;
|
||||
|
||||
/* extend rr_status if necessary */
|
||||
if (daemon->rr_status_sz < ntohs(header->ancount) + ntohs(header->nscount))
|
||||
{
|
||||
@@ -1975,27 +2014,119 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* Can't validate an RRSIG query */
|
||||
if (qtype == T_RRSIG)
|
||||
return STAT_INSECURE;
|
||||
|
||||
/* Find CNAME targets. */
|
||||
for (gotdname = i = 0; i < ntohs(header->ancount); i++)
|
||||
{
|
||||
if (!(p1 = skip_name(p1, header, plen, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type1, p1);
|
||||
GETSHORT(class1, p1);
|
||||
p1 += 4; /* TTL */
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
if (type1 == T_DNAME)
|
||||
gotdname = 1;
|
||||
|
||||
if (qtype != T_CNAME && qtype != T_ANY && type1 == T_CNAME && class1 == qclass)
|
||||
{
|
||||
if (!expand_workspace(&targets, &target_sz, targetidx))
|
||||
return STAT_BOGUS;
|
||||
|
||||
targets[targetidx++] = p1; /* pointer to target name */
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (qtype != T_CNAME && qtype != T_ANY)
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
/* A DNAME capable of sythesising a CNAME means we don't need to validate the CNAME,
|
||||
we can just assume that it's valid. RFC 4035 3.2.3 */
|
||||
if (gotdname)
|
||||
for (p1 = ans_start, i = 0; i < ntohs(header->ancount); i++)
|
||||
{
|
||||
if (!(p1 = skip_name(p1, header, plen, 10)))
|
||||
if (!extract_name(header, plen, &p1, name, EXTR_NAME_EXTRACT, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p1);
|
||||
p1 += 6; /* class, TTL */
|
||||
GETSHORT(rdlen2, p1);
|
||||
GETSHORT(type1, p1);
|
||||
GETSHORT(class1, p1);
|
||||
p1 += 4; /* TTL */
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
if (type2 == T_CNAME)
|
||||
if (type1 != T_DNAME)
|
||||
{
|
||||
if (!expand_workspace(&targets, &target_sz, targetidx))
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
|
||||
targets[targetidx++] = p1; /* pointer to target name */
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
else
|
||||
{
|
||||
if (!extract_name(header, plen, &p1, keyname, EXTR_NAME_EXTRACT, 0))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* We now have the name of the DNAME in name, and the target in keyname.
|
||||
Look for any CNAMEs which could have been synthesised from this DNAME
|
||||
and pre-qualify them. */
|
||||
for (p2 = ans_start, j = 0; j < ntohs(header->ancount); j++)
|
||||
{
|
||||
if (!extract_name(header, plen, &p2, daemon->cname, EXTR_NAME_EXTRACT, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p2);
|
||||
GETSHORT(class2, p2);
|
||||
GETLONG(ttl, p2);
|
||||
GETSHORT(rdlen2, p2);
|
||||
|
||||
if (type2 != T_CNAME || class2 != class1)
|
||||
{
|
||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t name_prefix_len = strlen(daemon->cname) - strlen(name);
|
||||
|
||||
if (!extract_name(header, plen, &p2, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* We have the name of the CNAME in daemon->cname, and the target in daemon->workspacename.
|
||||
See if the CNAME was sythesised from the DNAME.
|
||||
CNAME must be <subdomain>.<dname>
|
||||
CNAME target must be <subdomain>.<dname_target>
|
||||
<subdomain>s must match for name and target. */
|
||||
if (hostname_issubdomain(name, daemon->cname) == 1 &&
|
||||
hostname_issubdomain(keyname, daemon->workspacename) == 1 &&
|
||||
name_prefix_len == strlen(daemon->workspacename) - strlen(keyname))
|
||||
{
|
||||
char save = daemon->cname[name_prefix_len];
|
||||
daemon->cname[name_prefix_len] = 0;
|
||||
daemon->workspacename[name_prefix_len] = 0;
|
||||
|
||||
if (hostname_isequal(daemon->cname, daemon->workspacename))
|
||||
{
|
||||
/* pre-qualify this as validated */
|
||||
daemon->rr_status[j] = ttl > 0 ? ttl : 1;
|
||||
|
||||
/* and remove it from the targets we need to have validated answers to. */
|
||||
if (class2 == qclass)
|
||||
{
|
||||
daemon->cname[name_prefix_len] = save;
|
||||
for (k = 0; k <targetidx; k++)
|
||||
if ((p3 = targets[k]))
|
||||
{
|
||||
int rc1;
|
||||
if (!(rc1 = extract_name(header, plen, &p3, daemon->cname, EXTR_NAME_COMPARE, 0)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
if (rc1 == 1)
|
||||
targets[k] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
|
||||
@@ -2014,6 +2145,10 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* Don't try and validate RRSIGs! */
|
||||
if (type1 == T_RRSIG)
|
||||
continue;
|
||||
|
||||
/* Pre-validated by DNAME above don't validate. */
|
||||
if (daemon->rr_status[i] != 0)
|
||||
continue;
|
||||
|
||||
/* Check if we've done this RRset already */
|
||||
for (p2 = ans_start, j = 0; j < i; j++)
|
||||
@@ -2155,7 +2290,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
the answer is in an unsigned zone, or there's NSEC records.
|
||||
For a DS record, we return INSECURE, which almost always turns
|
||||
into BOGUS in the caller. */
|
||||
if ((rc_nsec = prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl, validate_counter)) != 0)
|
||||
{
|
||||
if (rc_nsec & DNSSEC_FAIL_WORK)
|
||||
@@ -2163,7 +2300,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS | rc_nsec;
|
||||
return STAT_INSECURE;
|
||||
|
||||
if ((rc_nsec & (DNSSEC_FAIL_NONSEC | DNSSEC_FAIL_NSEC3_ITERS)) &&
|
||||
!STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
|
||||
|
||||
+30
-32
@@ -20,7 +20,7 @@ static int order(char *qdomain, size_t qlen, struct server *serv);
|
||||
static int order_qsort(const void *a, const void *b);
|
||||
static int order_servers(struct server *s, struct server *s2);
|
||||
|
||||
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
|
||||
/* If the server is USE_RESOLV or LITERAL_ADDRESS, it lives on the local_domains chain. */
|
||||
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
|
||||
|
||||
void build_server_array(void)
|
||||
@@ -94,8 +94,7 @@ void build_server_array(void)
|
||||
server=/.example.com/ works.
|
||||
|
||||
A flag of F_SERVER returns an upstream server only.
|
||||
A flag of F_DNSSECOK returns a DNSSEC capable server only and
|
||||
also disables NODOTS servers from consideration.
|
||||
A flag of F_DNSSECOK disables NODOTS servers from consideration.
|
||||
A flag of F_DOMAINSRV returns a domain-specific server only.
|
||||
A flag of F_CONFIG returns anything that generates a local
|
||||
reply of IPv4 or IPV6.
|
||||
@@ -260,7 +259,6 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return first server in group of equivalent servers; this is the "master" record. */
|
||||
int server_samegroup(struct server *a, struct server *b)
|
||||
{
|
||||
return order_servers(a, b) == 0;
|
||||
@@ -297,11 +295,13 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now the servers are on order between low and high, in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
|
||||
/* Now the matching server records are all between low and high.
|
||||
order_qsort() ensures that they are in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, no-data return,
|
||||
"use resolvconf" servers, domain-specific upstream servers.
|
||||
|
||||
See which of those match our query in that priority order and narrow (low, high) */
|
||||
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||
|
||||
if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
|
||||
@@ -326,33 +326,27 @@ int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* Short to resolv.conf servers */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
/* now look for a NXDOMAIN answer --local=/domain/ */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
if (!(flags & (F_DOMAINSRV | F_SERVER)) && i != nlow)
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
nlow = i;
|
||||
|
||||
/* return "use resolv.conf servers" if they exist */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
/* If we want a server for a particular domain, and this one isn't, return nothing. */
|
||||
if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nlow = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -407,6 +401,8 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
gotname &= ~F_QUERY;
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||
|
||||
@@ -472,7 +468,7 @@ int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
|
||||
/* Find server to send DNSSEC query to. This will normally be the
|
||||
same as for the original query, but may be another if
|
||||
servers for domains are involved. */
|
||||
if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
|
||||
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK, &first, &last))
|
||||
return -1;
|
||||
|
||||
for (index = first; index != last; index++)
|
||||
@@ -546,12 +542,14 @@ static int order_qsort(const void *a, const void *b)
|
||||
rc = order_servers(s1, s2);
|
||||
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
|
||||
so the order is IPv6 literal, IPv4 literal, all-zero literal,
|
||||
unqualified servers, upstream server, NXDOMAIN literal. */
|
||||
in a very specific order IPv6 literal, IPv4 literal, all-zero literal,
|
||||
NXDOMAIN literal. We also include SERV_USE_RESOLV in this, so that
|
||||
use-standard servers sort before ordinary servers. (SERV_USR_RESOLV set
|
||||
implies that none of SERV_LITERAL_ADDRESS,SERV_4ADDR,SERV_6ADDR,SERV_ALL_ZEROS
|
||||
are set) */
|
||||
if (rc == 0)
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV))) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS | SERV_USE_RESOLV)));
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
|
||||
+148
-134
@@ -176,9 +176,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int first, last, start = 0;
|
||||
int forwarded = 0;
|
||||
int ede = EDE_UNSET;
|
||||
unsigned short rrtype;
|
||||
unsigned short rrtype, rrclass;
|
||||
|
||||
gotname = extract_request(header, plen, daemon->namebuff, &rrtype);
|
||||
gotname = extract_request(header, plen, daemon->namebuff, &rrtype, &rrclass);
|
||||
|
||||
/* Check for retry on existing query.
|
||||
FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
|
||||
@@ -192,17 +192,23 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
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, (int)rrclass, (int)rrtype, -1, fwd_flags,
|
||||
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
|
||||
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
|
||||
{
|
||||
struct frec_src *src;
|
||||
struct dns_header *saved_header;
|
||||
unsigned int casediff = 0;
|
||||
unsigned int *bitvector = NULL;
|
||||
unsigned short id = ntohs(header->id); /* Retrieve the id from the new query before we overwrite it. */
|
||||
|
||||
/* Get the case-scambled version of the query to resend. This is important because we
|
||||
may fall through below and forward the query in the packet buffer again and we
|
||||
want to use the same case scrambling as the first time. */
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
for (src = &forward->frec_src; src; src = src->next)
|
||||
if (src->orig_id == ntohs(header->id) &&
|
||||
if (src->orig_id == id &&
|
||||
sockaddr_isequal(&src->source, udpaddr))
|
||||
break;
|
||||
|
||||
@@ -242,7 +248,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
goto reply;
|
||||
}
|
||||
|
||||
/* Find a bitmap of case differences between the query send upstream and this one,
|
||||
/* Find a bitmap of case differences between the query sent upstream and this one,
|
||||
so we can reply to each query with the correct case pattern.
|
||||
Since we need this to get back the exact case pattern of each query when doing
|
||||
query combining, we have to handle the (rare) case that there are case differences
|
||||
@@ -253,9 +259,12 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
we only scramble the first 32 letters for security reasons.
|
||||
|
||||
Note the two names are guaranteed to be the same length and differ only in the case
|
||||
of letters. */
|
||||
if ((saved_header = blockdata_retrieve(forward->stash, forward->stash_len, NULL)) &&
|
||||
extract_request(saved_header, forward->stash_len, daemon->workspacename, NULL))
|
||||
of letters at this point.
|
||||
|
||||
The original query we sent is now in packet buffer and the query name in the
|
||||
new instance is on daemon->namebuff. */
|
||||
|
||||
if (extract_name(header, forward->stash_len, NULL, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||
{
|
||||
unsigned int i, gobig = 0;
|
||||
char *s1, *s2;
|
||||
@@ -284,8 +293,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (gobig && !bitvector)
|
||||
{
|
||||
casediff = (i/BITS_IN_INT) + 1; /* length of array */
|
||||
if ((bitvector = whine_malloc(casediff)))
|
||||
casediff = ((i - 1)/BITS_IN_INT) + 1; /* length of array */
|
||||
/* whine_malloc() zeros memory */
|
||||
if ((bitvector = whine_malloc(casediff * sizeof(unsigned int))))
|
||||
goto big_redo;
|
||||
}
|
||||
}
|
||||
@@ -294,7 +304,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
daemon->free_frec_src = src->next;
|
||||
src->next = forward->frec_src.next;
|
||||
forward->frec_src.next = src;
|
||||
src->orig_id = ntohs(header->id);
|
||||
src->orig_id = id;
|
||||
src->source = *udpaddr;
|
||||
src->dest = *dst_addr;
|
||||
src->log_id = daemon->log_id;
|
||||
@@ -319,8 +329,6 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* new query */
|
||||
if (!forward)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (OPCODE(header) != QUERY)
|
||||
{
|
||||
flags = F_RCODE;
|
||||
@@ -344,8 +352,6 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
master = daemon->serverarray[first];
|
||||
|
||||
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||
if (!flags &&
|
||||
option_bool(OPT_NODOTS_LOCAL) &&
|
||||
@@ -357,7 +363,9 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* Configured answer. */
|
||||
if (flags || ede == EDE_NOT_READY)
|
||||
goto reply;
|
||||
|
||||
|
||||
master = daemon->serverarray[first];
|
||||
|
||||
if (!(forward = get_new_frec(now, master, 0)))
|
||||
goto reply;
|
||||
/* table full - flags == 0, return REFUSED */
|
||||
@@ -365,7 +373,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->flags = fwd_flags;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
plen = add_do_bit(header, plen, ((unsigned char *) header) + daemon->edns_pktsz);
|
||||
|
||||
@@ -380,10 +388,10 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->frec_src.orig_id = ntohs(header->id);
|
||||
forward->new_id = get_id();
|
||||
header->id = ntohs(forward->new_id);
|
||||
|
||||
forward->frec_src.encode_bitmap = option_bool(OPT_NO_0x20) ? 0 : rand32();
|
||||
p = (unsigned char *)(header+1);
|
||||
if (!extract_name(header, plen, &p, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
||||
forward->frec_src.encode_bitmap = (!option_bool(OPT_NO_0x20) && option_bool(OPT_DO_0x20)) ? rand32() : 0;
|
||||
forward->frec_src.encode_bigmap = NULL;
|
||||
|
||||
if (!extract_name(header, plen, NULL, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
||||
goto reply;
|
||||
|
||||
/* Keep copy of query for retries and move to TCP */
|
||||
@@ -448,7 +456,7 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
/* get query for logging. */
|
||||
gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
gotname = extract_request(header, plen, daemon->namebuff, NULL, NULL);
|
||||
|
||||
/* Find suitable servers: should never fail. */
|
||||
if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
|
||||
@@ -696,16 +704,19 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
(void)ad_reqd;
|
||||
(void)do_bit;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
|
||||
#if defined(HAVE_IPSET) || defined(HAVE_NFTSET)
|
||||
if ((daemon->ipsets || daemon->nftsets) && extract_name(header, n, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
{
|
||||
# ifdef HAVE_IPSET
|
||||
ipsets = domain_find_sets(daemon->ipsets, daemon->namebuff);
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_NFTSET
|
||||
nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||
nftsets = domain_find_sets(daemon->nftsets, daemon->namebuff);
|
||||
#endif
|
||||
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
{
|
||||
/* Get extended RCODE. */
|
||||
@@ -779,7 +790,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
||||
else if (!bogusanswer || (header->hb4 & HB4_CD))
|
||||
{
|
||||
if (rcode == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
if (rcode == NXDOMAIN && extract_name(header, n, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0) &&
|
||||
(check_for_local_domain(daemon->namebuff, now) || lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL)))
|
||||
{
|
||||
/* if we forwarded a query for a locally known name (because it was for
|
||||
@@ -793,7 +804,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
if (daemon->doctors && do_doctor(header, n, daemon->namebuff))
|
||||
cache_secure = 0;
|
||||
|
||||
/* check_for_bogus_wildcard() does it's own caching, so
|
||||
/* check_for_bogus_wildcard() does its own caching, so
|
||||
don't call extract_addresses() if it triggers. */
|
||||
if (daemon->bogus_addr && rcode != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
|
||||
@@ -911,22 +922,26 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* Get the query we sent by UDP */
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
|
||||
if (extract_request(header, forward->stash_len, daemon->namebuff, NULL))
|
||||
log_query(F_UPSTREAM | F_NOEXTRA, daemon->namebuff, NULL, "truncated", 0);
|
||||
|
||||
/* Don't count failed UDP attempt AND TCP */
|
||||
if (status != STAT_OK)
|
||||
orig->work_counter++;
|
||||
|
||||
/* NOTE: Can't move connection marks from UDP to TCP */
|
||||
plen = forward->stash_len;
|
||||
status = swap_to_tcp(forward, now, status, header, &plen, forward->class, forward->sentto, &orig->work_counter, &orig->validate_counter);
|
||||
|
||||
/* We forked a new process. pop_and_retry_query() will be called when is completes. */
|
||||
if (STAT_ISEQUAL(status, STAT_ASYNC))
|
||||
if (!extract_name(header, forward->stash_len, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
forward->flags |= FREC_GONE_TO_TCP;
|
||||
return;
|
||||
log_query(F_UPSTREAM | F_NOEXTRA, daemon->namebuff, NULL, "truncated", 0);
|
||||
|
||||
/* Don't count failed UDP attempt AND TCP */
|
||||
if (status != STAT_OK)
|
||||
orig->work_counter++;
|
||||
|
||||
/* NOTE: Can't move connection marks from UDP to TCP */
|
||||
plen = forward->stash_len;
|
||||
status = swap_to_tcp(forward, now, status, header, &plen, daemon->namebuff, forward->class, forward->sentto, &orig->work_counter, &orig->validate_counter);
|
||||
|
||||
/* We forked a new process. pop_and_retry_query() will be called when is completes. */
|
||||
if (STAT_ISEQUAL(status, STAT_ASYNC))
|
||||
{
|
||||
forward->flags |= FREC_GONE_TO_TCP;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -943,8 +958,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
status = dnssec_validate_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, plen, daemon->namebuff, daemon->keyname, &forward->class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL, &orig->validate_counter);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, &orig->validate_counter);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
log_resource = 1;
|
||||
@@ -1031,6 +1045,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
new->flags |= flags;
|
||||
new->forwardall = 0;
|
||||
new->frec_src.encode_bitmap = 0;
|
||||
new->frec_src.encode_bigmap = NULL;
|
||||
|
||||
forward->next_dependent = NULL;
|
||||
new->dependent = forward; /* to find query awaiting new one. */
|
||||
@@ -1082,7 +1097,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
if (log_resource)
|
||||
{
|
||||
/* Log the actual validation that made us barf. */
|
||||
if (extract_request(header, plen, daemon->namebuff, NULL))
|
||||
if (extract_name(header, plen, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
|
||||
daemon->namebuff[0] ? daemon->namebuff : ".");
|
||||
}
|
||||
@@ -1259,14 +1274,13 @@ void reply_query(int fd, time_t now)
|
||||
server->query_latency = server->mma_latency/128;
|
||||
|
||||
/* Flip the bits back in the query name. */
|
||||
p = (unsigned char *)(header+1);
|
||||
if (!extract_name(header, n, &p, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
||||
if (!extract_name(header, n, NULL, (char *)&forward->frec_src.encode_bitmap, EXTR_NAME_FLIP, 1))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
if ((forward->sentto->flags & SERV_DO_DNSSEC) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||
if (!(forward->flags & FREC_CHECKING_DISABLED))
|
||||
{
|
||||
dnssec_validate(forward, header, n, STAT_OK, now);
|
||||
return;
|
||||
@@ -1293,8 +1307,7 @@ static void xor_array(unsigned int *arg1, unsigned int *arg2, unsigned int len)
|
||||
/* Call extract_name() to flip case of query in packet according to the XOR of the bit maps help in arg1 and arg2 */
|
||||
static void flip_queryname(struct dns_header *header, ssize_t len, struct frec_src *arg1, struct frec_src *arg2)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
unsigned int *arg1p, *arg2p, arg1len, arg2len, *swapp, swap;
|
||||
unsigned int *arg1p, *arg2p, arg1len, arg2len;
|
||||
|
||||
/* Two cases: bitmap is single 32 bit int, or it's arbitrary-length array of 32bit ints.
|
||||
The two args may be different and of different lengths.
|
||||
@@ -1313,17 +1326,14 @@ static void flip_queryname(struct dns_header *header, ssize_t len, struct frec_s
|
||||
/* make arg1 the longer, if they differ. */
|
||||
if (arg2len > arg1len)
|
||||
{
|
||||
swap = arg1len;
|
||||
swapp = arg1p;
|
||||
arg1len = arg2len;
|
||||
arg1p = arg2p;
|
||||
arg2len = swap;
|
||||
arg2p = swapp;
|
||||
unsigned int swapl = arg1len, *swapp = arg1p;
|
||||
arg1len = arg2len, arg1p = arg2p;
|
||||
arg2len = swapl, arg2p = swapp;
|
||||
}
|
||||
|
||||
/* XOR on shorter length, flip on longer, operate on longer */
|
||||
xor_array(arg1p, arg2p, arg2len);
|
||||
extract_name(header, len, &p, (char *)arg1p, EXTR_NAME_FLIP, arg1len);
|
||||
extract_name(header, len, NULL, (char *)arg1p, EXTR_NAME_FLIP, arg1len);
|
||||
xor_array(arg1p, arg2p, arg2len); /* restore */
|
||||
}
|
||||
|
||||
@@ -1381,7 +1391,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
|
||||
if (extract_request(header, n, daemon->namebuff, NULL))
|
||||
if (extract_name(header, n, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
@@ -1481,13 +1491,13 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
||||
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
||||
|
||||
/* This gets the name back to the state it was in when we started. */
|
||||
flip_queryname(header, nn, prev, &forward->frec_src);
|
||||
flip_queryname(header, new, prev, &forward->frec_src);
|
||||
|
||||
for (src = &forward->frec_src, prev = NULL; src; prev = src, src = src->next)
|
||||
{
|
||||
/* If you didn't undertand this above, you won't understand it here either. */
|
||||
if (prev)
|
||||
flip_queryname(header, nn, prev, src);
|
||||
flip_queryname(header, new, prev, src);
|
||||
|
||||
if (src->fd != -1 && nn > src->udp_pkt_size)
|
||||
{
|
||||
@@ -1809,14 +1819,14 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
|
||||
if (OPCODE(header) != QUERY)
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, "opcode", &source_addr, "non-query", 0);
|
||||
else if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
||||
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))
|
||||
{
|
||||
#ifdef HAVE_AUTH
|
||||
struct auth_zone *zone;
|
||||
#endif
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&source_addr, auth_dns ? "auth" : "query", type);
|
||||
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0 ) | F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&source_addr, NULL, type);
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* Find queries for zones we're authoritative for, and answer them directly.
|
||||
@@ -2118,7 +2128,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
|
||||
/* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket
|
||||
and wish to abort if the whole data is not read/written within the timeout. */
|
||||
if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) ||
|
||||
if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) ||
|
||||
!read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) ||
|
||||
!read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE))
|
||||
{
|
||||
@@ -2134,7 +2144,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
else
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
/* If the question section of the reply doesn't match the question we sent, then
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers.
|
||||
@@ -2164,14 +2174,13 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
returned truncated. (Which type held in status).
|
||||
Resend the query (in header) via TCP */
|
||||
int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *plenp,
|
||||
int class, char *name, char *keyname, struct server *server,
|
||||
int class, char *name, struct server *server,
|
||||
int *keycount, int *validatecount)
|
||||
{
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
struct dns_header *new_header = (struct dns_header *)&packet[2];
|
||||
int start, first, last, new_status;
|
||||
ssize_t n = *plenp;
|
||||
int have_req = extract_request(header, n, keyname, NULL);
|
||||
int log_save = daemon->log_display_id;
|
||||
|
||||
*plenp = 0;
|
||||
@@ -2188,48 +2197,48 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
first = start = server->arrayposn;
|
||||
last = first + 1;
|
||||
|
||||
if (!STAT_ISEQUAL(status, STAT_OK) && (!have_req || (start = dnssec_server(server, keyname, &first, &last)) == -1))
|
||||
new_status = STAT_ABANDONED;
|
||||
else if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0)
|
||||
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, &first, &last)) == -1)
|
||||
new_status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
if (have_req)
|
||||
{
|
||||
if (STAT_ISEQUAL(status, STAT_OK))
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, keyname, &server->addr, NULL, 0);
|
||||
else
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, keyname, &server->addr,
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||
}
|
||||
|
||||
new_status = tcp_key_recurse(now, status, new_header, n, class, name, keyname, server, 0, 0, keycount, validatecount);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_OK))
|
||||
{
|
||||
/* downstream query: strip DNSSSEC RRs and see if it will
|
||||
fit in a UDP reply. */
|
||||
rrfilter(new_header, (size_t *)&n, RRFILTER_DNSSEC);
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, name, &server->addr, NULL, 0);
|
||||
else
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||
|
||||
if (n >= daemon->edns_pktsz)
|
||||
if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0)
|
||||
new_status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_OK))
|
||||
{
|
||||
/* still too bIg, strip optional sections and try again. */
|
||||
new_header->nscount = htons(0);
|
||||
new_header->arcount = htons(0);
|
||||
n = resize_packet(new_header, n, NULL, 0);
|
||||
/* downstream query: strip DNSSSEC RRs and see if it will
|
||||
fit in a UDP reply. */
|
||||
rrfilter(new_header, (size_t *)&n, RRFILTER_DNSSEC);
|
||||
|
||||
if (n >= daemon->edns_pktsz)
|
||||
{
|
||||
/* truncating the packet will break the answers, so remove them too
|
||||
and mark the reply as truncated. */
|
||||
new_header->ancount = htons(0);
|
||||
/* still too bIg, strip optional sections and try again. */
|
||||
new_header->nscount = htons(0);
|
||||
new_header->arcount = htons(0);
|
||||
n = resize_packet(new_header, n, NULL, 0);
|
||||
new_status = STAT_TRUNCATED;
|
||||
if (n >= daemon->edns_pktsz)
|
||||
{
|
||||
/* truncating the packet will break the answers, so remove them too
|
||||
and mark the reply as truncated. */
|
||||
new_header->ancount = htons(0);
|
||||
n = resize_packet(new_header, n, NULL, 0);
|
||||
new_status = STAT_TRUNCATED;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the stripped or truncated reply. */
|
||||
memcpy(header, new_header, n);
|
||||
*plenp = n;
|
||||
}
|
||||
|
||||
/* return the stripped or truncated reply. */
|
||||
memcpy(header, new_header, n);
|
||||
*plenp = n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2259,8 +2268,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class, validatecount);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL, validatecount);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, validatecount);
|
||||
|
||||
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY) && !STAT_ISEQUAL(new_status, STAT_ABANDONED))
|
||||
break;
|
||||
@@ -2274,7 +2282,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
if (STAT_ISEQUAL(new_status, STAT_ABANDONED))
|
||||
{
|
||||
/* Log the actual validation that made us barf. */
|
||||
if (extract_request(header, n, daemon->namebuff, NULL))
|
||||
if (extract_name(header, n, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
my_syslog(LOG_WARNING, _("validation of %s failed: resource limit exceeded."),
|
||||
daemon->namebuff[0] ? daemon->namebuff : ".");
|
||||
break;
|
||||
@@ -2454,23 +2462,37 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
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;
|
||||
flags = F_RCODE;
|
||||
}
|
||||
else if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
else if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype, NULL)))
|
||||
ede = EDE_INVALID_DATA;
|
||||
else
|
||||
{
|
||||
if (saved_question)
|
||||
blockdata_free(saved_question);
|
||||
|
||||
do_bit = 0;
|
||||
|
||||
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
||||
{
|
||||
unsigned short ede_flags;
|
||||
|
||||
have_pseudoheader = 1;
|
||||
pheader += 4; /* udp_size, ext_rcode */
|
||||
GETSHORT(ede_flags, pheader);
|
||||
|
||||
if (ede_flags & 0x8000)
|
||||
do_bit = 1; /* do bit */
|
||||
}
|
||||
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
|
||||
saved_question = blockdata_alloc((char *)header, (size_t)size);
|
||||
saved_size = size;
|
||||
|
||||
log_query_mysockaddr(F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, auth_dns ? "auth" : "query", qtype);
|
||||
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, NULL, qtype);
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* Find queries for zones we're authoritative for, and answer them directly.
|
||||
@@ -2503,20 +2525,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
else
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
do_bit = 0;
|
||||
|
||||
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
||||
{
|
||||
unsigned short ede_flags;
|
||||
|
||||
have_pseudoheader = 1;
|
||||
pheader += 4; /* udp_size, ext_rcode */
|
||||
GETSHORT(ede_flags, pheader);
|
||||
|
||||
if (ede_flags & 0x8000)
|
||||
do_bit = 1; /* do bit */
|
||||
}
|
||||
|
||||
ad_reqd = do_bit;
|
||||
/* RFC 6840 5.7 */
|
||||
if (header->hb4 & HB4_AD)
|
||||
@@ -2586,7 +2594,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
start = master->last_server;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
|
||||
@@ -2603,7 +2611,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
else
|
||||
{
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
if (!extract_name(header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||
|
||||
@@ -2615,7 +2623,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (checking_disabled || (header->hb4 & HB4_CD))
|
||||
no_cache_dnssec = 1;
|
||||
else if (master->flags & SERV_DO_DNSSEC)
|
||||
else
|
||||
{
|
||||
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];
|
||||
@@ -2645,7 +2653,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
|
||||
if (extract_request(header, m, daemon->namebuff, NULL))
|
||||
if (extract_name(header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
@@ -3033,7 +3041,7 @@ static void free_frec(struct frec *f)
|
||||
struct frec_src *last;
|
||||
|
||||
/* add back to freelist if not the record builtin to every frec,
|
||||
also free any bigmaps they's been decorated with. */
|
||||
also free any bigmaps they've been decorated with. */
|
||||
for (last = f->frec_src.next; last && last->next; last = last->next)
|
||||
if (last->encode_bigmap)
|
||||
{
|
||||
@@ -3043,6 +3051,12 @@ static void free_frec(struct frec *f)
|
||||
|
||||
if (last)
|
||||
{
|
||||
/* final link in the chain loses bigmap too. */
|
||||
if (last->encode_bigmap)
|
||||
{
|
||||
free(last->encode_bigmap);
|
||||
last->encode_bigmap = NULL;
|
||||
}
|
||||
last->next = daemon->free_frec_src;
|
||||
daemon->free_frec_src = f->frec_src.next;
|
||||
}
|
||||
@@ -3182,12 +3196,12 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int
|
||||
struct dns_header *header;
|
||||
int compare_mode = EXTR_NAME_COMPARE;
|
||||
|
||||
/* Only compare case-sensitive when matching frec to a recieved answer,
|
||||
/* Only compare case-sensitive when matching frec to a received answer,
|
||||
NOT when looking for a duplicated question. */
|
||||
if (flags & FREC_ANSWER)
|
||||
{
|
||||
flags &= ~FREC_ANSWER;
|
||||
if (!option_bool(OPT_NO_0x20))
|
||||
if (!option_bool(OPT_NO_0x20) && option_bool(OPT_DO_0x20))
|
||||
compare_mode = EXTR_NAME_NOCASE;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
|
||||
#if defined(HAVE_IPSET)
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
+2
-33
@@ -1379,7 +1379,7 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
|
||||
/* cannot set source _port_ for TCP connections. */
|
||||
if (is_tcp)
|
||||
port = 0;
|
||||
else if (port == 0 && daemon->max_port != 0)
|
||||
else if (port == 0 && daemon->max_port != 0 && daemon->max_port >= daemon->min_port)
|
||||
{
|
||||
/* Bind a random port within the range given by min-port and max-port if either
|
||||
or both are set. Otherwise use the OS's random ephemeral port allocation by
|
||||
@@ -1587,33 +1587,6 @@ void check_servers(int no_loop_check)
|
||||
|
||||
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
if (!(serv->flags & SERV_FOR_NODOTS))
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
if (strlen(serv->domain) != 0)
|
||||
{
|
||||
struct ds_config *ds;
|
||||
char *domain = serv->domain;
|
||||
|
||||
/* .example.com is valid */
|
||||
while (*domain == '.')
|
||||
domain++;
|
||||
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
|
||||
break;
|
||||
|
||||
if (!ds)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
port = prettyprint_addr(&serv->addr, daemon->namebuff);
|
||||
|
||||
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
|
||||
@@ -1659,10 +1632,6 @@ void check_servers(int no_loop_check)
|
||||
{
|
||||
char *s1, *s2, *s3 = "", *s4 = "";
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
|
||||
s3 = _("(no DNSSEC)");
|
||||
#endif
|
||||
if (serv->flags & SERV_FOR_NODOTS)
|
||||
s1 = _("unqualified"), s2 = _("names");
|
||||
else if (strlen(serv->domain) == 0)
|
||||
@@ -1696,7 +1665,7 @@ void check_servers(int no_loop_check)
|
||||
if (++locals <= LOCALS_LOGGED)
|
||||
my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain);
|
||||
}
|
||||
else if (serv->flags & SERV_USE_RESOLV)
|
||||
else if (serv->flags & SERV_USE_RESOLV && serv->domain_len != 0)
|
||||
my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined (HAVE_NFTSET) && defined (HAVE_LINUX_NETWORK)
|
||||
#if defined (HAVE_NFTSET)
|
||||
|
||||
#include <nftables/libnftables.h>
|
||||
|
||||
|
||||
+46
-29
@@ -194,6 +194,7 @@ struct myoption {
|
||||
#define LOPT_DNSSEC_LIMITS 385
|
||||
#define LOPT_PXE_OPT 386
|
||||
#define LOPT_NO_ENCODE 387
|
||||
#define LOPT_DO_ENCODE 388
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -249,6 +250,7 @@ static const struct myoption opts[] =
|
||||
{ "no-negcache", 0, 0, 'N' },
|
||||
{ "no-round-robin", 0, 0, LOPT_NORR },
|
||||
{ "no-0x20-encode", 0, 0, LOPT_NO_ENCODE },
|
||||
{ "do-0x20-encode", 0, 0, LOPT_DO_ENCODE },
|
||||
{ "cache-rr", 1, 0, LOPT_CACHE_RR },
|
||||
{ "addn-hosts", 1, 0, 'H' },
|
||||
{ "hostsdir", 1, 0, LOPT_HOST_INOTIFY },
|
||||
@@ -594,6 +596,7 @@ static struct {
|
||||
{ LOPT_QUIET_TFTP, OPT_QUIET_TFTP, NULL, gettext_noop("Do not log routine TFTP."), NULL },
|
||||
{ LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL },
|
||||
{ LOPT_NO_ENCODE, OPT_NO_0x20, NULL, gettext_noop("Suppress DNS bit 0x20 encoding."), NULL },
|
||||
{ LOPT_DO_ENCODE, OPT_DO_0x20, NULL, gettext_noop("Enable DNS bit 0x20 encoding."), NULL },
|
||||
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
||||
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
||||
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
||||
@@ -958,7 +961,7 @@ char *parse_server(char *arg, struct server_details *sdetails)
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
|
||||
/* Get addresses suitable for sending datagrams. We assume that we can use the
|
||||
same addresses for TCP connections. Settting this to zero gets each address
|
||||
same addresses for TCP connections. Setting this to zero gets each address
|
||||
threes times, for SOCK_STREAM, SOCK_RAW and SOCK_DGRAM, which is not useful. */
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
@@ -2672,15 +2675,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (msize > 128)
|
||||
ret_err_free(_("bad prefix length"), new);
|
||||
|
||||
mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
/* prefix==64 overflows the mask calculation */
|
||||
if (msize <= 64)
|
||||
mask = (u64)-1LL;
|
||||
else
|
||||
mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
|
||||
new->is6 = 1;
|
||||
new->prefixlen = msize;
|
||||
|
||||
/* prefix==64 overflows the mask calculation above */
|
||||
if (msize <= 64)
|
||||
mask = (u64)-1LL;
|
||||
|
||||
new->end6 = new->start6;
|
||||
setaddr6part(&new->start6, addrpart & ~mask);
|
||||
setaddr6part(&new->end6, addrpart | mask);
|
||||
@@ -3432,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_LOG_PROTO);
|
||||
}
|
||||
else if (strcmp(arg, "auth") == 0)
|
||||
set_option_bool(OPT_AUTH_LOG);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3984,7 +3989,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
while (arg)
|
||||
{
|
||||
comma = split(arg);
|
||||
if (strchr(arg, ':')) /* ethernet address, netid or binary CLID */
|
||||
if (strchr(arg, ':')) /* Ethernet address, netid or binary CLID */
|
||||
{
|
||||
if ((arg[0] == 'i' || arg[0] == 'I') &&
|
||||
(arg[1] == 'd' || arg[1] == 'D') &&
|
||||
@@ -5334,7 +5339,8 @@ err:
|
||||
|
||||
new->class = C_IN;
|
||||
new->name = NULL;
|
||||
|
||||
new->digestlen = 0;
|
||||
|
||||
if ((comma = split(arg)) && (algo = split(comma)))
|
||||
{
|
||||
int class = 0;
|
||||
@@ -5352,29 +5358,37 @@ err:
|
||||
algo = split(comma);
|
||||
}
|
||||
}
|
||||
|
||||
if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
|
||||
!atoi_check16(comma, &new->keytag) ||
|
||||
!atoi_check8(algo, &new->algo) ||
|
||||
!atoi_check8(digest, &new->digest_type) ||
|
||||
!(new->name = canonicalise_opt(arg)))
|
||||
|
||||
if (!(new->name = canonicalise_opt(arg)))
|
||||
ret_err_free(_("bad trust anchor"), new);
|
||||
|
||||
/* Upper bound on length */
|
||||
len = (2*strlen(keyhex))+1;
|
||||
new->digest = opt_malloc(len);
|
||||
unhide_metas(keyhex);
|
||||
/* 4034: "Whitespace is allowed within digits" */
|
||||
for (cp = keyhex; *cp; )
|
||||
if (isspace((unsigned char)*cp))
|
||||
for (cp1 = cp; *cp1; cp1++)
|
||||
*cp1 = *(cp1+1);
|
||||
else
|
||||
cp++;
|
||||
if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
|
||||
|
||||
if (comma)
|
||||
{
|
||||
free(new->name);
|
||||
ret_err_free(_("bad HEX in trust anchor"), new);
|
||||
if (!algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
|
||||
!atoi_check16(comma, &new->keytag) ||
|
||||
!atoi_check8(algo, &new->algo) ||
|
||||
!atoi_check8(digest, &new->digest_type))
|
||||
{
|
||||
free(new->name);
|
||||
ret_err_free(_("bad trust anchor"), new);
|
||||
}
|
||||
|
||||
/* Upper bound on length */
|
||||
len = (2*strlen(keyhex))+1;
|
||||
new->digest = opt_malloc(len);
|
||||
unhide_metas(keyhex);
|
||||
/* 4034: "Whitespace is allowed within digits" */
|
||||
for (cp = keyhex; *cp; )
|
||||
if (isspace((unsigned char)*cp))
|
||||
for (cp1 = cp; *cp1; cp1++)
|
||||
*cp1 = *(cp1+1);
|
||||
else
|
||||
cp++;
|
||||
if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
|
||||
{
|
||||
free(new->name);
|
||||
ret_err_free(_("bad HEX in trust anchor"), new);
|
||||
}
|
||||
}
|
||||
|
||||
new->next = daemon->ds;
|
||||
@@ -5923,6 +5937,9 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->randport_limit = 1;
|
||||
daemon->host_index = SRC_AH;
|
||||
daemon->max_procs = MAX_PROCS;
|
||||
#ifdef HAVE_DUMPFILE
|
||||
daemon->dump_mask = 0xffffffff;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
daemon->limit[LIMIT_SIG_FAIL] = DNSSEC_LIMIT_SIG_FAIL;
|
||||
daemon->limit[LIMIT_CRYPTO] = DNSSEC_LIMIT_CRYPTO;
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ void poll_listen(int fd, short event)
|
||||
{
|
||||
if (arrsize == nfds)
|
||||
{
|
||||
/* Array too small, extend. */
|
||||
/* Array too small. Extend. */
|
||||
struct pollfd *new;
|
||||
|
||||
arrsize = (arrsize == 0) ? 64 : arrsize * 2;
|
||||
|
||||
+3
-3
@@ -411,7 +411,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
|
||||
if (!old_prefix && !parm.found_context)
|
||||
return;
|
||||
|
||||
/* If we're sending router address instead of prefix in at least on prefix,
|
||||
/* If we're sending router address instead of prefix in at least one prefix,
|
||||
include the advertisement interval option. */
|
||||
if (parm.adv_router)
|
||||
{
|
||||
@@ -825,10 +825,10 @@ time_t periodic_ra(time_t now)
|
||||
}
|
||||
else if (iface_enumerate(AF_INET6, ¶m, (callback_t){.af_inet6=iface_search}))
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
associated with it, because it's for a subnet we don't
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satisfy it. */
|
||||
ever be able to send RAs to satisfy it. */
|
||||
context->ra_time = 0;
|
||||
|
||||
if (param.iface != 0 &&
|
||||
|
||||
+97
-67
@@ -29,16 +29,19 @@
|
||||
return = 1 -> extract OK, compare OK, flip OK
|
||||
return = 2 -> extract OK, compare failed.
|
||||
return = 3 -> extract OK, compare failed but only on case.
|
||||
|
||||
If pp == NULL, operate on the query name in the packet.
|
||||
*/
|
||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int func, unsigned int parm)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
unsigned char *cp = (unsigned char *)name, *p1 = NULL;
|
||||
unsigned int j, l, namelen = 0, hops = 0;
|
||||
unsigned int bigmap_counter = 0, bigmap_posn = 0, bigmap_size, bitmap;
|
||||
unsigned int bigmap_counter = 0, bigmap_posn = 0, bigmap_size = parm, bitmap = 0;
|
||||
int retvalue = 1, case_insens = 1, isExtract = 0, flip = 0, extrabytes = (int)parm;
|
||||
unsigned int *bigmap;
|
||||
|
||||
unsigned int *bigmap = (unsigned int *)name;
|
||||
unsigned char *p = pp ? *pp : (unsigned char *)(header+1);
|
||||
|
||||
if (func == EXTR_NAME_EXTRACT)
|
||||
isExtract = 1, *cp = 0;
|
||||
else if (func == EXTR_NAME_NOCASE)
|
||||
@@ -46,9 +49,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
else if (func == EXTR_NAME_FLIP)
|
||||
{
|
||||
flip = 1, extrabytes = 0;
|
||||
bigmap = (unsigned int *)name;
|
||||
name = NULL;
|
||||
bigmap_size = parm;
|
||||
}
|
||||
|
||||
while (1)
|
||||
@@ -73,11 +74,14 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
}
|
||||
else if (!flip && *cp != 0)
|
||||
retvalue = 2;
|
||||
|
||||
if (p1) /* we jumped via compression */
|
||||
*pp = p1;
|
||||
else
|
||||
*pp = p;
|
||||
|
||||
if (pp)
|
||||
{
|
||||
if (p1) /* we jumped via compression */
|
||||
*pp = p1;
|
||||
else
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
return retvalue;
|
||||
}
|
||||
@@ -530,9 +534,6 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
||||
if (substring)
|
||||
*substring = name_len;
|
||||
|
||||
if (ttlp)
|
||||
*ttlp = daemon->neg_ttl;
|
||||
|
||||
for (i = 0; i < ntohs(header->nscount); i++)
|
||||
{
|
||||
if (!extract_name(header, qlen, &p, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||
@@ -592,18 +593,18 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
|
||||
}
|
||||
|
||||
/* rest of RR */
|
||||
if (!no_cache && !blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
|
||||
{
|
||||
blockdata_free(addr.rrblock.rrdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr.rrblock.datalen += 20;
|
||||
|
||||
if (!no_cache)
|
||||
{
|
||||
int secflag = 0;
|
||||
|
||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
|
||||
{
|
||||
blockdata_free(addr.rrblock.rrdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr.rrblock.datalen += 20;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[i + ntohs(header->ancount)] != 0)
|
||||
{
|
||||
@@ -808,21 +809,32 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
if (!found)
|
||||
{
|
||||
/* For reverse records, we use the name field to store the SOA name. */
|
||||
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
||||
|
||||
flags |= F_NEG | (secure ? F_DNSSECOK : 0);
|
||||
if (name_encoding && ttl)
|
||||
{
|
||||
flags |= F_REVERSE | name_encoding;
|
||||
if (!have_soa)
|
||||
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||
cache_insert(name + substring, &addr, C_IN, now, ttl, flags);
|
||||
}
|
||||
|
||||
|
||||
if (name_encoding)
|
||||
flags |= F_REVERSE | name_encoding;
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, &addr, NULL, 0);
|
||||
|
||||
if (name_encoding && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
/* For reverse records, we use the name field to store the SOA name. */
|
||||
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
||||
|
||||
if (have_soa || daemon->neg_ttl)
|
||||
{
|
||||
/* If daemon->neg_ttl is set, we can cache even without an SOA. */
|
||||
if (!have_soa)
|
||||
{
|
||||
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||
ttl = daemon->neg_ttl;
|
||||
}
|
||||
|
||||
cache_insert(name + substring, &addr, C_IN, now, ttl, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1045,19 +1057,34 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
private_net6(&addr.addr6, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
{
|
||||
/* If we're a child process, send this to the parent,
|
||||
since the ipset and nfset access is not re-entrant. */
|
||||
#ifdef HAVE_IPSET
|
||||
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
for (ipsets_cur = ipsets->sets; *ipsets_cur; ipsets_cur++)
|
||||
if (add_to_ipset(*ipsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, ipsets->domain, &addr, *ipsets_cur, 1);
|
||||
if (ipsets)
|
||||
{
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
cache_send_ipset(PIPE_OP_IPSET, ipsets, flags, &addr);
|
||||
else
|
||||
for (ipsets_cur = ipsets->sets; *ipsets_cur; ipsets_cur++)
|
||||
if (add_to_ipset(*ipsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, ipsets->domain, &addr, *ipsets_cur, 1);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NFTSET
|
||||
if (nftsets && (flags & (F_IPV4 | F_IPV6)))
|
||||
for (nftsets_cur = nftsets->sets; *nftsets_cur; nftsets_cur++)
|
||||
if (add_to_nftset(*nftsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, nftsets->domain, &addr, *nftsets_cur, 0);
|
||||
if (nftsets)
|
||||
{
|
||||
if (daemon->pipe_to_parent != -1)
|
||||
cache_send_ipset(PIPE_OP_NFTSET, nftsets, flags, &addr);
|
||||
else
|
||||
for (nftsets_cur = nftsets->sets; *nftsets_cur; nftsets_cur++)
|
||||
if (add_to_nftset(*nftsets_cur, &addr, flags, 0) == 0)
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, nftsets->domain, &addr, *nftsets_cur, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (insert)
|
||||
@@ -1110,26 +1137,27 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
||||
|
||||
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
if (!ttl)
|
||||
ttl = cttl;
|
||||
|
||||
addr.rrdata.datalen = substring;
|
||||
addr.rrdata.rrtype = qtype;
|
||||
|
||||
if (!have_soa)
|
||||
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||
}
|
||||
|
||||
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
if (have_soa || daemon->neg_ttl)
|
||||
{
|
||||
if (have_soa)
|
||||
{
|
||||
addr.rrdata.datalen = substring;
|
||||
addr.rrdata.rrtype = qtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If daemon->neg_ttl is set, we can cache even without an SOA. */
|
||||
ttl = daemon->neg_ttl;
|
||||
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||
}
|
||||
|
||||
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1234,7 +1262,8 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark)
|
||||
|
||||
/* If the packet holds exactly one query
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
unsigned short *typep, unsigned short *classp)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass;
|
||||
@@ -1259,6 +1288,9 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
if (typep)
|
||||
*typep = qtype;
|
||||
|
||||
if (classp)
|
||||
*classp = qclass;
|
||||
|
||||
if (qclass == C_IN)
|
||||
{
|
||||
if (qtype == T_A)
|
||||
@@ -1270,9 +1302,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* F_DNSSECOK as agument to search_servers() inhibits forwarding
|
||||
to servers for domains without a trust anchor. This make the
|
||||
behaviour for DS and DNSKEY queries we forward the same
|
||||
/* Make the behaviour for DS and DNSKEY queries we forward the same
|
||||
as for DS and DNSKEY queries we originate. */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY))
|
||||
return F_DNSSECOK;
|
||||
|
||||
+1
-1
@@ -1345,7 +1345,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else if (!lease && (ltmp = lease_find_by_addr(mess->yiaddr)))
|
||||
{
|
||||
/* If a host is configured with more than one MAC address, it's OK to 'nix
|
||||
a lease from one of it's MACs to give the address to another. */
|
||||
a lease from one of its MACs to give the address to another. */
|
||||
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
|
||||
{
|
||||
inet_ntop(AF_INET, <mp->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
+2
-2
@@ -377,7 +377,7 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new)
|
||||
int to_wire(char *name)
|
||||
{
|
||||
unsigned char *l, *p, *q, term;
|
||||
int len;
|
||||
unsigned int len;
|
||||
|
||||
for (l = (unsigned char*)name; *l != 0; l = p)
|
||||
{
|
||||
@@ -409,7 +409,7 @@ int to_wire(char *name)
|
||||
void from_wire(char *name)
|
||||
{
|
||||
unsigned char *l, *p, *last;
|
||||
int len;
|
||||
unsigned int len;
|
||||
|
||||
for (last = (unsigned char *)name; *last != 0; last += *last+1);
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
else if (lease->clid_len == 9 &&
|
||||
lease->clid[0] == ARPHRD_EUI64 &&
|
||||
lease->hwaddr_type == ARPHRD_IEEE1394)
|
||||
/* firewire has EUI-64 identifier as clid */
|
||||
/* FireWire has EUI-64 identifier as clid */
|
||||
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
|
||||
#endif
|
||||
else
|
||||
|
||||
+10
-9
@@ -274,7 +274,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
/* Enforce simultaneous transfer limit. In non-single-port mode
|
||||
this is doene by not listening on the server socket when
|
||||
this is done by not listening on the server socket when
|
||||
too many transfers are in progress. */
|
||||
if (!transfer && tftp_cnt >= daemon->tftp_max)
|
||||
return;
|
||||
@@ -360,7 +360,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
p = packet + 2;
|
||||
end = packet + 2 + len;
|
||||
end = packet + len;
|
||||
|
||||
if (ntohs(*((unsigned short *)packet)) != OP_RRQ ||
|
||||
!(filename = next(&p, end)) ||
|
||||
@@ -742,15 +742,16 @@ static void free_transfer(struct tftp_transfer *transfer)
|
||||
|
||||
static char *next(char **p, char *end)
|
||||
{
|
||||
char *ret = *p;
|
||||
size_t len;
|
||||
char *n, *ret = *p;
|
||||
|
||||
/* Look for end of string, without running off the end of the packet. */
|
||||
for (n = *p; n < end && *n != 0; n++);
|
||||
|
||||
if (*(end-1) != 0 ||
|
||||
*p == end ||
|
||||
(len = strlen(ret)) == 0)
|
||||
/* ran off the end or zero length string - failed */
|
||||
if (n == end || n == ret)
|
||||
return NULL;
|
||||
|
||||
*p += len + 1;
|
||||
|
||||
*p = n + 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -426,7 +426,7 @@ int hostname_order(const char *a, const char *b)
|
||||
|
||||
int hostname_isequal(const char *a, const char *b)
|
||||
{
|
||||
return hostname_order(a, b) == 0;
|
||||
return strlen(a) == strlen(b) && hostname_order(a, b) == 0;
|
||||
}
|
||||
|
||||
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
|
||||
|
||||
Reference in new issue
Block a user