Compare commits

...

116 Commits

Author SHA1 Message Date
Simon Kelley
94b6878821 Tidy crypto.c of old library compat. Now need libnettle 3. 2018-03-17 18:39:23 +00:00
Simon Kelley
8b96552f0d Fix compiler warning. 2018-03-10 20:44:17 +00:00
Simon Kelley
ae290659de Fix debian/changelog syntax. 2018-03-10 20:28:32 +00:00
Simon Kelley
6b2b564ac3 Enhance --synth-domain to allow names with sequential integers. 2018-03-10 20:25:57 +00:00
Simon Kelley
4f7bb57e97 Fix deletion of dhcp-options from inotify dynamic files.
These were not deleted except in the case that a dhcp-optsfile
option was coincidentally provided.
2018-03-08 18:47:08 +00:00
Petr Menšík
56f0623930 Allow trailing dot in CNAME.
I got reported bug in Fedora [1], that cname is broken in new releases.
At first I though this was false report, but there is still new
regression in cname handling.

Before, it accepted alias with trailing dot. Not it would accept only
target, but not alias.

cname=alias.,target

is no longer valid. The issue is it will count size to skip after
canonicalize. If that ignores trailing dot, next name would be "". And
that is invalid and refused, dnsmasq refuses to start.

I also think that any whitespace like tab should be possible after
comma. So this fixes also 30858e3b9b.
2018-03-06 23:13:32 +00:00
Simon Kelley
f3223fbff6 Fix nettle_hash() function to avoid ABI incompatibilities.
The way of accessing the list of available hashes on nettle was
vulnerable to breaking if the version of libnettle in use was
different to the version dnsmasq was compiled against.
Change to a new system if libnettle >= 3.4 is in use.
Older versions if nettle are still OK, once 3.4 is reached,
the ABi problem is fixed. Thanks to Petr Menšík for clues on this.
2018-03-06 22:55:36 +00:00
Simon Kelley
4c4f4c2649 Debian dependency tweaking for new dnsmasq-base-lua package. 2018-02-16 22:43:29 +00:00
Ville Skyttä
773af304ea Man page typo fix. 2018-02-16 21:47:55 +00:00
Simon Kelley
4cc944b0d6 Merge branch 'master' of ssh://thekelleys.org.uk/var/local/git/dnsmasq 2018-02-16 21:30:21 +00:00
Simon Kelley
87e00feb01 Compiler warning fixes. 2018-02-16 21:29:32 +00:00
Simon Kelley
e7a4af8903 Compiler warning fixes. 2018-02-16 21:27:35 +00:00
Simon Kelley
2d69d6146d Add liblua-dev to Debian build-depends. 2018-02-16 21:11:17 +00:00
Simon Kelley
30e4a9441e Debian package: add dnsmasq-base-lua binary package. 2018-02-16 19:56:56 +00:00
Simon Kelley
232a8f3569 Merge messages for release. 2018-02-14 23:02:34 +00:00
Simon Kelley
1721453d51 Remove special handling of A-for-A queries. 2018-02-14 22:56:09 +00:00
yiwenchen
499d8dde2b Fix boundary for test introduced in 3e3f1029c9ec6c63e430ff51063a6301d4b2262
This fixes breakage of  DHCPv6 relay.
2018-02-14 22:26:54 +00:00
Andy Hawkins
6f1cbfd000 Fix debian/readme typo. 2018-02-14 21:35:56 +00:00
Andy Hawkins
55ecde7f1b Inotify: Ignore backup files created by editors
Use strlen to determine the length of the filename returned by
inotify, as in->len refers to the length of the buffer containing
the name, not the length of the name itself.

http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2018q1/011950.html

Signed-off-by: Andy Hawkins <andy@gently.org.uk>

Patch further modified by simon@thekelleys.org to avoid
out-of-bounds array access with an empty string, call strlen once,
and reverse order of filename verifcation and resolv-file test.
2018-02-14 18:36:47 +00:00
Simon Kelley
6b54d69a85 Make failure to chown() pidfile a warning. 2018-02-08 21:32:16 +00:00
Simon Kelley
246a31cd73 Change ownership of pid file, to keep systemd happy. 2018-02-06 17:27:55 +00:00
Simon Kelley
83e4b73596 Remove confusion between --user and --script-user. 2018-02-06 16:57:15 +00:00
Simon Kelley
6340ca734f Tweak heuristic for initial DNSSEC memory allocation. 2018-01-30 21:39:01 +00:00
Simon Kelley
baf553db0c Default min-port to 1024 to avoid reserved ports. 2018-01-29 23:04:06 +00:00
Kurt H Maier
486bcd5a7b Simplify and correct bindtodevice(). 2018-01-26 15:10:59 +00:00
Simon Kelley
be9a74d2f8 Close Debian bug for CVE-2017-15107. 2018-01-26 14:36:32 +00:00
Leon M. George
ffcbc0f011 Example config typo fixes. 2018-01-26 13:17:41 +00:00
Simon Kelley
a969ba6e2a Special case NSEC processing for root DS record, to avoid spurious BOGUS. 2018-01-20 23:08:38 +00:00
Simon Kelley
f1781728af Add homepage to Debian control file. 2018-01-20 22:18:54 +00:00
Simon Kelley
cd7df612b1 Fix DNSSEC validation errors introduced in 4fe6744a22 2018-01-20 00:10:55 +00:00
Simon Kelley
c1a4e257a3 Try to be a little more clever at falling back to smaller DNS packet sizes. 2018-01-19 22:00:05 +00:00
Simon Kelley
4fe6744a22 DNSSEC fix for wildcard NSEC records. CVE-2017-15107 applies.
It's OK for NSEC records to be expanded from wildcards,
but in that case, the proof of non-existence is only valid
starting at the wildcard name, *.<domain> NOT the name expanded
from the wildcard. Without this check it's possible for an
attacker to craft an NSEC which wrongly proves non-existence
in a domain which includes a wildcard for NSEC.
2018-01-19 12:39:46 +00:00
Neil Jerram
3bd4c47f31 Remove limit on length of command-line options. 2018-01-18 22:49:38 +00:00
Artem Poloznikov
98196c4931 Typo fix. 2018-01-18 22:14:26 +00:00
Simon Kelley
22cd860124 Allow more than one --bridge-interface option to refer to an interface. 2018-01-14 22:57:14 +00:00
Simon Kelley
3c973ad92d Use SIGINT (instead of overloading SIGHUP) to turn on DNSSEC time validation. 2018-01-14 21:40:56 +00:00
Ville Skyttä
faaf306a63 Spelling fixes. 2018-01-14 17:32:52 +00:00
Geert Stappers
c7e6aea81b Change references to gPXE to iPXE.
Development of EtherBoot gPXE was always development
of iPXE core developer Michael Brown.

http://git.etherboot.org/?p=gpxe.git was last updated in 2011
https://git.ipxe.org/ipxe.git is well alive

This  s/gPXE/iPXE/ reflects that.

Signed-off-by: Geert Stappers <stappers@stappers.nl>
2018-01-13 17:56:37 +00:00
Simon Kelley
e541245987 Handle duplicate RRs in DNSSEC validation.
RFC 4034 says:
  [RFC2181] specifies that an RRset is not allowed to contain duplicate
  records (multiple RRs with the same owner name, class, type, and
  RDATA).  Therefore, if an implementation detects duplicate RRs when
  putting the RRset in canonical form, it MUST treat this as a protocol
  error.  If the implementation chooses to handle this protocol error
  in the spirit of the robustness principle (being liberal in what it
  accepts), it MUST remove all but one of the duplicate RR(s) for the
  purposes of calculating the canonical form of the RRset.

We chose to handle this robustly, having found at least one recursive
server in the wild which returns duplicate NSEC records in the AUTHORITY
section of an answer generated from a wildcard record. sort_rrset() is
therefore modified to delete duplicate RRs which are detected almost
for free during the bubble-sort process.

Thanks to Toralf Förster for helping to diagnose this problem.
2018-01-06 22:16:31 +00:00
Simon Kelley
84a01bee10 Bump year in Debian copyright notice. 2018-01-03 15:16:09 +00:00
Simon Kelley
d1ced3ae38 Update copyrights to 2018. 2018-01-01 22:18:03 +00:00
Simon Kelley
a6cee69af4 Fix exit code from dhcp_release6. 2017-12-14 22:40:48 +00:00
Simon Kelley
0039920ab6 Severely fix code formating of contrib/lease-tools/dhcp_release6.c 2017-12-14 22:29:31 +00:00
Simon Kelley
39d8550a80 Run Debian startup regex in "C" locale. 2017-12-14 21:23:34 +00:00
Simon Kelley
ef3d137a64 Fix infinite retries in strict-order mode.
If all configured dns servers return refused in
 response to a query; dnsmasq will end up in an infinite loop
 retransmitting the dns query resulting into high CPU load.
 Problem is caused by the dns refuse retransmission logic which does
 not check for the end of a dns server list iteration in strict mode.
 Having one configured dns server returning a refused reply easily
 triggers this problem in strict order mode. This was introduced in
 9396752c11

 Thanks to Hans Dedecker <dedeckeh@gmail.com> for spotting this
 and the initial patch.
2017-12-05 22:37:29 +00:00
Simon Kelley
8c707e1e37 Make 373e917389 compile without DNSSEC. 2017-12-05 22:28:10 +00:00
Simon Kelley
373e917389 Fix a6004d7f17 to cope with >256 RRs in answer section. 2017-12-01 22:40:56 +00:00
Josh Soref
74f0f9a042 Commment language tweaks. 2017-12-01 21:38:27 +00:00
李三0159
ed6bdb0967 Man page typos. 2017-11-30 16:47:01 +00:00
Simon Kelley
c88af046b7 Modify doc.html to mention git-over-http is now available. 2017-11-15 21:23:43 +00:00
Dr. Markus Waldeck
ae0187d454 Fix trust-anchor regexp in Debian init script. 2017-11-07 22:53:06 +00:00
Simon Kelley
0c50e3ddc8 Bump version in Debian package. 2017-11-07 22:49:20 +00:00
Petr Menšík
075366ad6e Open inotify socket only when used.
Some of our Openstack users run quite large number of dnsmasq instances
on single host. They started hitting default limit of inotify socket
number on single system after upgrade to more recent version. System
defaults of sysctl fs.inotify.max_user_instances is 128. They reached
limit of 116 dnsmasq instances, then more instances failed to start.

I was surprised they have any use case for such high number of
instances. They use one dnsmasq for one virtual network.

I found simple way to avoid hitting low system limit. They do not use
resolv.conf for name server configuration or any dhcp hosts or options
directory. Created inotify socket is never used in that case. Simple
patch attached.

I know we can raise inotify system limit. I think better is to not waste
resources that are left unused.
2017-11-05 16:05:39 +00:00
Simon Kelley
8e8b2d6f63 Release notes update. 2017-10-30 23:21:52 +00:00
Simon Kelley
087eb76140 Always return a SERVFAIL response to DNS queries with RD=0.
Unless we are acting in authoritative mode, obviously.

To do otherwise may allows cache snooping, see.
http://cs.unc.edu/~fabian/course_papers/cache_snooping.pdf
2017-10-30 23:16:54 +00:00
Simon Kelley
ebedcbaeb8 Typo in printf format string added in 22dee512f3 2017-10-29 20:54:17 +00:00
Simon Kelley
0954a977c9 Remove RSA/MD5 DNSSEC algorithm.
This is set to status DoNotImplement in RFC 6944.
2017-10-27 23:26:51 +01:00
Simon Kelley
b77efc1948 Tidy DNSSEC algorithm table use. 2017-10-27 23:23:53 +01:00
Simon Kelley
3b0cb34710 Fix manpage which said ZSK but meant KSK. 2017-10-27 22:54:35 +01:00
Simon Kelley
aa6f832d61 Add a few DNS RRs to the table. 2017-10-27 22:52:26 +01:00
Simon Kelley
ad9c6f06c5 Add support for Ed25519 DNSSEC signature algorithm. 2017-10-27 22:13:49 +01:00
Simon Kelley
a6004d7f17 Fix caching logic for validated answers.
The current logic is naive in the case that there is more than
one RRset in an answer (Typically, when a non-CNAME query is answered
by one or more CNAME RRs, and then then an answer RRset.)

If all the RRsets validate, then they are cached and marked as validated,
but if any RRset doesn't validate, then the AD flag is not set (good) and
ALL the RRsets are cached marked as not validated.

This breaks when, eg, the answer contains a validated CNAME, pointing
to a non-validated answer. A subsequent query for the CNAME without do
will get an answer with the AD flag wrongly reset, and worse, the same
query with do will get a cached answer without RRSIGS, rather than
being forwarded.

The code now records the validation of individual RRsets and that
is used to correctly set the "validated" bits in the cache entries.
2017-10-25 17:48:19 +01:00
Simon Kelley
c366717e66 Tidy up add_resource_record() buffer size checks.
Mainly code-size and readability fixes.

Also return NULL from do_rfc1035_name() when limit exceeded, so
that truncated bit gets set in answer.
2017-10-13 23:26:29 +01:00
Simon Kelley
22dee512f3 Log DNS server max packet size reduction. 2017-10-13 22:54:00 +01:00
Simon Kelley
6fd5d79e73 Fix logic on EDNS0 headers.
The logic to determine is an EDNS0 header was added was wrong. It compared
the packet length before and after the operations on the EDNS0 header,
but these can include adding options to an existing EDNS0 header. So
a query may have an existing EDNS0 header, which is extended, and logic
thinks that it had a header added de-novo.

Replace this with a simpler system. Check if the packet has an EDSN0 header,
do the updates/additions, and then check again. If it didn't have one
initially, but it has one laterly, that's the correct condition
to strip the header from a reply, and to assume that the client
cannot handle packets larger than 512 bytes.
2017-10-13 22:26:40 +01:00
Simon Kelley
9d6918d32c Use IP[V6]_UNICAST_IF socket option instead of SO_BINDTODEVICE for DNS.
dnsmasq allows to specify a interface for each name server passed with
the -S option or pushed through D-Bus; when an interface is set,
queries to the server will be forced via that interface.

Currently dnsmasq uses SO_BINDTODEVICE to enforce that traffic goes
through the given interface; SO_BINDTODEVICE also guarantees that any
response coming from other interfaces is ignored.

This can cause problems in some scenarios: consider the case where
eth0 and eth1 are in the same subnet and eth0 has a name server ns0
associated.  There is no guarantee that the response to a query sent
via eth0 to ns0 will be received on eth0 because the local router may
have in the ARP table the MAC address of eth1 for the IP of eth0. This
can happen because Linux sends ARP responses for all the IPs of the
machine through all interfaces. The response packet on the wrong
interface will be dropped because of SO_BINDTODEVICE and the
resolution will fail.

To avoid this situation, dnsmasq should only restrict queries, but not
responses, to the given interface. A way to do this on Linux is with
the IP_UNICAST_IF and IPV6_UNICAST_IF socket options which were added
in kernel 3.4 and, respectively, glibc versions 2.16 and 2.26.

Reported-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Beniamino Galvani <bgalvani@redhat.com>
2017-10-13 17:55:09 +01:00
Simon Kelley
a49c5c2265 Fix search_servers() segfault with DNSSEC.
--address=/example.com/<IP> would segfault if query on example.com
was generated as part of DNSSEC validation.
2017-10-10 22:04:59 +01:00
Simon Kelley
30858e3b9b Spaces in CNAME options break parsing.
cname = wibble,wobble

works, but

cname =	wibble, wobble

fails. Bug introduced in 2.77. commit a1d973f987
2017-10-09 22:36:11 +01:00
Simon Kelley
30df7efc96 Merge i18n messages. 2017-10-02 14:13:51 +01:00
Simon Kelley
3e8c42cba5 Debian changlelog update. 2017-09-29 17:39:26 +01:00
Simon Kelley
62cb936cb7 Security fix, CVE-2017-14491, DNS heap buffer overflow.
Further fix to 0549c73b7e
Handles case when RR name is not a pointer to the question,
only occurs for some auth-mode replies, therefore not
detected by fuzzing (?)
2017-09-26 22:00:11 +01:00
Simon Kelley
39921d03ba Update credits for Google security team. 2017-09-26 18:43:19 +01:00
Simon Kelley
6a0b00f0d6 Misc code cleanups arising from Google analysis.
No security impleications or CVEs.
2017-09-25 20:19:55 +01:00
Simon Kelley
51eadb692a Security fix, CVE-2017-14495, OOM in DNS response creation.
Fix out-of-memory Dos vulnerability. An attacker which can
send malicious DNS queries to dnsmasq can trigger memory
allocations in the add_pseudoheader function
The allocated memory is never freed which leads to a DoS
through memory exhaustion. dnsmasq is vulnerable only
if one of the following option is specified:
--add-mac, --add-cpe-id or --add-subnet.
2017-09-25 20:16:50 +01:00
Simon Kelley
897c113fda Security fix, CVE-2017-14496, Integer underflow in DNS response creation.
Fix DoS in DNS. Invalid boundary checks in the
add_pseudoheader function allows a memcpy call with negative
size An attacker which can send malicious DNS queries
to dnsmasq can trigger a DoS remotely.
dnsmasq is vulnerable only if one of the following option is
specified: --add-mac, --add-cpe-id or --add-subnet.
2017-09-25 20:11:58 +01:00
Simon Kelley
33e3f1029c Security fix, CVE-2017-14494, Infoleak handling DHCPv6 forwarded requests.
Fix information leak in DHCPv6. A crafted DHCPv6 packet can
cause dnsmasq to forward memory from outside the packet
buffer to a DHCPv6 server when acting as a relay.
2017-09-25 20:05:11 +01:00
Simon Kelley
3d4ff1ba84 Security fix, CVE-2017-14493, DHCPv6 - Stack buffer overflow.
Fix stack overflow in DHCPv6 code. An attacker who can send
a DHCPv6 request to dnsmasq can overflow the stack frame and
crash or control dnsmasq.
2017-09-25 19:59:54 +01:00
Simon Kelley
24036ea507 Security fix, CVE-2017-14492, DHCPv6 RA heap overflow.
Fix heap overflow in IPv6 router advertisement code.
This is a potentially serious security hole, as a
crafted RA request can overflow a buffer and crash or
control dnsmasq. Attacker must be on the local network.
2017-09-25 19:59:27 +01:00
Simon Kelley
0549c73b7e Security fix, CVE-2017-14491 DNS heap buffer overflow.
Fix heap overflow in DNS code. This is a potentially serious
security hole. It allows an attacker who can make DNS
requests to dnsmasq, and who controls the contents of
a domain, which is thereby queried, to overflow
(by 2 bytes) a heap buffer and either crash, or
even take control of, dnsmasq.
2017-09-25 18:17:11 +01:00
Christian Hesse
b697fbb7f1 Do not include stdio.h before dnsmasq.h
We define some constants in dnsmasq.h, which have an influence on
stdio.h. So do not include stdio.h before dnsmasq.h.
2017-09-25 17:36:24 +01:00
Rasmus Ahlberg
96e063c43d Update contrib/try-all-ns. 2017-09-25 17:30:59 +01:00
Chris Novakovic
4e841da1a6 Fix broken translations after commit 730c6745 2017-09-25 17:21:49 +01:00
Simon Kelley
09ce307bdb Disable libIDN2 underscore workaround with libIDN or fixed libIDN2. 2017-09-25 16:53:55 +01:00
Simon Kelley
a3303e196e Don't return arcount=1 if EDNS0 RR won't fit in the packet.
Omitting the EDNS0 RR but setting arcount gives a malformed packet.
Also, don't accept UDP packet size less than 512 in recieved EDNS0.
2017-09-07 20:45:00 +01:00
Simon Kelley
63437ffbb5 Fix CVE-2017-13704, which resulted in a crash on a large DNS query.
A DNS query recieved by UDP which exceeds 512 bytes (or the EDNS0 packet size,
if different.) is enough to cause SIGSEGV.
2017-09-06 22:34:21 +01:00
Simon Kelley
69a815aa8f Fix loss of undercores in domain names when using libidn2.
libidn2 strips underscores from international domain names
when encoding them. Indeed, it strips underscores even if
no encoding is necessary, which breaks SRV records.

Don't submit domain names to IDN encoding if they contain
one or more underscores to fix this.
2017-07-08 21:20:16 +01:00
Simon Kelley
1d224949cc Remove ping-check of configured DHCP address.
This was added in 5ce3e76fbf but
it trips over too many buggy clients that leave an interface configured
even in DHCPDISCOVER case.
2017-07-08 20:52:55 +01:00
Simon Kelley
391f708a09 Man page tweak. 2017-07-08 20:48:51 +01:00
Rosen Penev
cbd29e5da8 Printf related fixes. 2017-06-27 22:29:51 +01:00
Rosen Penev
50a2841d34 Fix function declarations. 2017-06-27 22:27:02 +01:00
Hans Dedecker
9396752c11 Try other servers if first returns REFUSED when --strict-order active.
If a DNS server replies REFUSED for a given DNS query in strict order mode
no failover to the next DNS server is triggered as the failover logic only
covers non strict mode.
As a result the client will be returned the REFUSED reply without first
falling back to the secondary DNS server(s).

Make failover support work as well for strict mode config in case REFUSED is
replied by deleting the strict order check and rely only on forwardall being
equal to 0 which is the case in non strict mode when a single server has been
contacted or when strict order mode has been configured.
2017-06-27 22:08:47 +01:00
Simon Kelley
712dadb287 Bump Debian version to 2.78-1 2017-06-25 21:35:47 +01:00
Simon Kelley
32be32eab8 Formatting fixes for CHANGELOG 2017-06-25 21:33:28 +01:00
Simon Kelley
1649f709e7 Fix DHCP relay, broken by ff325644c7
Thanks to John Fitzgibbon for initial patch.
2017-06-25 21:19:30 +01:00
Simon Kelley
50ca85504c Bump year in copyrights. 2017-06-24 22:43:18 +01:00
Simon Kelley
4bb68866a8 Tweak ICMP ping check logic for DHCPv4. 2017-06-15 23:23:25 +01:00
Chris Novakovic
2446514e71 Fix logic of appending ".<layer>" to PXE basename
Commit f77700aa, which fixes a compiler warning, also breaks the
behaviour of prepending ".<layer>" to basenames in --pxe-service: in
situations where the basename contains a ".", the ".<layer>" suffix is
erroneously added, and in situations where the basename doesn't contain
a ".", the ".<layer>" suffix is erroneously omitted.

A patch against the git HEAD is attached that inverts this logic and
restores the expected behaviour of --pxe-service.
2017-06-06 23:02:59 +01:00
Simon Kelley
109d0e74f1 Debian: improve regexp for parsing root.ds. 2017-06-05 20:50:54 +01:00
Simon Kelley
74ea91531a Fix typo and format in CHANGELOG 2017-05-22 22:58:46 +01:00
Matthias Andree
9828ab115e Fix compiler warning. 2017-05-21 22:41:16 +01:00
Matthias Andree
f77700aa27 Fix compiler warning. 2017-05-21 22:36:09 +01:00
Simon Kelley
0fbd980639 Fix compiler warning. 2017-05-21 22:24:43 +01:00
Simon Kelley
43cdf1c3d0 Remove automatic IDN support when building i18n.
Remove historic automatic inclusion of IDN support when
building internationalisation support. This doesn't
fit now there is a choice of IDN libraries. Be sure
to include either -DHAVE_IDN or _DHAVE_LIBIDN2 for
IDN support
2017-05-21 22:12:44 +01:00
Simon Kelley
ff19b1a97d Fix &/&& confusion. 2017-05-21 21:15:32 +01:00
Conrad Kostecki
1835343acd Update German translation. 2017-05-12 15:16:02 +01:00
Simon Kelley
2aaea18f43 Add .gitattributes to substitute VERSION on export. 2017-05-12 13:14:17 +01:00
Simon Kelley
7ab78b937f Fix c7be0164ce 2017-05-11 20:33:21 +01:00
Simon Kelley
c7be0164ce Suppress DHCP ping checks when allocating on the loopback interface. 2017-05-10 22:21:53 +01:00
Petr Menšík
d203af4a02 Add optional support for libidn2 and therefore IDNA2008. 2017-05-10 21:41:57 +01:00
Simon Kelley
05f76dab89 Don't die() on failing to parse lease-script output. 2017-05-09 22:57:04 +01:00
Simon Kelley
bf05f8ff20 Fix crash introduced by 09f3b2cd9c. 2017-05-09 22:37:46 +01:00
Simon Kelley
09f3b2cd9c Fix case of DS queries to domains marked as not doing DNSSEC.
This was causing confusion: DNSSEC queries would be sent to
servers for domains that don't do DNSSEC, but because of that status
the answers would be treated as answers to ordinary queries,
sometimes resulting in a crash.
2017-05-09 01:34:02 +01:00
Simon Kelley
22827870fa Fix botch introduced by 561441320f 2017-05-08 21:39:04 +01:00
Vladislav Grishenko
4583dd9e42 Replace obsolete utime() usage with utimes().
This fixes build time warnings with POSIX.1-2008-aware c libraries.
2017-05-03 23:16:51 +01:00
Simon Kelley
561441320f Fix a couple of crashes on malformed config files.
Thanks to Stephan Zeisberg and
american fuzzy lop http://lcamtuf.coredump.cx/afl/
2017-05-03 22:54:09 +01:00
Simon Kelley
b2a9c571eb Add "known-othernet" DHCP tag. 2017-04-30 18:21:31 +01:00
74 changed files with 9653 additions and 8227 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
VERSION export-subst

5
.gitignore vendored
View File

@@ -7,9 +7,8 @@ src/.copts_*
contrib/lease-tools/dhcp_lease_time
contrib/lease-tools/dhcp_release
contrib/lease-tools/dhcp_release6
debian/base/
debian/daemon/
debian/files
debian/substvars
debian/utils-substvars
debian/utils/
debian/trees/
debian/build/

3583
CHANGELOG

File diff suppressed because it is too large Load Diff

View File

@@ -1010,7 +1010,7 @@ release 2.9
but to the address of another interface were ignored
unless the loopback interface was explicitly configured.
2) on OpenBSD failure to configure one interface now
causes a fatal error on startup rather than an huge
causes a fatal error on startup rather than a huge
stream of log messages. Thanks to Erik Jan Tromp for
finding that bug.
@@ -2067,7 +2067,7 @@ version 2.36
kernel. Thanks to Philip Wall for the bug report.
Added --dhcp-bridge option, but only to the FreeBSD
build. This fixes an oddity with a a particular bridged
build. This fixes an oddity with a particular bridged
network configuration on FreeBSD. Thanks to Luigi Rizzo
for the patch.
@@ -2273,7 +2273,7 @@ version 2.40
this.
Use client-id as hash-seed for DHCP address allocation
with Firewire and InfiniBand, as these don't supply an MAC
with Firewire and InfiniBand, as these don't supply a MAC
address.
Tweaked TFTP file-open code to make it behave sensibly
@@ -2433,7 +2433,7 @@ version 2.41
Add --dhcp-match flag, to check for arbitrary options in
DHCP messages from clients. This enables use of dnsmasq
with gPXE. Thanks to Rance Hall for the suggestion.
with iPXE. Thanks to Rance Hall for the suggestion.
Added --dhcp-broadcast, to force broadcast replies to DHCP
clients which need them but are too dumb or too old to

6
FAQ
View File

@@ -9,7 +9,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
from port 53 the replies would be _to_ port 53 and get blocked.
This is not a security hole since dnsmasq will only accept replies to that
port: queries are dropped. The replies must be to oustanding queries
port: queries are dropped. The replies must be to outstanding queries
which dnsmasq has forwarded, otherwise they are dropped too.
Addendum: dnsmasq now has the option "query-port" (-Q), which allows
@@ -297,7 +297,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
mode, such interfaces are handled normally.
A --interface specification for a non-existent interface is a fatal
An --interface specification for a non-existent interface is a fatal
error at start-up when in --bind-interfaces mode, by just generates a
warning in wildcard or bind-dynamic mode.
@@ -320,7 +320,7 @@ A: Yes, new releases of dnsmasq are always announced through
Q: What does the dhcp-authoritative option do?
A: The DHCP spec says that when a DHCP server recieves a renewal request
A: The DHCP spec says that when a DHCP server receives a renewal request
from a client it has no knowledge of, it should just ignore it.
This is because it's supported to have more than one DHCP server
on a network, and another DHCP server may be dealing with the client.

View File

@@ -55,6 +55,8 @@ dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG)
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
idn2_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
@@ -74,7 +76,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o
poll.o rrfilter.o edns0.o arp.o crypto.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h
@@ -82,8 +84,8 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
-f $(top)/Makefile dnsmasq
mostly_clean :
@@ -106,8 +108,8 @@ all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) `$(PKG_CONFIG) --libs libidn`" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \

View File

@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c crypto.c
LOCAL_MODULE := dnsmasq

View File

@@ -206,13 +206,13 @@ int main(int argc, char **argv)
{
unsigned int x;
if ((x = t/86400))
printf("%dd", x);
printf("%ud", x);
if ((x = (t/3600)%24))
printf("%dh", x);
printf("%uh", x);
if ((x = (t/60)%60))
printf("%dm", x);
printf("%um", x);
if ((x = t%60))
printf("%ds", x);
printf("%us", x);
}
return 0;
}

View File

@@ -46,7 +46,8 @@ typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
enum DHCP6_TYPES{
enum DHCP6_TYPES
{
SOLICIT = 1,
ADVERTISE = 2,
REQUEST = 3,
@@ -61,8 +62,10 @@ enum DHCP6_TYPES{
RELAY_FORW = 12,
RELAY_REPL = 13
};
enum DHCP6_OPTIONS{
};
enum DHCP6_OPTIONS
{
CLIENTID = 1,
SERVERID = 2,
IA_NA = 3,
@@ -82,25 +85,27 @@ enum DHCP6_OPTIONS{
INTERFACE_ID = 18,
RECONF_MSG = 19,
RECONF_ACCEPT = 20,
};
};
enum DHCP6_STATUSES{
enum DHCP6_STATUSES
{
SUCCESS = 0,
UNSPEC_FAIL = 1,
NOADDR_AVAIL=2,
NO_BINDING = 3,
NOT_ON_LINK = 4,
USE_MULTICAST =5
};
};
static struct option longopts[] = {
{"ip", required_argument, 0, 'a'},
{"server-id", required_argument, 0, 's'},
{"client-id", required_argument, 0, 'c'},
{"iface", required_argument, 0, 'n'},
{"iaid", required_argument, 0, 'i'},
{"dry-run", no_argument, 0, 'd'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
{"ip", required_argument, 0, 'a' },
{"server-id", required_argument, 0, 's' },
{"client-id", required_argument, 0, 'c' },
{"iface", required_argument, 0, 'n' },
{"iaid", required_argument, 0, 'i' },
{"dry-run", no_argument, 0, 'd' },
{"help", no_argument, 0, 'h' },
{0, 0, 0, 0 }
};
const short DHCP6_CLIENT_PORT = 546;
@@ -108,207 +113,230 @@ const short DHCP6_SERVER_PORT = 547;
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
struct dhcp6_option{
uint16_t type;
uint16_t len;
char value[1024];
struct dhcp6_option {
uint16_t type;
uint16_t len;
char value[1024];
};
struct dhcp6_iaaddr_option{
uint16_t type;
uint16_t len;
struct in6_addr ip;
uint32_t preferred_lifetime;
uint32_t valid_lifetime;
struct dhcp6_iaaddr_option {
uint16_t type;
uint16_t len;
struct in6_addr ip;
uint32_t preferred_lifetime;
uint32_t valid_lifetime;
};
struct dhcp6_iana_option{
uint16_t type;
uint16_t len;
uint32_t iaid;
uint32_t t1;
uint32_t t2;
char options[1024];
struct dhcp6_iana_option {
uint16_t type;
uint16_t len;
uint32_t iaid;
uint32_t t1;
uint32_t t2;
char options[1024];
};
struct dhcp6_packet{
size_t len;
char buf[2048];
} ;
struct dhcp6_packet {
size_t len;
char buf[2048];
};
size_t pack_duid(const char* str, char* dst){
char* tmp = strdup(str);
char* tmp_to_free = tmp;
char *ptr;
uint8_t write_pos = 0;
while ((ptr = strtok (tmp, ":"))) {
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
write_pos += 1;
tmp = NULL;
size_t pack_duid(const char* str, char* dst)
{
char* tmp = strdup(str);
char* tmp_to_free = tmp;
char *ptr;
uint8_t write_pos = 0;
while ((ptr = strtok (tmp, ":")))
{
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
write_pos += 1;
tmp = NULL;
}
free(tmp_to_free);
return write_pos;
free(tmp_to_free);
return write_pos;
}
struct dhcp6_option create_client_id_option(const char* duid){
struct dhcp6_option option;
option.type = htons(CLIENTID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
struct dhcp6_option create_client_id_option(const char* duid)
{
struct dhcp6_option option;
option.type = htons(CLIENTID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
}
struct dhcp6_option create_server_id_option(const char* duid){
struct dhcp6_option option;
option.type = htons(SERVERID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
struct dhcp6_option create_server_id_option(const char* duid)
{
struct dhcp6_option option;
option.type = htons(SERVERID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
}
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){
struct dhcp6_iaaddr_option result;
result.type =htons(IAADDR);
/* no suboptions needed here, so length is 24 */
result.len = htons(24);
result.preferred_lifetime = 0;
result.valid_lifetime = 0;
int s = inet_pton(AF_INET6, ip, &(result.ip));
if (s <= 0) {
if (s == 0)
fprintf(stderr, "Not in presentation format");
else
perror("inet_pton");
exit(EXIT_FAILURE);
}
return result;
}
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){
struct dhcp6_iana_option result;
result.type = htons(IA_NA);
result.iaid = htonl(atoi(iaid));
result.t1 = 0;
result.t2 = 0;
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
return result;
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip)
{
struct dhcp6_iaaddr_option result;
result.type =htons(IAADDR);
/* no suboptions needed here, so length is 24 */
result.len = htons(24);
result.preferred_lifetime = 0;
result.valid_lifetime = 0;
int s = inet_pton(AF_INET6, ip, &(result.ip));
if (s <= 0) {
if (s == 0)
fprintf(stderr, "Not in presentation format");
else
perror("inet_pton");
exit(EXIT_FAILURE);
}
return result;
}
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){
struct dhcp6_packet result;
bzero(result.buf, sizeof(result.buf));
/* message_type */
result.buf[0] = RELEASE;
/* tx_id */
bzero(result.buf+1, 3);
struct dhcp6_option client_option = create_client_id_option(client_id);
struct dhcp6_option server_option = create_server_id_option(server_id);
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
int offset = 4;
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
result.len = offset;
return result;
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr)
{
struct dhcp6_iana_option result;
result.type = htons(IA_NA);
result.iaid = htonl(atoi(iaid));
result.t1 = 0;
result.t2 = 0;
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
return result;
}
uint16_t parse_iana_suboption(char* buf, size_t len){
size_t current_pos = 0;
char option_value[1024];
while (current_pos < len) {
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE){
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS){
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
option_value[option_len-sizeof(uint16_t)] ='\0';
fprintf(stderr, "Error: %s\n", option_value);
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id)
{
struct dhcp6_packet result;
bzero(result.buf, sizeof(result.buf));
/* message_type */
result.buf[0] = RELEASE;
/* tx_id */
bzero(result.buf+1, 3);
struct dhcp6_option client_option = create_client_id_option(client_id);
struct dhcp6_option server_option = create_server_id_option(server_id);
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
int offset = 4;
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
result.len = offset;
return result;
}
uint16_t parse_iana_suboption(char* buf, size_t len)
{
size_t current_pos = 0;
char option_value[1024];
while (current_pos < len)
{
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE)
{
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
option_value[option_len-sizeof(uint16_t)] ='\0';
fprintf(stderr, "Error: %s\n", option_value);
}
return status;
return status;
}
}
return -2;
return -2;
}
int16_t parse_packet(char* buf, size_t len){
uint8_t type = buf[0];
/*skipping tx id. you need it, uncomment following line
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
*/
size_t current_pos = 4;
if (type != REPLY ){
return NOT_REPLY_CODE;
}
char option_value[1024];
while (current_pos < len) {
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE){
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS){
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
fprintf(stderr, "Error: %d %s\n", status, option_value);
return status;
}
int16_t parse_packet(char* buf, size_t len)
{
int16_t ret = -1;
uint8_t type = buf[0];
/*skipping tx id. you need it, uncomment following line
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
*/
size_t current_pos = 4;
if (type != REPLY )
return NOT_REPLY_CODE;
char option_value[1024];
while (current_pos < len)
{
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE)
{
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
fprintf(stderr, "Error: %d %s\n", status, option_value);
return status;
}
/* Got success status, return that if there's no specific error in an IA_NA. */
ret = SUCCESS;
}
if (option_type == IA_NA ){
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
if (result){
return result;
}
}
current_pos += option_len;
if (option_type == IA_NA )
{
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
if (result)
return result;
}
current_pos += option_len;
}
return -1;
return ret;
}
void usage(const char* arg, FILE* stream){
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
void usage(const char* arg, FILE* stream)
{
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
}
int send_release_packet(const char* iface, struct dhcp6_packet* packet){
struct sockaddr_in6 server_addr, client_addr;
char response[1400];
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
int i = 0;
if (sock < 0) {
perror("creating socket");
return -1;
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
{
struct sockaddr_in6 server_addr, client_addr;
char response[1400];
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
int i = 0;
if (sock < 0)
{
perror("creating socket");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1) {
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1)
{
perror("SO_BINDTODEVICE");
close(sock);
return -1;
}
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
client_addr.sin6_family = AF_INET6;
@@ -320,126 +348,149 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet){
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
int16_t recv_size = 0;
for (i = 0; i < 5; i++) {
if (sendto(sock, packet->buf, packet->len, 0,
(struct sockaddr *)&server_addr,
sizeof(server_addr)) < 0) {
perror("sendto failed");
for (i = 0; i < 5; i++)
{
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
perror("sendto failed");
exit(4);
}
}
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
if (recv_size == -1){
if (errno == EAGAIN){
sleep(1);
continue;
}else {
if (recv_size == -1)
{
if (errno == EAGAIN)
{
sleep(1);
continue;
}
else
{
perror("recvfrom");
}
}
}
}
int16_t result = parse_packet(response, recv_size);
if (result == NOT_REPLY_CODE){
if (result == NOT_REPLY_CODE)
{
sleep(1);
continue;
}
}
return result;
}
fprintf(stderr, "Response timed out\n");
return -1;
}
fprintf(stderr, "Response timed out\n");
return -1;
}
int main(int argc, char * const argv[]) {
const char* UNINITIALIZED = "";
const char* iface = UNINITIALIZED;
const char* ip = UNINITIALIZED;
const char* client_id = UNINITIALIZED;
const char* server_id = UNINITIALIZED;
const char* iaid = UNINITIALIZED;
int dry_run = 0;
while (1) {
int option_index = 0;
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
if (c == -1){
break;
}
switch(c){
case 0:
if (longopts[option_index].flag !=0){
break;
}
printf ("option %s", longopts[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'i':
iaid = optarg;
break;
case 'n':
iface = optarg;
break;
case 'a':
ip = optarg;
break;
case 'c':
client_id = optarg;
break;
case 'd':
dry_run = 1;
break;
case 's':
server_id = optarg;
break;
case 'h':
usage(argv[0], stdout);
return 0;
case '?':
usage(argv[0], stderr);
return -1;
default:
abort();
}
int main(int argc, char * const argv[])
{
const char* UNINITIALIZED = "";
const char* iface = UNINITIALIZED;
const char* ip = UNINITIALIZED;
const char* client_id = UNINITIALIZED;
const char* server_id = UNINITIALIZED;
const char* iaid = UNINITIALIZED;
int dry_run = 0;
while (1)
{
int option_index = 0;
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
if (c == -1)
break;
switch(c)
{
case 0:
if (longopts[option_index].flag !=0)
break;
printf ("option %s", longopts[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'i':
iaid = optarg;
break;
case 'n':
iface = optarg;
break;
case 'a':
ip = optarg;
break;
case 'c':
client_id = optarg;
break;
case 'd':
dry_run = 1;
break;
case 's':
server_id = optarg;
break;
case 'h':
usage(argv[0], stdout);
return 0;
case '?':
usage(argv[0], stderr);
return -1;
default:
abort();
}
}
if (iaid == UNINITIALIZED){
fprintf(stderr, "Missing required iaid parameter\n");
usage(argv[0], stderr);
return -1;
if (iaid == UNINITIALIZED)
{
fprintf(stderr, "Missing required iaid parameter\n");
usage(argv[0], stderr);
return -1;
}
if (server_id == UNINITIALIZED){
if (server_id == UNINITIALIZED)
{
fprintf(stderr, "Missing required server-id parameter\n");
usage(argv[0], stderr);
return -1;
}
if (client_id == UNINITIALIZED){
}
if (client_id == UNINITIALIZED)
{
fprintf(stderr, "Missing required client-id parameter\n");
usage(argv[0], stderr);
return -1;
}
if (ip == UNINITIALIZED){
}
if (ip == UNINITIALIZED)
{
fprintf(stderr, "Missing required ip parameter\n");
usage(argv[0], stderr);
return -1;
}
if (iface == UNINITIALIZED){
fprintf(stderr, "Missing required iface parameter\n");
}
if (iface == UNINITIALIZED)
{
fprintf(stderr, "Missing required iface parameter\n");
usage(argv[0], stderr);
return -1;
}
}
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
if (dry_run){
if (dry_run)
{
uint16_t i;
for(i=0;i<packet.len;i++){
printf("%hhx", packet.buf[i]);
}
for(i=0; i<packet.len; i++)
printf("%hhx", packet.buf[i]);
printf("\n");
return 0;
}
}
return send_release_packet(iface, &packet);
}

View File

@@ -3,7 +3,7 @@
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
# Script for dnsmasq lease-change hook.
# Maintains the above file with a IP address/MAC address pairs,
# Maintains the above file with an IP address/MAC address pairs,
# one lease per line. Works with IPv4 and IPv6 leases, file is
# atomically updated, so no races for users of the data.

View File

@@ -0,0 +1,10 @@
Hi,
I updated the try-all-ns patch to work with the latest version of git. Ended up implementing it on top of master, 2.78test2-7-g63437ff. As that specific if-clause has been changed in the last few commits, it's not compatible for 2.77, sadly.
Find the patch attached.
Regards,
Rasmus Ahlberg
Software Developer, R&D
Electrolux Small Appliances

View File

@@ -0,0 +1,20 @@
diff --git a/src/forward.c b/src/forward.c
index e3fa94b..ecf3b98 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -789,9 +789,12 @@ void reply_query(int fd, int family, time_t now)
/* Note: if we send extra options in the EDNS0 header, we can't recreate
the query from the reply. */
- if (RCODE(header) == REFUSED &&
- forward->forwardall == 0 &&
- !(forward->flags & FREC_HAS_EXTRADATA))
+ if ((RCODE(header) == REFUSED &&
+ forward->forwardall == 0 &&
+ !(forward->flags & FREC_HAS_EXTRADATA)) ||
+ /* If strict-order is set, try next server on NXDOMAIN reply */
+ (RCODE(header) == NXDOMAIN && option_bool(OPT_ORDER) &&
+ server->next != NULL))
/* for broken servers, attempt to send to another one. */
{
unsigned char *pheader;

41
debian/changelog vendored
View File

@@ -1,3 +1,42 @@
dnsmasq (2.79-1) unstable; urgency=low
* New upstream. (closes: #888200)
* Fix trust-anchor regex in init script. (closes: #884347)
* Fix exit code for dhcp_release6 (closes: #833596)
* Add project homepage to control file. (closes: #887764)
* New binary package dnsmasq-base-lua, includes Lua support.
* Remove hardwired shlibs dependency for libnettle 3.3 and
fix code to avoid ABI breakage as long as compiled against
libnettle 3.4 or later. (closes: #891315)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 Feb 2018 19:54:22 +0000
dnsmasq (2.78-3) unstable; urgency=high
* Make failure of pidfile chown a warning. (closes: #889857)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 8 Feb 2018 21:26:30 +0000
dnsmasq (2.78-2) unstable; urgency=high
* Change ownership of pid file, to keep systemd happy. (closes: #889336)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Feb 2018 17:21:30 +0000
dnsmasq (2.78-1) unstable; urgency=high
* New upstream.
Security fixes for CVE-2017-13704 (closes: #877102)
Security fixes for CVE-2017-14491 - CVE-2017-14496 inclusive.
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 29 Sep 2017 21:34:00 +0000
dnsmasq (2.77-2) unstable; urgency=low
* Improve sed regexp for parsing root.ds.
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 5 Jun 2017 20:46:32 +0000
dnsmasq (2.77-1) unstable; urgency=low
* New upstream.
@@ -5,7 +44,7 @@ dnsmasq (2.77-1) unstable; urgency=low
includes port=0 to disable DNS.
* Handle gratuitous format change in /usr/share/dns/root.ds
(closes: #858506) (closes: #860064)
* Add lsb-base dependancy.
* Add lsb-base dependency.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000

24
debian/control vendored
View File

@@ -3,13 +3,15 @@ Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
liblua5.2-dev
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
Standards-Version: 3.9.8
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
Depends: netbase, dnsmasq-base,
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
@@ -27,13 +29,29 @@ Package: dnsmasq-base
Architecture: any
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
Recommends: dns-root-data
Provides: dnsmasq-base
Conflicts: dnsmasq-base-lua
Description: Small caching DNS proxy and DHCP/TFTP server
This package contains the dnsmasq executable and documentation, but
not the infrastructure required to run it as a system daemon. For
that, install the dnsmasq package.
Package: dnsmasq-base-lua
Architecture: any
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
Recommends: dns-root-data
Provides: dnsmasq-base
Conflicts: dnsmasq-base
Description: Small caching DNS proxy and DHCP/TFTP server
This package contains the dnsmasq executable and documentation, but
not the infrastructure required to run it as a system daemon. For
that, install the dnsmasq package. This package is an alternative
to dnsmasq-base which includes the LUA interpreter.
Package: dnsmasq-utils
Architecture: linux-any
Depends: ${shlibs:Depends}

2
debian/copyright vendored
View File

@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2016 Simon Kelley
dnsmasq is Copyright (c) 2000-2018 Simon Kelley
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/

2
debian/init vendored
View File

@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/"^.*DS[\t ]"/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
fi
start()

2
debian/readme vendored
View File

@@ -54,7 +54,7 @@ Notes on configuring dnsmasq as packaged for Debian.
nodhcp : omit DHCP support.
nodhcp6 : omit DHCPv6 support.
noscript : omit lease-change script support.
use_lua : provide support for lease-change scripts written
uselua : provide support for lease-change scripts written
in Lua.
noipv6 : omit IPv6 support.
nodbus : omit DBus support.

268
debian/rules vendored
View File

@@ -1,6 +1,6 @@
#!/usr/bin/make -f
# debian/rules file - for dnsmasq.
# Copyright 2001-2011 by Simon Kelley
# Copyright 2001-2018 by Simon Kelley
# Based on the sample in the debian hello package which carries the following:
# Copyright 1994,1995 by Ian Jackson.
# I hereby give you perpetual unlimited permission to copy,
@@ -48,6 +48,10 @@ ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DBUS
endif
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_IDN
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
@@ -84,9 +88,6 @@ endif
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_IDN
endif
endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
@@ -102,128 +103,167 @@ ifneq ($(DEB_HOST_ARCH_OS),linux)
LDFLAGS += -lbsd
endif
clean:
$(checkdir)
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
make clean
make -C contrib/lease-tools clean
binary-indep: checkroot
$(checkdir)
rm -rf debian/daemon
define build_tree
rm -rf $1
install -m 755 \
-d debian/daemon/DEBIAN \
-d debian/daemon/usr/share/doc \
-d debian/daemon/etc/init.d \
-d debian/daemon/etc/dnsmasq.d \
-d debian/daemon/etc/resolvconf/update.d \
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/daemon/usr/share/dnsmasq \
-d debian/daemon/etc/default \
-d debian/daemon/lib/systemd/system \
-d debian/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
install -m 644 debian/installed-marker debian/daemon/usr/share/dnsmasq
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
-d $1/DEBIAN \
-d $1/etc/dbus-1/system.d \
-d $1/usr/share/doc/$(package) \
-d $1/usr/share/doc/$(package)/examples \
-d $1/usr/share/$(package) \
-d $1/var/lib/misc
binary-arch: checkroot
$(checkdir)
rm -rf debian/base
install -m 755 \
-d debian/base/DEBIAN \
-d debian/base/etc/dbus-1/system.d \
-d debian/base/usr/share/doc/$(package) \
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/usr/share/$(package) \
-d debian/base/var/lib/misc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
endef
define add_docs
# Need to remove paypal links in Debian Package for policy reasons.
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
gzip -9n debian/base/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
gzip -9n debian/base/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
endif
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
gzip -9n debian/base/usr/share/doc/$(package)/changelog.Debian
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
gzip -9n debian/base/usr/share/man/man8/dnsmasq.8
for f in debian/base/usr/share/man/*; do \
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >$1/usr/share/doc/$(package)/doc.html
echo "</BODY>" >>$1/usr/share/doc/$(package)/doc.html
install -m 644 setup.html $1/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example $1/usr/share/doc/$(package)/examples/.
install -m 644 FAQ $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG $1/usr/share/doc/$(package)/changelog
gzip -9n $1/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG.archive $1/usr/share/doc/$(package)/changelog.archive
gzip -9n $1/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/DBus-interface
gzip -9n $1/usr/share/man/man8/dnsmasq.8
for f in $1/usr/share/man/*; do \
if [ -f $$f/man8/dnsmasq.8 ]; then \
gzip -9n $$f/man8/dnsmasq.8 ; \
fi \
done
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endef
define add_files
install -m 644 trust-anchors.conf $1/usr/share/$(package)/.
install -m 644 debian/dnsmasq-base.conffiles $1/DEBIAN/conffiles
install -m 755 debian/dnsmasq-base.postinst $1/DEBIAN/postinst
install -m 755 debian/dnsmasq-base.postrm $1/DEBIAN/postrm
install -m 644 debian/changelog $1/usr/share/doc/$(package)/changelog.Debian
gzip -9n $1/usr/share/doc/$(package)/changelog.Debian
install -m 644 debian/readme $1/usr/share/doc/$(package)/README.Debian
install -m 644 debian/copyright $1/usr/share/doc/$(package)/copyright
install -m 644 debian/dbus.conf $1/etc/dbus-1/system.d/dnsmasq.conf
endef
clean:
$(checkdir)
make BUILDDIR=debian/build/no-lua clean
make BUILDDIR=debian/build/lua clean
make -C contrib/lease-tools clean
rm -rf debian/build debian/trees debian/*~ debian/files debian/substvars debian/utils-substvars
binary-indep: checkroot
$(checkdir)
rm -rf debian/trees/daemon
install -m 755 \
-d debian/trees/daemon/DEBIAN \
-d debian/trees/daemon/usr/share/doc \
-d debian/trees/daemon/etc/init.d \
-d debian/trees/daemon/etc/dnsmasq.d \
-d debian/trees/daemon/etc/resolvconf/update.d \
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/trees/daemon/usr/share/dnsmasq \
-d debian/trees/daemon/etc/default \
-d debian/trees/daemon/lib/systemd/system \
-d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
install -m 644 debian/installed-marker debian/trees/daemon/usr/share/dnsmasq
install -m 644 debian/default debian/trees/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/trees/daemon
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/daemon
chmod -R g-ws debian/trees/daemon
dpkg --build debian/trees/daemon ..
binary-arch: checkroot
$(call build_tree,debian/trees/base)
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
$(call add_docs,debian/trees/base)
else
rm -rf debian/trees/base/usr/share/man
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
$(call add_files,debian/trees/base)
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/base/usr/sbin/dnsmasq
endif
cd debian/trees/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/trees/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/trees/base
find debian/trees/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/base
chmod -R g-ws debian/trees/base
dpkg --build debian/trees/base ..
$(call build_tree,debian/trees/lua-base)
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
$(call add_docs,debian/trees/lua-base)
else
rm -rf debian/trees/lua-base/usr/share/man
endif
$(call add_files,debian/trees/lua-base)
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/lua-base/usr/sbin/dnsmasq
endif
cd debian/trees/lua-base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/trees/lua-base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base-lua -Pdebian/trees/lua-base
find debian/trees/lua-base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/lua-base
chmod -R g-ws debian/trees/lua-base
dpkg --build debian/trees/lua-base ..
ifeq ($(DEB_HOST_ARCH_OS),linux)
rm -rf debian/utils
install -m 755 -d debian/utils/DEBIAN \
-d debian/utils/usr/share/man/man1 \
-d debian/utils/usr/bin \
-d debian/utils/usr/share/doc/dnsmasq-utils
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
rm -rf debian/trees/utils
install -m 755 -d debian/trees/utils/DEBIAN \
-d debian/trees/utils/usr/bin \
-d debian/trees/utils/usr/share/doc/dnsmasq-utils
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 755 -d debian/trees/utils/usr/share/man/man1
endif
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 644 contrib/lease-tools/dhcp_release.1 debian/trees/utils/usr/share/man/man1/dhcp_release.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release.1
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/trees/utils/usr/share/man/man1/dhcp_release6.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release6.1
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
endif
install -m 644 debian/copyright debian/trees/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release6
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_lease_time
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..
cd debian/trees/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/trees/utils/usr/bin/dhcp_release debian/trees/utils/usr/bin/dhcp_release6 debian/trees/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/trees/utils
find debian/trees/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/utils
chmod -R g-ws debian/trees/utils
dpkg --build debian/trees/utils ..
endif
define checkdir

1
debian/shlibs.local vendored
View File

@@ -1 +0,0 @@
libnettle 6 libnettle6 (>= 3.3)

View File

@@ -90,7 +90,7 @@
# server=10.1.2.3@eth1
# and this sets the source (ie local) address used to talk to
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
# IP on the machine, obviously).
# server=10.1.2.3@192.168.1.1#55
@@ -288,7 +288,7 @@
# Give a fixed IPv6 address and name to client with
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
# Note also the they [] around the IPv6 address are obligatory.
# Note also that the [] around the IPv6 address are obligatory.
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
# Ignore any clients which are not specified in dhcp-host lines
@@ -354,11 +354,11 @@
# Set option 58 client renewal time (T1). Defaults to half of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T1:1m
#dhcp-option=option:T1,1m
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T2:2m
#dhcp-option=option:T2,2m
# Set the NTP time server address to be the same machine as
# is running dnsmasq
@@ -436,22 +436,22 @@
#dhcp-option-force=211,30i
# Set the boot filename for netboot/PXE. You will only need
# this is you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built in TFTP server or an
# this if you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built-in TFTP server or an
# external one. (See below for how to enable the TFTP server.)
#dhcp-boot=pxelinux.0
# The same as above, but use custom tftp-server instead machine running dnsmasq
#dhcp-boot=pxelinux,server.name,192.168.1.100
# Boot for Etherboot gPXE. The idea is to send two different
# filenames, the first loads gPXE, and the second tells gPXE what to
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
#dhcp-boot=tag:!gpxe,undionly.kpxe
#dhcp-boot=mybootimage
# Boot for iPXE. The idea is to send two different
# filenames, the first loads iPXE, and the second tells iPXE what to
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
#dhcp-boot=undionly.kpxe
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
# Encapsulated options for Etherboot gPXE. All the options are
# Encapsulated options for iPXE. All the options are
# encapsulated within option 175
#dhcp-option=encap:175, 1, 5b # priority code
#dhcp-option=encap:175, 176, 1b # no-proxydhcp

View File

@@ -66,6 +66,10 @@ the repo, or get a copy using git protocol with the command
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
or
<PRE><TT>git clone http://thekelleys.org.uk/git/dnsmasq.git </TT></PRE>
<H2>License.</H2>
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
for details.

View File

@@ -182,7 +182,8 @@ OS: this was the default behaviour in versions prior to 2.43.
Do not use ports less than that given as source for outbound DNS
queries. Dnsmasq picks random ports as source for outbound queries:
when this option is given, the ports used will always to larger
than that specified. Useful for systems behind firewalls.
than that specified. Useful for systems behind firewalls. If not specified,
defaults to 1024.
.TP
.B --max-port=<port>
Use ports lower than that given as source for outbound DNS queries.
@@ -241,7 +242,7 @@ configuration, indeed
.B --auth-server
will override these and provide a different DNS service on the
specified interface. The <domain> is the "glue record". It should
resolve in the global DNS to a A and/or AAAA record which points to
resolve in the global DNS to an A and/or AAAA record which points to
the address dnsmasq is listening on. When an interface is specified,
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
addresses associated with the interface.
@@ -464,7 +465,7 @@ is a synonym for
.B server
to make configuration files clearer in this case.
IPv6 addresses may include a %interface scope-id, eg
IPv6 addresses may include an %interface scope-id, eg
fe80::202:a412:4512:7bbf%eth0.
The optional string after the @ character tells dnsmasq how to set the source of
@@ -597,7 +598,7 @@ hosts files), from DHCP, from --interface-name or from another
.B --cname.
If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it
is permissable to have more than one cname pointing to the same target. Indeed
is permissible to have more than one cname pointing to the same target. Indeed
it's possible to declare multiple cnames to a target in a single line, like so:
.B --cname=cname1,cname2,target
@@ -625,13 +626,16 @@ address by repeating the flag; in that case the first instance is used
for the reverse address-to-name mapping. Note that a name used in
--interface-name may not appear in /etc/hosts.
.TP
.B --synth-domain=<domain>,<address range>[,<prefix>]
.B --synth-domain=<domain>,<address range>[,<prefix>[*]]
Create artificial A/AAAA and PTR records for an address range. The
records use the address, with periods (or colons for IPv6) replaced
with dashes.
records either seqential numbers or the address, with periods (or colons for IPv6) replaced with dashes.
An example should make this clearer.
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
An examples should make this clearer. First sequential numbers.
.B --synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-*
results in the name internal-0.thekelleys.org.uk. returning 192.168.0.50, internal-1.thekelleys.org.uk returning 192.168.0.51 and so on. (note the *) The same principle applies to IPv6 addresses (where the numbers may be very large). Reverse lookups from address to name behave as expected.
Second,
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal- (no *)
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
but IPv6 addresses may start with '::'
@@ -641,7 +645,7 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask>
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
.TP
.B --add-mac[=base64|text]
Add the MAC address of the requestor to DNS queries which are
@@ -655,7 +659,7 @@ given for --add-subnet applies to --add-mac too. An alternative encoding of the
MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter.
.TP
.B --add-cpe-id=<string>
Add a arbitrary identifying string to o DNS queries which are
Add an arbitrary identifying string to o DNS queries which are
forwarded upstream.
.TP
.B --add-subnet[[=[<IPv4 address>/]<IPv4 prefix length>][,[<IPv6 address>/]<IPv6 prefix length>]]
@@ -715,8 +719,8 @@ is set and the upstream servers don't support DNSSEC, then DNS service will be e
.TP
.B --trust-anchor=[<class>],<domain>,<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 Zone Signing
key(s) of the root zone,
validation. 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
.TP
@@ -736,10 +740,14 @@ section on
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGINT. The intention is
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
which have not been throughly checked.
reliable time is established, a SIGINT should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
which have not been thoroughly checked.
Earlier versions of dnsmasq overloaded SIGHUP (which re-reads much configuration) to also enable time validation.
If dnsmasq is run in debug mode (-d flag) then SIGINT retains its usual meaning of terminating the dnsmasq process.
.TP
.B --dnssec-timestamp=<path>
Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the
@@ -1021,6 +1029,8 @@ dhcp-host directive (or one implied by /etc/ethers) then the special
tag "known" is set. This allows dnsmasq to be configured to
ignore requests from unknown machines using
.B --dhcp-ignore=tag:!known
If the host matches only a dhcp-host directive which cannot
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
@@ -1071,7 +1081,7 @@ in a dhcp-optsfile.
This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP.
If a file is deleted for changed after it has been read by dnsmasq, then the
If a file is deleted or changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq receives a SIGHUP, or
is restarted; ie host records are only added dynamically.
.TP
@@ -1313,7 +1323,7 @@ Perform boolean operations on tags. Any tag appearing as set:<tag> is set if
all the tags which appear as tag:<tag> are set, (or unset when tag:!<tag> is used)
If no tag:<tag> appears set:<tag> tags are set unconditionally.
Any number of set: and tag: forms may appear, in any order.
Tag-if lines ares executed in order, so if the tag in tag:<tag> is a
Tag-if lines are executed in order, so if the tag in tag:<tag> is a
tag set by another
.B tag-if,
the line which sets the tag must precede the one which tests it.
@@ -1689,13 +1699,17 @@ option also forces the leasechange script to be called on changes
to the client-id and lease length and expiry time.
.TP
.B --bridge-interface=<interface>,<alias>[,<alias>]
Treat DHCP (v4 and v6) request and IPv6 Router Solicit packets
Treat DHCP (v4 and v6) requests and IPv6 Router Solicit packets
arriving at any of the <alias> interfaces as if they had arrived at
<interface>. This option allows dnsmasq to provide DHCP and RA
service over unaddressed and unbridged Ethernet interfaces, e.g. on an
OpenStack compute host where each such interface is a TAP interface to
a VM, or as in "old style bridging" on BSD platforms. A trailing '*'
wildcard can be used in each <alias>.
It is permissible to add more than one alias using more than one --bridge-interface option since
--bridge-interface=int1,alias1,alias2 is exactly equivalent to
--bridge-interface=int1,alias1 --bridge-interface=int1,alias2
.TP
.B \-s, --domain=<domain>[,<address range>[,local]]
Specifies DNS domains for the DHCP server. Domains may be be given
@@ -1977,7 +1991,7 @@ and
.PP
Dnsmasq is a DNS query forwarder: it it not capable of recursively
Dnsmasq is a DNS query forwarder: it is not capable of recursively
answering arbitrary queries starting from the root servers but
forwards such queries to a fully recursive upstream DNS server which is
typically provided by an ISP. By default, dnsmasq reads
@@ -2046,7 +2060,7 @@ include set:<tag>, including one from the
.B dhcp-range
used to allocate the address, one from any matching
.B dhcp-host
(and "known" if a dhcp-host matches)
(and "known" or "known-othernet" if a dhcp-host matches)
The tag "bootp" is set for BOOTP requests, and a tag whose name is the
name of the interface on which the request arrived is also set.

1099
po/de.po

File diff suppressed because it is too large Load Diff

1042
po/es.po

File diff suppressed because it is too large Load Diff

1050
po/fi.po

File diff suppressed because it is too large Load Diff

1014
po/fr.po

File diff suppressed because it is too large Load Diff

1079
po/id.po

File diff suppressed because it is too large Load Diff

1050
po/it.po

File diff suppressed because it is too large Load Diff

1072
po/no.po

File diff suppressed because it is too large Load Diff

1018
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1072
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -125,7 +125,7 @@ address of its ethernet card. For the former to work, a machine needs to know it
requests a DHCP lease. For dhcpcd, the -h option specifies this. The
names may be anything as far as DHCP is concerned, but dnsmasq adds
some limitations. By default the names must no have a domain part, ie
they must just be a alphanumeric name, without any dots. This is a
they must just be alphanumeric names, without any dots. This is a
security feature to stop a machine on your network telling DHCP that
its name is "www.microsoft.com" and thereby grabbing traffic which
shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -119,11 +119,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
struct cname *a, *candidate;
unsigned int wclen;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(((char *)header) + qlen, 0,
(limit - ((char *)header)) - qlen);
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
@@ -597,12 +592,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
char *p = name;
if (subnet->prefixlen >= 24)
p += sprintf(p, "%d.", a & 0xff);
p += sprintf(p, "%u.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%d.", a & 0xff);
p += sprintf(p, "%u.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
}
#ifdef HAVE_IPV6

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ static void blockdata_expand(int n)
{
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
if (n > 0 && new)
if (new)
{
int i;
@@ -49,7 +49,7 @@ void blockdata_init(void)
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
if (option_bool(OPT_DNSSEC_VALID))
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
blockdata_expand(daemon->cachesize);
}
void blockdata_report(void)
@@ -100,6 +100,7 @@ struct blockdata *blockdata_alloc(char *data, size_t len)
return ret;
}
void blockdata_free(struct blockdata *blocks)
{
struct blockdata *tmp;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,6 +45,7 @@ static const struct {
{ 24, "SIG" },
{ 25, "KEY" },
{ 28, "AAAA" },
{ 29, "LOC" },
{ 33, "SRV" },
{ 35, "NAPTR" },
{ 36, "KX" },
@@ -57,6 +58,10 @@ static const struct {
{ 47, "NSEC" },
{ 48, "DNSKEY" },
{ 50, "NSEC3" },
{ 51, "NSEC3PARAM" },
{ 52, "TLSA" },
{ 53, "SMIMEA" },
{ 55, "HIP" },
{ 249, "TKEY" },
{ 250, "TSIG" },
{ 251, "IXFR" },
@@ -1511,7 +1516,7 @@ void dump_cache(time_t now)
/* ctime includes trailing \n - eat it */
*(p-1) = 0;
#endif
my_syslog(LOG_INFO, daemon->namebuff);
my_syslog(LOG_INFO, "%s", daemon->namebuff);
}
}
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 20 /* or 20 seconds */
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
@@ -94,10 +95,10 @@ HAVE_DBUS
servers via DBus.
HAVE_IDN
define this if you want international domain name support.
NOTE: for backwards compatibility, IDN support is automatically
included when internationalisation support is built, using the
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
define this if you want international domain name 2003 support.
HAVE_LIBIDN2
define this if you want international domain name 2008 support.
HAVE_CONNTRACK
define this to include code which propagates conntrack marks from
@@ -136,9 +137,6 @@ NO_INOTIFY
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
NO_NETTLE_ECC
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
NO_GMP
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
@@ -177,6 +175,7 @@ RESOLVFILE
/* #define HAVE_LUASCRIPT */
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_LIBIDN2 */
/* #define HAVE_CONNTRACK */
/* #define HAVE_DNSSEC */
@@ -396,10 +395,14 @@ static char *compile_opts =
"no-"
#endif
"i18n "
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
#if defined(HAVE_LIBIDN2)
"IDN2 "
#else
#if !defined(HAVE_IDN)
"no-"
#endif
"IDN "
#endif
"IDN "
#endif
#ifndef HAVE_DHCP
"no-"
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

460
src/crypto.c Normal file
View File

@@ -0,0 +1,460 @@
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DNSSEC
#include <nettle/rsa.h>
#include <nettle/dsa.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#include <nettle/eddsa.h>
#include <nettle/nettle-meta.h>
#include <nettle/bignum.h>
/* Implement a "hash-function" to the nettle API, which simply returns
the input data, concatenated into a single, statically maintained, buffer.
Used for the EdDSA sigs, which operate on the whole message, rather
than a digest. */
struct null_hash_digest
{
uint8_t *buff;
size_t len;
};
struct null_hash_ctx
{
size_t len;
};
static size_t null_hash_buff_sz = 0;
static uint8_t *null_hash_buff = NULL;
#define BUFF_INCR 128
static void null_hash_init(void *ctx)
{
((struct null_hash_ctx *)ctx)->len = 0;
}
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
{
struct null_hash_ctx *ctx = ctxv;
size_t new_len = ctx->len + length;
if (new_len > null_hash_buff_sz)
{
uint8_t *new;
if (!(new = whine_malloc(new_len + BUFF_INCR)))
return;
if (null_hash_buff)
{
if (ctx->len != 0)
memcpy(new, null_hash_buff, ctx->len);
free(null_hash_buff);
}
null_hash_buff_sz = new_len + BUFF_INCR;
null_hash_buff = new;
}
memcpy(null_hash_buff + ctx->len, src, length);
ctx->len += length;
}
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
{
(void)length;
((struct null_hash_digest *)dst)->buff = null_hash_buff;
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
}
static struct nettle_hash null_hash = {
"null_hash",
sizeof(struct null_hash_ctx),
sizeof(struct null_hash_digest),
0,
(nettle_hash_init_func *) null_hash_init,
(nettle_hash_update_func *) null_hash_update,
(nettle_hash_digest_func *) null_hash_digest
};
/* Find pointer to correct hash function in nettle library */
const struct nettle_hash *hash_find(char *name)
{
if (!name)
return NULL;
/* We provide a "null" hash which returns the input data as digest. */
if (strcmp(null_hash.name, name) == 0)
return &null_hash;
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library
versions. It also #defines nettle_hashes, so use that to tell
if we have the new facilities. */
#ifdef nettle_hashes
return nettle_lookup_hash(name);
#else
{
int i;
for (i = 0; nettle_hashes[i]; i++)
if (strcmp(nettle_hashes[i]->name, name) == 0)
return nettle_hashes[i];
}
return NULL;
#endif
}
/* expand ctx and digest memory allocations if necessary and init hash function */
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
{
static void *ctx = NULL;
static unsigned char *digest = NULL;
static unsigned int ctx_sz = 0;
static unsigned int digest_sz = 0;
void *new;
if (ctx_sz < hash->context_size)
{
if (!(new = whine_malloc(hash->context_size)))
return 0;
if (ctx)
free(ctx);
ctx = new;
ctx_sz = hash->context_size;
}
if (digest_sz < hash->digest_size)
{
if (!(new = whine_malloc(hash->digest_size)))
return 0;
if (digest)
free(digest);
digest = new;
digest_sz = hash->digest_size;
}
*ctxp = ctx;
*digestp = digest;
hash->init(ctx);
return 1;
}
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
size_t exp_len;
static struct rsa_public_key *key = NULL;
static mpz_t sig_mpz;
(void)digest_len;
if (key == NULL)
{
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
return 0;
nettle_rsa_public_key_init(key);
mpz_init(sig_mpz);
}
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
key_len--;
if ((exp_len = *p++) == 0)
{
GETSHORT(exp_len, p);
key_len -= 2;
}
if (exp_len >= key_len)
return 0;
key->size = key_len - exp_len;
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
switch (algo)
{
case 1:
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
case 5: case 7:
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
case 8:
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
case 10:
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
}
return 0;
}
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
unsigned int t;
static mpz_t y;
static struct dsa_params *params = NULL;
static struct dsa_signature *sig_struct;
(void)digest_len;
if (params == NULL)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
!(params = whine_malloc(sizeof(struct dsa_params))))
return 0;
mpz_init(y);
nettle_dsa_params_init(params);
nettle_dsa_signature_init(sig_struct);
}
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
t = *p++;
if (key_len < (213 + (t * 24)))
return 0;
mpz_import(params->q, 20, 1, 1, 0, 0, p); p += 20;
mpz_import(params->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(params->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
(void)algo;
return nettle_dsa_verify(params, y, digest_len, digest, sig_struct);
}
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
unsigned int t;
struct ecc_point *key;
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
if (!sig_struct)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
return 0;
nettle_dsa_signature_init(sig_struct);
mpz_init(x);
mpz_init(y);
}
switch (algo)
{
case 13:
if (!key_256)
{
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
}
key = key_256;
t = 32;
break;
case 14:
if (!key_384)
{
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
}
key = key_384;
t = 48;
break;
default:
return 0;
}
if (sig_len != 2*t || key_len != 2*t ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
mpz_import(x, t , 1, 1, 0, 0, p);
mpz_import(y, t , 1, 1, 0, 0, p + t);
if (!ecc_point_set(key, x, y))
return 0;
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
}
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
if (key_len != ED25519_KEY_SIZE ||
sig_len != ED25519_SIGNATURE_SIZE ||
digest_len != sizeof(struct null_hash_digest) ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
which has a pointer to the actual data and a length, because the buffer
may need to be extended during "hashing". */
switch (algo)
{
case 15:
return ed25519_sha512_verify(p,
((struct null_hash_digest *)digest)->len,
((struct null_hash_digest *)digest)->buff,
sig);
case 16:
/* Ed448 when available */
return 0;
}
return 0;
}
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
/* Enure at runtime that we have support for this digest */
if (!hash_find(algo_digest_name(algo)))
return NULL;
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
switch (algo)
{
case 1: case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify;
case 3: case 6:
return dnsmasq_dsa_verify;
case 13: case 14:
return dnsmasq_ecdsa_verify;
case 15: case 16:
return dnsmasq_eddsa_verify;
}
return NULL;
}
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo);
func = verify_func(algo);
if (!func)
return 0;
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
}
/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
define which algo numbers we support. If algo_digest_name() returns
non-NULL for an algorithm number, we assume that algorithm is
supported by verify(). */
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
char *ds_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
case 2: return "sha256";
case 3: return "gosthash94";
case 4: return "sha384";
default: return NULL;
}
}
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
char *algo_digest_name(int algo)
{
switch (algo)
{
case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
case 2: return NULL; /* Diffie-Hellman */
case 3: return "sha1"; /* DSA/SHA1 */
case 5: return "sha1"; /* RSA/SHA1 */
case 6: return "sha1"; /* DSA-NSEC3-SHA1 */
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
case 8: return "sha256"; /* RSA/SHA-256 */
case 10: return "sha512"; /* RSA/SHA-512 */
case 12: return NULL; /* ECC-GOST */
case 13: return "sha256"; /* ECDSAP256SHA256 */
case 14: return "sha384"; /* ECDSAP384SHA384 */
case 15: return "null_hash"; /* ED25519 */
case 16: return NULL; /* ED448 */
default: return NULL;
}
}
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
char *nsec3_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
default: return NULL;
}
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -485,11 +485,8 @@ char *whichdevice(void)
void bindtodevice(char *device, int fd)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, device);
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, IFNAMSIZ) == -1 &&
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -145,7 +145,7 @@ void dhcp_packet(time_t now, int pxe_fd)
struct cmsghdr *cmptr;
struct iovec iov;
ssize_t sz;
int iface_index = 0, unicast_dest = 0, is_inform = 0;
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
int rcvd_iface_index;
struct in_addr iface_addr;
struct iface_param parm;
@@ -223,9 +223,13 @@ void dhcp_packet(time_t now, int pxe_fd)
}
#endif
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
return;
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
#ifdef HAVE_LINUX_NETWORK
/* ARP fiddling uses original interface even if we pretend to use a different one. */
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
@@ -269,8 +273,8 @@ void dhcp_packet(time_t now, int pxe_fd)
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
{
/* Reply from server, using us as relay. */
iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
rcvd_iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
return;
is_relay_reply = 1;
iov.iov_len = sz;
@@ -331,7 +335,7 @@ void dhcp_packet(time_t now, int pxe_fd)
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
return;
/* May have configured relay, but not DHCP server */
@@ -340,7 +344,7 @@ void dhcp_packet(time_t now, int pxe_fd)
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr, recvtime);
now, unicast_dest, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
lease_update_file(now);
lease_update_dns(0);
@@ -647,7 +651,7 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
This wrapper handles a cache and load-limiting.
Return is NULL is address in use, or a pointer to a cache entry
recording that it isn't. */
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash)
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
{
static struct ping_result dummy;
struct ping_result *r, *victim = NULL;
@@ -671,9 +675,9 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
}
/* didn't find cached entry */
if ((count >= max) || option_bool(OPT_NO_PING))
if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
{
/* overloaded, or configured not to check, return "not in use" */
/* overloaded, or configured not to check, loopback interface, return "not in use" */
dummy.hash = 0;
return &dummy;
}
@@ -705,7 +709,7 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now)
struct dhcp_netid *netids, time_t now, int loopback)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -763,7 +767,7 @@ int address_allocate(struct dhcp_context *context,
{
struct ping_result *r;
if ((r = do_icmp_ping(now, addr, j)))
if ((r = do_icmp_ping(now, addr, j, loopback)))
{
/* consec-ip mode: we offered this address for another client
(different hash) recently, don't offer it to this one. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
#define NAMESERVER_PORT 53
#define TFTP_PORT 69
#define MIN_PORT 1024 /* first non-reserved port */
#define MAX_PORT 65535u
#define IN6ADDRSZ 16

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -48,6 +48,7 @@ int main (int argc, char **argv)
long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL;
int log_err;
int chown_warn = 0;
#if defined(HAVE_LINUX_NETWORK)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
@@ -77,7 +78,8 @@ int main (int argc, char **argv)
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL);
sigaction(SIGCHLD, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
/* ignore SIGPIPE */
sigact.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sigact, NULL);
@@ -118,6 +120,9 @@ int main (int argc, char **argv)
daemon->namebuff = safe_malloc(MAXDNAME * 2);
daemon->keyname = safe_malloc(MAXDNAME * 2);
daemon->workspacename = safe_malloc(MAXDNAME * 2);
/* one char flag per possible RR in answer section (may get extended). */
daemon->rr_status_sz = 64;
daemon->rr_status = safe_malloc(daemon->rr_status_sz);
}
#endif
@@ -220,9 +225,6 @@ int main (int argc, char **argv)
die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
#endif
if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
daemon->min_port = 1024u;
if (daemon->max_port < daemon->min_port)
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
@@ -358,7 +360,8 @@ int main (int argc, char **argv)
}
#ifdef HAVE_INOTIFY
if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
&& (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
inotify_dnsmasq_init();
else
daemon->inotifyfd = -1;
@@ -386,10 +389,12 @@ int main (int argc, char **argv)
daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript))
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
struct passwd *scr_pw;
if ((scr_pw = getpwnam(daemon->scriptuser)))
{
script_uid = ent_pw->pw_uid;
script_gid = ent_pw->pw_gid;
script_uid = scr_pw->pw_uid;
script_gid = scr_pw->pw_gid;
}
else
baduser = daemon->scriptuser;
@@ -537,9 +542,18 @@ int main (int argc, char **argv)
}
else
{
/* We're still running as root here. Change the ownership of the PID file
to the user we will be running as. Note that this is not to allow
us to delete the file, since that depends on the permissions
of the directory containing the file. That directory will
need to by owned by the dnsmasq user, and the ownership of the
file has to match, to keep systemd >273 happy. */
if (getuid() == 0 && ent_pw && ent_pw->pw_uid != 0 && fchown(fd, ent_pw->pw_uid, ent_pw->pw_gid) == -1)
chown_warn = errno;
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
err = 1;
else
else
{
while (retry_send(close(fd)));
if (errno != 0)
@@ -726,6 +740,9 @@ int main (int argc, char **argv)
}
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
if (chown_warn != 0)
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
#ifdef HAVE_DBUS
if (option_bool(OPT_DBUS))
@@ -755,7 +772,7 @@ int main (int argc, char **argv)
daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until receipt of SIGINT"));
if (rc == 1)
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
@@ -1079,7 +1096,7 @@ static void sig_handler(int sig)
{
/* ignore anything other than TERM during startup
and in helper proc. (helper ignore TERM too) */
if (sig == SIGTERM)
if (sig == SIGTERM || sig == SIGINT)
exit(EC_MISC);
}
else if (pid != getpid())
@@ -1105,6 +1122,15 @@ static void sig_handler(int sig)
event = EVENT_DUMP;
else if (sig == SIGUSR2)
event = EVENT_REOPEN;
else if (sig == SIGINT)
{
/* Handle SIGINT normally in debug mode, so
ctrl-c continues to operate. */
if (option_bool(OPT_DEBUG))
exit(EC_MISC);
else
event = EVENT_TIME;
}
else
return;
@@ -1187,31 +1213,40 @@ static void fatal_event(struct event_desc *ev, char *msg)
case EVENT_FORK_ERR:
die(_("cannot fork into background: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_CAP_ERR:
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_USER_ERR:
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
/* fall through */
case EVENT_GROUP_ERR:
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
/* fall through */
case EVENT_PIDFILE:
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
/* fall through */
case EVENT_LOG_ERR:
die(_("cannot open log %s: %s"), msg, EC_FILE);
/* fall through */
case EVENT_LUA_ERR:
die(_("failed to load Lua script: %s"), msg, EC_MISC);
/* fall through */
case EVENT_TFTP_ERR:
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
/* fall through */
case EVENT_TIME_ERR:
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
}
@@ -1232,14 +1267,7 @@ static void async_event(int pipe, time_t now)
{
case EVENT_RELOAD:
daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
#ifdef HAVE_DNSSEC
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
daemon->dnssec_no_time_check = 0;
}
#endif
/* fall through */
case EVENT_INIT:
@@ -1348,6 +1376,17 @@ static void async_event(int pipe, time_t now)
poll_resolv(0, 1, now);
break;
case EVENT_TIME:
#ifdef HAVE_DNSSEC
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
daemon->dnssec_no_time_check = 0;
clear_cache_and_reload(now);
}
#endif
break;
case EVENT_TERM:
/* Knock all our children on the head. */
for (i = 0; i < MAX_PROCS; i++)
@@ -1375,7 +1414,7 @@ static void async_event(int pipe, time_t now)
/* update timestamp file on TERM if time is considered valid */
if (daemon->back_to_the_future)
{
if (utime(daemon->timestamp_file, NULL) == -1)
if (utimes(daemon->timestamp_file, NULL) == -1)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
}
#endif
@@ -1472,9 +1511,6 @@ void clear_cache_and_reload(time_t now)
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();
reread_dhcp();
#ifdef HAVE_INOTIFY
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
#endif
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,7 +14,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2016 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2018 Simon Kelley"
/* We do defines that influence behavior of stdio.h, so complain
if included too early. */
#ifdef _STDIO_H
# error "Header file stdio.h included too early!"
#endif
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
@@ -117,7 +123,6 @@ typedef unsigned long long u64;
#include <sys/uio.h>
#include <syslog.h>
#include <dirent.h>
#include <utime.h>
#ifndef HAVE_LINUX_NETWORK
# include <net/if_dl.h>
#endif
@@ -137,6 +142,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
#include <priv.h>
#endif
#ifdef HAVE_DNSSEC
# include <nettle/nettle-meta.h>
#endif
/* daemon is function in the C library.... */
#define daemon dnsmasq_daemon
@@ -170,6 +179,7 @@ struct event_desc {
#define EVENT_NEWROUTE 23
#define EVENT_TIME_ERR 24
#define EVENT_SCRIPT_LOG 25
#define EVENT_TIME 26
/* Exit codes. */
#define EC_GOOD 0
@@ -447,6 +457,7 @@ struct crec {
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
#define F_NOEXTRA (1u<<27)
#define F_SERVFAIL (1u<<28)
/* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0
@@ -509,6 +520,7 @@ struct server {
struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd, edns_pktsz;
time_t pktsz_reduced;
unsigned int queries, failed_queries;
#ifdef HAVE_LOOP
u32 uid;
@@ -827,7 +839,7 @@ struct cond_domain {
#ifdef HAVE_IPV6
struct in6_addr start6, end6;
#endif
int is6;
int is6, indexed;
struct cond_domain *next;
};
@@ -1020,6 +1032,8 @@ extern struct daemon {
#ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */
char *rr_status; /* flags for individual RRs */
int rr_status_sz;
#endif
unsigned int local_answer, queries_forwarded, auth_answer;
struct frec *frec_list;
@@ -1131,18 +1145,18 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep);
size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags,
unsigned long local_ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
time_t now, char **ipsets, int is_sign, int checkrebind,
int no_cache, int secure, int *doctored);
unsigned long ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, char **ipsets, int is_sign, int check_rebind,
int no_cache_dnssec, int secure, int *doctored);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now);
struct bogus_addr *baddr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
int check_for_local_domain(char *name, time_t now);
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
@@ -1164,23 +1178,32 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
/* dnssec.c */
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
int check_unsigned, int *neganswer, int *nons);
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
size_t filter_rrsigs(struct dns_header *header, size_t plen);
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
int setup_timestamp(void);
/* crypto.c */
const struct nettle_hash *hash_find(char *name);
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo);
char *ds_digest_name(int digest);
char *algo_digest_name(int algo);
char *nsec3_digest_name(int digest);
/* util.c */
void rand_init(void);
unsigned short rand16(void);
u32 rand32(void);
u64 rand64(void);
int legal_hostname(char *c);
char *canonicalise(char *s, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
int legal_hostname(char *name);
char *canonicalise(char *in, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
void *safe_malloc(size_t size);
void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
@@ -1213,7 +1236,9 @@ int wildcard_matchn(const char* wildcard, const char* match, int num);
void die(char *message, char *arg1, int exit_code);
int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...);
void set_log_writer(void);
void check_log_writer(int force);
void flush_log(void);
@@ -1241,13 +1266,13 @@ struct frec *get_new_frec(time_t now, int *wait, int force);
int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source,
unsigned int iface);
void resend_query();
void resend_query(void);
struct randfd *allocate_rfd(int family);
void free_rfd(struct randfd *rfd);
/* network.c */
int indextoname(int fd, int index, char *name);
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
@@ -1261,12 +1286,12 @@ void add_update_server(int flags,
void check_servers(void);
int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
void create_bound_listeners(int dienow);
void warn_bound_listeners(void);
void warn_wild_labels(void);
void warn_int_names(void);
int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int iface_check(int family, struct all_addr *addr, char *name, int *auth);
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd);
@@ -1287,16 +1312,16 @@ void newaddress(time_t now);
void dhcp_init(void);
void dhcp_packet(time_t now, int pxe_fd);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct in_addr taddr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr,
unsigned int hash);
unsigned int hash, int loopback);
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
struct dhcp_netid *netids, time_t now, int loopback);
void dhcp_read_ethers(void);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *host_from_dns(struct in_addr addr);
@@ -1345,7 +1370,8 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback, time_t recvtime);
size_t sz, time_t now, int unicast_dest, int loopback,
int *is_inform, int pxe, struct in_addr fallback, time_t recvtime);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
@@ -1460,10 +1486,10 @@ unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arriva
#ifdef HAVE_DHCP
void dhcp_common_init(void);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags);
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
struct dhcp_opt *opts);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded);
char *strip_hostname(char *hostname);
void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
@@ -1521,13 +1547,13 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
/* loop.c */
#ifdef HAVE_LOOP
void loop_send_probes();
void loop_send_probes(void);
int detect_loop(char *query, int type);
#endif
/* inotify.c */
#ifdef HAVE_INOTIFY
void inotify_dnsmasq_init();
void inotify_dnsmasq_init(void);
int inotify_check(time_t now);
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#endif

View File

@@ -1,5 +1,5 @@
/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
and Copyright (c) 2012-2016 Simon Kelley
and Copyright (c) 2012-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,332 +19,11 @@
#ifdef HAVE_DNSSEC
#include <nettle/rsa.h>
#include <nettle/dsa.h>
#ifndef NO_NETTLE_ECC
# include <nettle/ecdsa.h>
# include <nettle/ecc-curve.h>
#endif
#include <nettle/nettle-meta.h>
#include <nettle/bignum.h>
/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
to detect Nettle-3, and invoke the backwards compatibility mode. */
#ifdef dsa_params_init
#include <nettle/dsa-compat.h>
#endif
#define SERIAL_UNDEF -100
#define SERIAL_EQ 0
#define SERIAL_LT -1
#define SERIAL_GT 1
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
static char *ds_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
case 2: return "sha256";
case 3: return "gosthash94";
case 4: return "sha384";
default: return NULL;
}
}
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
static char *algo_digest_name(int algo)
{
switch (algo)
{
case 1: return "md5";
case 3: return "sha1";
case 5: return "sha1";
case 6: return "sha1";
case 7: return "sha1";
case 8: return "sha256";
case 10: return "sha512";
case 12: return "gosthash94";
case 13: return "sha256";
case 14: return "sha384";
default: return NULL;
}
}
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
static char *nsec3_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
default: return NULL;
}
}
/* Find pointer to correct hash function in nettle library */
static const struct nettle_hash *hash_find(char *name)
{
int i;
if (!name)
return NULL;
for (i = 0; nettle_hashes[i]; i++)
{
if (strcmp(nettle_hashes[i]->name, name) == 0)
return nettle_hashes[i];
}
return NULL;
}
/* expand ctx and digest memory allocations if necessary and init hash function */
static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
{
static void *ctx = NULL;
static unsigned char *digest = NULL;
static unsigned int ctx_sz = 0;
static unsigned int digest_sz = 0;
void *new;
if (ctx_sz < hash->context_size)
{
if (!(new = whine_malloc(hash->context_size)))
return 0;
if (ctx)
free(ctx);
ctx = new;
ctx_sz = hash->context_size;
}
if (digest_sz < hash->digest_size)
{
if (!(new = whine_malloc(hash->digest_size)))
return 0;
if (digest)
free(digest);
digest = new;
digest_sz = hash->digest_size;
}
*ctxp = ctx;
*digestp = digest;
hash->init(ctx);
return 1;
}
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
size_t exp_len;
static struct rsa_public_key *key = NULL;
static mpz_t sig_mpz;
(void)digest_len;
if (key == NULL)
{
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
return 0;
nettle_rsa_public_key_init(key);
mpz_init(sig_mpz);
}
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
key_len--;
if ((exp_len = *p++) == 0)
{
GETSHORT(exp_len, p);
key_len -= 2;
}
if (exp_len >= key_len)
return 0;
key->size = key_len - exp_len;
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
switch (algo)
{
case 1:
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
case 5: case 7:
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
case 8:
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
case 10:
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
}
return 0;
}
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
unsigned int t;
static struct dsa_public_key *key = NULL;
static struct dsa_signature *sig_struct;
(void)digest_len;
if (key == NULL)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
!(key = whine_malloc(sizeof(struct dsa_public_key))))
return 0;
nettle_dsa_public_key_init(key);
nettle_dsa_signature_init(sig_struct);
}
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
t = *p++;
if (key_len < (213 + (t * 24)))
return 0;
mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
(void)algo;
return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
}
#ifndef NO_NETTLE_ECC
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
unsigned int t;
struct ecc_point *key;
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
if (!sig_struct)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
return 0;
nettle_dsa_signature_init(sig_struct);
mpz_init(x);
mpz_init(y);
}
switch (algo)
{
case 13:
if (!key_256)
{
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
}
key = key_256;
t = 32;
break;
case 14:
if (!key_384)
{
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
}
key = key_384;
t = 48;
break;
default:
return 0;
}
if (sig_len != 2*t || key_len != 2*t ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
mpz_import(x, t , 1, 1, 0, 0, p);
mpz_import(y, t , 1, 1, 0, 0, p + t);
if (!ecc_point_set(key, x, y))
return 0;
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
}
#endif
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
/* Enure at runtime that we have support for this digest */
if (!hash_find(algo_digest_name(algo)))
return NULL;
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
switch (algo)
{
case 1: case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify;
case 3: case 6:
return dnsmasq_dsa_verify;
#ifndef NO_NETTLE_ECC
case 13: case 14:
return dnsmasq_ecdsa_verify;
#endif
}
return NULL;
}
static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo);
func = verify_func(algo);
if (!func)
return 0;
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
}
/* Convert from presentation format to wire format, in place.
Also map UC -> LC.
Note that using extract_name to get presentation format
@@ -424,15 +103,17 @@ static void from_wire(char *name)
static int count_labels(char *name)
{
int i;
char *p;
if (*name == 0)
return 0;
for (i = 0; *name; name++)
if (*name == '.')
for (p = name, i = 0; *p; p++)
if (*p == '.')
i++;
return i+1;
/* Don't count empty first label. */
return *name == '.' ? i : i+1;
}
/* Implement RFC1982 wrapped compare for 32-bit numbers */
@@ -475,7 +156,7 @@ int setup_timestamp(void)
if (difftime(timestamp_time, time(0)) <= 0)
{
/* time already OK, update timestamp, and do key checking from the start. */
if (utime(daemon->timestamp_file, NULL) == -1)
if (utimes(daemon->timestamp_file, NULL) == -1)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
daemon->back_to_the_future = 1;
return 0;
@@ -489,12 +170,14 @@ int setup_timestamp(void)
int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
if (fd != -1)
{
struct utimbuf timbuf;
struct timeval tv[2];
close(fd);
timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
if (utime(daemon->timestamp_file, &timbuf) == 0)
timestamp_time = 1420070400; /* 1-1-2015 */
tv[0].tv_sec = tv[1].tv_sec = timestamp_time;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(daemon->timestamp_file, tv) == 0)
goto check_and_exit;
}
}
@@ -519,7 +202,7 @@ static int check_date_range(u32 date_start, u32 date_end)
{
if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
{
if (utime(daemon->timestamp_file, NULL) != 0)
if (utimes(daemon->timestamp_file, NULL) != 0)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
@@ -596,10 +279,10 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
*/
static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
unsigned char **rrset, char *buff1, char *buff2)
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
unsigned char **rrset, char *buff1, char *buff2)
{
int swap, quit, i;
int swap, quit, i, j;
do
{
@@ -661,11 +344,21 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
rrset[i] = tmp;
swap = quit = 1;
}
else if (rc == 0 && quit && len1 == len2)
{
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
for (j = i+1; j < rrsetidx-1; j++)
rrset[j] = rrset[j+1];
rrsetidx--;
i--;
}
else if (rc < 0)
quit = 1;
}
}
} while (swap);
return rrsetidx;
}
static unsigned char **rrset = NULL, **sigs = NULL;
@@ -810,7 +503,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
/* Sort RRset records into canonical order.
Note that at this point keyname and daemon->workspacename buffs are
unused, and used as workspace by the sort. */
sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
/* Now try all the sigs to try and find one which validates */
for (j = 0; j <sigidx; j++)
@@ -864,6 +557,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
u16 len, *dp;
p = rrset[i];
if (!extract_name(header, plen, &p, name, 1, 10))
return STAT_BOGUS;
@@ -1118,7 +812,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
{
a.addr.log.keytag = keytag;
a.addr.log.algo = algo;
if (verify_func(algo))
if (algo_digest_name(algo))
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
@@ -1179,7 +873,6 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
rc = STAT_BOGUS;
else
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
/* Note dnssec_validate_reply() will have cached positive answers */
if (rc == STAT_INSECURE)
rc = STAT_BOGUS;
@@ -1246,7 +939,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
a.addr.log.keytag = keytag;
a.addr.log.algo = algo;
a.addr.log.digest = digest;
if (hash_find(ds_digest_name(digest)) && verify_func(algo))
if (ds_digest_name(digest) && algo_digest_name(algo))
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
@@ -1403,8 +1096,8 @@ static int hostname_cmp(const char *a, const char *b)
}
}
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
char *workspace1, char *workspace2, char *name, int type, int *nons)
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
char *workspace1_in, char *workspace2, char *name, int type, int *nons)
{
int i, rc, rdlen;
unsigned char *p, *psave;
@@ -1417,6 +1110,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
/* Find NSEC record that proves name doesn't exist */
for (i = 0; i < nsec_count; i++)
{
char *workspace1 = workspace1_in;
int sig_labels, name_labels;
p = nsecs[i];
if (!extract_name(header, plen, &p, workspace1, 1, 10))
return 0;
@@ -1425,7 +1121,27 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
psave = p;
if (!extract_name(header, plen, &p, workspace2, 1, 10))
return 0;
/* If NSEC comes from wildcard expansion, use original wildcard
as name for computation. */
sig_labels = *labels[i];
name_labels = count_labels(workspace1);
if (sig_labels < name_labels)
{
int k;
for (k = name_labels - sig_labels; k != 0; k--)
{
while (*workspace1 != '.' && *workspace1 != 0)
workspace1++;
if (k != 1 && *workspace1 == '.')
workspace1++;
}
workspace1--;
*workspace1 = '*';
}
rc = hostname_cmp(workspace1, name);
if (rc == 0)
@@ -1451,8 +1167,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
return 0;
/* If the SOA bit is set for a DS record, then we have the
DS from the wrong side of the delegation. */
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
DS from the wrong side of the delegation. For the root DS,
this is expected. */
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
return 0;
}
@@ -1557,7 +1274,7 @@ static int base32_decode(char *in, unsigned char *out)
}
static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
{
int i, hash_len, salt_len, base32_len, rdlen, flags;
unsigned char *p, *psave;
@@ -1612,8 +1329,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
return 0;
/* If the SOA bit is set for a DS record, then we have the
DS from the wrong side of the delegation. */
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
DS from the wrong side of the delegation. For the root DS,
this is expected. */
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
return 0;
}
@@ -1754,7 +1472,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
return 0;
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons, count_labels(name)))
return 1;
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
@@ -1799,7 +1517,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
return 0;
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
return 0;
/* Finally, check that there's no seat of wildcard synthesis */
@@ -1814,7 +1532,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
return 0;
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
return 0;
}
@@ -1823,24 +1541,26 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
{
static unsigned char **nsecset = NULL;
static int nsecset_sz = 0;
static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
static int nsecset_sz = 0, rrsig_labels_sz = 0;
int type_found = 0;
unsigned char *p = skip_questions(header, plen);
unsigned char *auth_start, *p = skip_questions(header, plen);
int type, class, rdlen, i, nsecs_found;
/* Move to NS section */
if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
return 0;
auth_start = p;
for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
{
unsigned char *pstart = p;
if (!(p = skip_name(p, header, plen, 10)))
if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
return 0;
GETSHORT(type, p);
GETSHORT(class, p);
p += 4; /* TTL */
@@ -1857,7 +1577,69 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
return 0;
nsecset[nsecs_found++] = pstart;
if (type == T_NSEC)
{
/* If we're looking for NSECs, find the corresponding SIGs, to
extract the labels value, which we need in case the NSECs
are the result of wildcard expansion.
Note that the NSEC may not have been validated yet
so if there are multiple SIGs, make sure the label value
is the same in all, to avoid be duped by a rogue one.
If there are no SIGs, that's an error */
unsigned char *p1 = auth_start;
int res, j, rdlen1, type1, class1;
if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
return 0;
rrsig_labels[nsecs_found] = NULL;
for (j = ntohs(header->nscount); j != 0; j--)
{
if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
return 0;
GETSHORT(type1, p1);
GETSHORT(class1, p1);
p1 += 4; /* TTL */
GETSHORT(rdlen1, p1);
if (!CHECK_LEN(header, p1, plen, rdlen1))
return 0;
if (res == 1 && class1 == qclass && type1 == T_RRSIG)
{
int type_covered;
unsigned char *psav = p1;
if (rdlen1 < 18)
return 0; /* bad packet */
GETSHORT(type_covered, p1);
if (type_covered == T_NSEC)
{
p1++; /* algo */
/* labels field must be the same in every SIG we find. */
if (!rrsig_labels[nsecs_found])
rrsig_labels[nsecs_found] = p1;
else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
return 0;
}
p1 = psav;
}
if (!ADD_RDLEN(header, p1, plen, rdlen1))
return 0;
}
/* Must have found at least one sig. */
if (!rrsig_labels[nsecs_found])
return 0;
}
nsecset[nsecs_found++] = pstart;
}
if (!ADD_RDLEN(header, p, plen, rdlen))
@@ -1865,7 +1647,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
}
if (type_found == T_NSEC)
return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
else if (type_found == T_NSEC3)
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
else
@@ -1933,8 +1715,8 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
do
{
if (crecp->uid == (unsigned int)class &&
hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
verify_func(crecp->addr.ds.algo))
ds_digest_name(crecp->addr.ds.digest) &&
algo_digest_name(crecp->addr.ds.algo))
break;
}
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
@@ -1963,7 +1745,10 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
STAT_INSECURE at least one RRset not validated, because in unsigned zone.
STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
daemon->rr_status points to a char array which corressponds to the RRs in the
answer section (only). This is set to 1 for each RR which is validated, and 0 for any which aren't.
*/
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
int *class, int check_unsigned, int *neganswer, int *nons)
@@ -1972,9 +1757,25 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
static int target_sz = 0;
unsigned char *ans_start, *p1, *p2;
int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
int i, j, rc;
int secure = STAT_SECURE;
/* extend rr_status if necessary */
if (daemon->rr_status_sz < ntohs(header->ancount))
{
char *new = whine_malloc(ntohs(header->ancount) + 64);
if (!new)
return STAT_BOGUS;
free(daemon->rr_status);
daemon->rr_status = new;
daemon->rr_status_sz = ntohs(header->ancount) + 64;
}
memset(daemon->rr_status, 0, ntohs(header->ancount));
if (neganswer)
*neganswer = 0;
@@ -2031,7 +1832,10 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
{
if (!extract_name(header, plen, &p1, name, 1, 10))
if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
return STAT_BOGUS;
if (!extract_name(header, plen, &p1, name, 1, 10))
return STAT_BOGUS; /* bad packet */
GETSHORT(type1, p1);
@@ -2040,106 +1844,125 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
GETSHORT(rdlen1, p1);
/* Don't try and validate RRSIGs! */
if (type1 != T_RRSIG)
if (type1 == T_RRSIG)
continue;
/* Check if we've done this RRset already */
for (p2 = ans_start, j = 0; j < i; j++)
{
/* Check if we've done this RRset already */
for (p2 = ans_start, j = 0; j < i; j++)
{
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
return STAT_BOGUS; /* bad packet */
GETSHORT(type2, p2);
GETSHORT(class2, p2);
p2 += 4; /* TTL */
GETSHORT(rdlen2, p2);
if (type2 == type1 && class2 == class1 && rc == 1)
break; /* Done it before: name, type, class all match. */
if (!ADD_RDLEN(header, p2, plen, rdlen2))
return STAT_BOGUS;
}
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
return STAT_BOGUS; /* bad packet */
GETSHORT(type2, p2);
GETSHORT(class2, p2);
p2 += 4; /* TTL */
GETSHORT(rdlen2, p2);
if (type2 == type1 && class2 == class1 && rc == 1)
break; /* Done it before: name, type, class all match. */
if (!ADD_RDLEN(header, p2, plen, rdlen2))
return STAT_BOGUS;
}
if (j != i)
{
/* Done already: copy the validation status */
if (i < ntohs(header->ancount))
daemon->rr_status[i] = daemon->rr_status[j];
}
else
{
/* Not done, validate now */
if (j == i)
int sigcnt, rrcnt;
char *wildname;
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
return STAT_BOGUS;
/* No signatures for RRset. We can be configured to assume this is OK and return an INSECURE result. */
if (sigcnt == 0)
{
int sigcnt, rrcnt;
char *wildname;
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
return STAT_BOGUS;
/* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
if (sigcnt == 0)
if (check_unsigned)
{
if (check_unsigned)
{
rc = zone_status(name, class1, keyname, now);
if (rc == STAT_SECURE)
rc = STAT_BOGUS;
if (class)
*class = class1; /* Class for NEED_DS or NEED_KEY */
}
else
rc = STAT_INSECURE;
return rc;
rc = zone_status(name, class1, keyname, now);
if (rc == STAT_SECURE)
rc = STAT_BOGUS;
if (class)
*class = class1; /* Class for NEED_DS or NEED_KEY */
}
else
rc = STAT_INSECURE;
if (rc != STAT_INSECURE)
return rc;
}
else
{
/* explore_rrset() gives us key name from sigs in keyname.
Can't overwrite name here. */
strcpy(daemon->workspacename, keyname);
rc = zone_status(daemon->workspacename, class1, keyname, now);
if (rc != STAT_SECURE)
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
{
/* Zone is insecure, don't need to validate RRset */
if (class)
*class = class1; /* Class for NEED_DS or NEED_KEY */
return rc;
}
}
rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
{
if (class)
*class = class1; /* Class for DS or DNSKEY */
return rc;
}
else
/* Zone is insecure, don't need to validate RRset */
if (rc == STAT_SECURE)
{
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
{
if (class)
*class = class1; /* Class for DS or DNSKEY */
return rc;
}
/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
/* Note that RR is validated */
if (i < ntohs(header->ancount))
daemon->rr_status[i] = 1;
/* Note if we've validated either the answer to the question
or the target of a CNAME. Any not noted will need NSEC or
to be in unsigned space. */
for (j = 0; j <targetidx; j++)
if ((p2 = targets[j]))
{
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
int rc1;
if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
return STAT_BOGUS; /* bad packet */
if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
targets[j] = NULL;
}
/* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that
the genuine record doesn't exist. Check that here.
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
That's not a problem since if the RRsets later fail
we'll return BOGUS then. */
if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
/* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that
the genuine record doesn't exist. Check that here.
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
That's not a problem since if the RRsets later fail
we'll return BOGUS then. */
if (rc == STAT_SECURE_WILDCARD &&
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
return STAT_BOGUS;
rc = STAT_SECURE;
}
}
}
if (!ADD_RDLEN(header, p1, plen, rdlen1))
return STAT_BOGUS;
if (rc == STAT_INSECURE)
secure = STAT_INSECURE;
}
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
@@ -2173,7 +1996,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
}
}
return STAT_SECURE;
return secure;
}
@@ -2228,7 +2051,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
p = (unsigned char *)(header+1);
p = do_rfc1035_name(p, name);
p = do_rfc1035_name(p, name, NULL);
*p++ = 0;
PUTSHORT(type, p);
PUTSHORT(class, p);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,83 +55,133 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
if (pref && *pref != 0)
continue; /* prefix match fail */
/* NB, must not alter name if we return zero */
for (p = tail; *p; p++)
if (c->indexed)
{
char c = *p;
for (p = tail; *p; p++)
{
char c = *p;
if (c < '0' || c > '9')
break;
}
if ((c >='0' && c <= '9') || c == '-')
if (*p != '.')
continue;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
*p = 0;
if (hostname_isequal(c->domain, p+1))
{
if (prot == AF_INET)
{
unsigned int index = atoi(tail);
if (!c->is6 &&
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
{
addr->addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
found = 1;
}
}
#ifdef HAVE_IPV6
else
{
u64 index = atoll(tail);
if (c->is6 &&
index <= addr6part(&c->end6) - addr6part(&c->start6))
{
u64 start = addr6part(&c->start6);
addr->addr.addr6 = c->start6;
setaddr6part(&addr->addr.addr6, start + index);
found = 1;
}
}
#endif
break;
}
if (*p != '.')
continue;
*p = 0;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
{
/* special hack for v4-mapped. */
memcpy(tail, "::ffff:", 7);
for (p = tail + 7; *p; p++)
if (*p == '-')
*p = '.';
}
}
else
#endif
{
/* swap . or : for - */
/* NB, must not alter name if we return zero */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
{
char c = *p;
if ((c >='0' && c <= '9') || c == '-')
continue;
#ifdef HAVE_IPV6
else
*p = ':';
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
#endif
}
break;
}
if (*p != '.')
continue;
*p = 0;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
{
/* special hack for v4-mapped. */
memcpy(tail, "::ffff:", 7);
for (p = tail + 7; *p; p++)
if (*p == '-')
*p = '.';
}
else
#endif
{
/* swap . or : for - */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
#ifdef HAVE_IPV6
else
*p = ':';
#endif
}
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
found = 1;
}
#ifdef HAVE_IPV6
else
{
u64 addrpart = addr6part(&addr->addr.addr6);
if (c->is6 &&
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
found = 1;
}
#endif
}
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
found = 1;
}
#ifdef HAVE_IPV6
else
{
u64 addrpart = addr6part(&addr->addr.addr6);
if (c->is6 &&
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
found = 1;
}
#endif
}
/* restore name */
for (p = tail; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
if (found)
return 1;
}
@@ -149,14 +199,22 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
char *p;
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
if (c->indexed)
{
unsigned int index = ntohl(addr->addr.addr4.s_addr) - ntohl(c->start.s_addr);
snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
}
else
{
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
}
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
@@ -169,23 +227,32 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
char *p;
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (!c->prefix && *name == ':')
if (c->indexed)
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
u64 index = addr6part(&addr->addr.addr6) - addr6part(&c->start6);
snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
}
else
{
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
/* V4-mapped have periods.... */
for (p = name; *p; p++)
if (*p == ':' || *p == '.')
*p = '-';
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (!c->prefix && *name == ':')
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
}
/* V4-mapped have periods.... */
for (p = name; *p; p++)
if (*p == ':' || *p == '.')
*p = '-';
}
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -144,7 +144,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
GETSHORT(len, p);
/* malformed option, delete the whole OPT RR and start again. */
if (i + len > rdlen)
if (i + 4 + len > rdlen)
{
rdlen = 0;
is_last = 0;
@@ -159,7 +159,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
/* delete option if we're to replace it. */
p -= 4;
rdlen -= len + 4;
memcpy(p, p+len+4, rdlen - i);
memmove(p, p+len+4, rdlen - i);
PUTSHORT(rdlen, lenp);
lenp -= 2;
}
@@ -192,7 +192,15 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
{
free(buff);
return plen;
}
if (p + 11 > limit)
{
free(buff);
return plen; /* Too big */
}
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
@@ -204,11 +212,19 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
/* Copy back any options */
if (buff)
{
if (p + rdlen > limit)
{
free(buff);
return plen; /* Too big */
}
memcpy(p, buff, rdlen);
free(buff);
p += rdlen;
}
header->arcount = htons(ntohs(header->arcount) + 1);
/* Only bump arcount if RR is going to fit */
if (((ssize_t)optlen) <= (limit - (p + 4)))
header->arcount = htons(ntohs(header->arcount) + 1);
}
if (((ssize_t)optlen) > (limit - (p + 4)))
@@ -217,8 +233,12 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
/* Add new option */
if (optno != 0 && replace != 2)
{
if (p + 4 > limit)
return plen; /* Too big */
PUTSHORT(optno, p);
PUTSHORT(optlen, p);
if (p + optlen > limit)
return plen; /* Too big */
memcpy(p, opt, optlen);
p += optlen;
PUTSHORT(p - datap, lenp);
@@ -304,7 +324,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
void *addrp;
void *addrp = NULL;
int sa_family = source->sa.sa_family;
opt->source_netmask = 0;
@@ -344,7 +364,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
len = 0;
if (opt->source_netmask != 0)
if (addrp && opt->source_netmask != 0)
{
len = ((opt->source_netmask - 1) >> 3) + 1;
memcpy(opt->addr, addrp, len);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
unsigned int flags = 0;
for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
continue;
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
{
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
*type = SERV_FOR_NODOTS;
@@ -202,7 +204,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
}
}
if (flags == 0 && !(qtype & F_QUERY) &&
if (flags == 0 && !(qtype & (F_QUERY | F_DNSSECOK)) &&
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
/* don't forward A or AAAA queries for simple names, except the empty name */
flags = F_NOERR;
@@ -270,14 +272,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (forward->blocking_query)
forward = forward->blocking_query;
forward->flags |= FREC_TEST_PKTSZ;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
forward->flags |= FREC_TEST_PKTSZ;
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
PUTSHORT(SAFE_PKTSZ, pheader);
if (forward->sentto->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6
@@ -398,31 +399,22 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct server *firstsentto = start;
int subnet, forwarded = 0;
size_t edns0_len;
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
unsigned char *pheader;
/* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id;
edns0_len = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
if (edns0_len != plen)
{
plen = edns0_len;
forward->flags |= FREC_ADDED_PHEADER;
if (subnet)
forward->flags |= FREC_HAS_SUBNET;
}
if (subnet)
forward->flags |= FREC_HAS_SUBNET;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
{
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
if (new != plen)
forward->flags |= FREC_ADDED_PHEADER;
plen = new;
plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG))
@@ -431,9 +423,20 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#endif
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
forward->flags |= FREC_HAS_EXTRADATA;
if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
{
/* If there wasn't a PH before, and there is now, we added it. */
if (!oph)
forward->flags |= FREC_ADDED_PHEADER;
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
if (edns0_len > 11)
forward->flags |= FREC_HAS_EXTRADATA;
/* Reduce udp size on retransmits. */
if (forward->flags & FREC_TEST_PKTSZ)
PUTSHORT(SAFE_PKTSZ, pheader);
}
while (1)
{
@@ -561,7 +564,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
char **sets = 0;
int munged = 0, is_sign;
size_t plen;
(void)ad_reqd;
(void)do_bit;
(void)bogusanswer;
@@ -765,7 +768,11 @@ void reply_query(int fd, int family, time_t now)
if (!server)
return;
/* If sufficient time has elapsed, try and expand UDP buffer size again. */
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
server->edns_pktsz = daemon->edns_pktsz;
#ifdef HAVE_DNSSEC
hash = hash_questions(header, n, daemon->namebuff);
#else
@@ -788,7 +795,6 @@ void reply_query(int fd, int family, time_t now)
/* Note: if we send extra options in the EDNS0 header, we can't recreate
the query from the reply. */
if (RCODE(header) == REFUSED &&
!option_bool(OPT_ORDER) &&
forward->forwardall == 0 &&
!(forward->flags & FREC_HAS_EXTRADATA))
/* for broken servers, attempt to send to another one. */
@@ -796,10 +802,20 @@ void reply_query(int fd, int family, time_t now)
unsigned char *pheader;
size_t plen;
int is_sign;
/* In strict order mode, there must be a server later in the chain
left to send to, otherwise without the forwardall mechanism,
code further on will cycle around the list forwever if they
all return REFUSED. Note that server is always non-NULL before
this executes. */
if (option_bool(OPT_ORDER))
for (server = forward->sentto->next; server; server = server->next)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
break;
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
if (!is_sign)
if (!is_sign && server)
{
header->ancount = htons(0);
header->nscount = htons(0);
@@ -843,12 +859,18 @@ void reply_query(int fd, int family, time_t now)
}
/* We tried resending to this server with a smaller maximum size and got an answer.
Make that permanent. To avoid reduxing the packet size for an single dropped packet,
Make that permanent. To avoid reduxing the packet size for a single dropped packet,
only do this when we get a truncated answer, or one larger than the safe size. */
if (server && (forward->flags & FREC_TEST_PKTSZ) &&
if (server && server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
server->edns_pktsz = SAFE_PKTSZ;
{
server->edns_pktsz = SAFE_PKTSZ;
server->pktsz_reduced = now;
prettyprint_addr(&server->addr, daemon->addrbuff);
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
}
/* If the answer is an error, keep the forward record in place in case
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
@@ -857,7 +879,7 @@ void reply_query(int fd, int family, time_t now)
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
{
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
if (option_bool(OPT_NO_REBIND))
check_rebind = !(forward->flags & FREC_NOREBIND);
@@ -877,10 +899,10 @@ void reply_query(int fd, int family, time_t now)
return;
/* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
if (header->hb3 & HB3_TC)
status = STAT_TRUNCATED;
@@ -897,7 +919,8 @@ void reply_query(int fd, int family, time_t now)
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
else
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags && SERV_DO_DNSSEC), NULL, NULL);
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL);
}
/* Can't validate, as we're missing key data. Put this
@@ -933,37 +956,35 @@ void reply_query(int fd, int family, time_t now)
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
{
struct server *start = server, *new_server = NULL;
type &= ~SERV_DO_DNSSEC;
while (1)
{
if (type == (start->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
new_server = start;
if (server == start)
{
new_server = NULL;
break;
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == server)
break;
}
if (new_server)
server = new_server;
while (1)
{
if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
new_server = start;
if (server == start)
{
new_server = NULL;
break;
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == server)
break;
}
if (new_server)
server = new_server;
}
new->sentto = server;
new->rfd4 = NULL;
#ifdef HAVE_IPV6
new->rfd6 = NULL;
@@ -1096,7 +1117,7 @@ void reply_query(int fd, int family, time_t now)
header->hb4 |= HB4_RA; /* recursion if available */
#ifdef HAVE_DNSSEC
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
{
@@ -1189,6 +1210,10 @@ void receive_query(struct listener *listen, time_t now)
(msg.msg_flags & MSG_TRUNC) ||
(header->hb3 & HB3_QR))
return;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
source_addr.sa.sa_family = listen->family;
@@ -1409,6 +1434,8 @@ void receive_query(struct listener *listen, time_t now)
defaults to 512 */
if (udp_size > daemon->edns_pktsz)
udp_size = daemon->edns_pktsz;
else if (udp_size < PACKETSZ)
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
}
#ifdef HAVE_AUTH
@@ -1477,7 +1504,8 @@ 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);
else
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags && SERV_DO_DNSSEC), NULL, NULL);
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL);
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
break;
@@ -1506,14 +1534,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) != 0)
if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
{
new_status = STAT_ABANDONED;
break;
}
type &= ~SERV_DO_DNSSEC;
while (1)
{
if (!firstsendto)
@@ -1530,34 +1556,34 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
}
}
if (type != (server->flags & SERV_TYPE) ||
if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
continue;
retry:
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
retry:
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */
}
server->flags &= ~SERV_GOT_TCP;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
continue; /* No good, next server */
}
server->flags &= ~SERV_GOT_TCP;
}
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
!read_write(server->tcpfd, &c1, 1, 1) ||
@@ -1691,6 +1717,10 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header))
continue;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(payload + size, 0, 65536 - size);
query_count++;
@@ -1776,17 +1806,30 @@ unsigned char *tcp_request(int confd, time_t now,
struct all_addr *addrp = NULL;
int type = SERV_DO_DNSSEC;
char *domain = NULL;
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
if (size != new_size)
{
added_pheader = 1;
size = new_size;
}
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
{
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG))
header->hb4 |= HB4_CD;
}
#endif
/* Check if we added a pheader on forwarding - may need to
strip it from the reply. */
if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
added_pheader = 1;
type &= ~SERV_DO_DNSSEC;
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
@@ -1840,7 +1883,7 @@ unsigned char *tcp_request(int confd, time_t now,
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
close(last_server->tcpfd);
@@ -1851,24 +1894,6 @@ unsigned char *tcp_request(int confd, time_t now,
last_server->flags &= ~SERV_GOT_TCP;
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
{
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
if (size != new_size)
{
added_pheader = 1;
size = new_size;
}
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG))
header->hb4 |= HB4_CD;
}
#endif
*length = htons(size);
/* get query name again for logging - may have been overwritten */
@@ -2080,6 +2105,8 @@ static void free_frec(struct frec *f)
#endif
}
/* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. Impose an absolute
@@ -2126,7 +2153,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
/* can't find empty one, use oldest if there is one
and it's older than timeout */
if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
{
/* keep stuff for twice timeout if we can by allocating a new
record instead */
@@ -2166,7 +2193,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
return f; /* OK if malloc fails and this is NULL */
}
/* crc is all-ones if not known. */
static struct frec *lookup_frec(unsigned short id, void *hash)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,7 +14,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "dnsmasq.h"
#ifdef HAVE_SCRIPT
@@ -98,13 +97,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
return pipefd[1];
}
/* ignore SIGTERM, so that we can clean up when the main process gets hit
/* ignore SIGTERM and SIGINT, so that we can clean up when the main process gets hit
and SIGALRM so that we can use sleep() */
sigact.sa_handler = SIG_IGN;
sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
if (!option_bool(OPT_DEBUG) && uid != 0)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
#include <sys/inotify.h>
#include <sys/param.h> /* For MAXSYMLINKS */
/* the strategy is to set a inotify on the directories containing
/* the strategy is to set an inotify on the directories containing
resolv files, for any files in the directory which are close-write
or moved into the directory.
@@ -227,19 +227,21 @@ int inotify_check(time_t now)
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
{
size_t namelen;
in = (struct inotify_event*)p;
for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
hit = 1;
/* ignore emacs backups and dotfiles */
if (in->len == 0 ||
in->name[in->len - 1] == '~' ||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
if (in->len == 0 || (namelen = strlen(in->name)) == 0 ||
in->name[namelen - 1] == '~' ||
(in->name[0] == '#' && in->name[namelen - 1] == '#') ||
in->name[0] == '.')
continue;
for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && strcmp(res->file, in->name) == 0)
hit = 1;
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
if (ah->wd == in->wd)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -133,7 +133,6 @@ static int read_leases(time_t now, FILE *leasestream)
void lease_init(time_t now)
{
FILE *leasestream;
int readok = 0;
leases_left = daemon->dhcp_max;
@@ -172,7 +171,7 @@ void lease_init(time_t now)
if (leasestream)
{
if (!(readok = read_leases(now, leasestream)))
if (!read_leases(now, leasestream))
my_syslog(MS_DHCP | LOG_ERR, _("failed to parse lease database, invalid line: %s %s %s %s ..."),
daemon->dhcp_buff3, daemon->dhcp_buff2,
daemon->namebuff, daemon->dhcp_buff);
@@ -202,12 +201,6 @@ void lease_init(time_t now)
sprintf(daemon->dhcp_buff, "%d", WEXITSTATUS(rc));
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
}
/* Only die if we stopped reading due to a non-parsed line when running script,
this is expected behaviour when reading from a file, if the file was written with IPv6 data
and we are not compiled to understand that. */
if (!readok)
die(_("failed to read lease-init script output"), NULL, EC_FILE);
}
#endif
@@ -236,7 +229,7 @@ void lease_update_from_configs(void)
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
}
static void ourprintf(int *errp, char *format, ...)
{
va_list ap;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1149,10 +1149,7 @@ int random_sock(int family)
if (fix_fd(fd))
while(tries--)
{
unsigned short port = rand16();
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
if (family == AF_INET)
{
@@ -1187,7 +1184,7 @@ int random_sock(int family)
}
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
{
union mysockaddr addr_copy = *addr;
@@ -1204,7 +1201,25 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
return 0;
if (!is_tcp && ifindex > 0)
{
#if defined(IP_UNICAST_IF)
if (addr_copy.sa.sa_family == AF_INET)
{
uint32_t ifindex_opt = htonl(ifindex);
return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
}
#endif
#if defined(HAVE_IPV6) && defined (IPV6_UNICAST_IF)
if (addr_copy.sa.sa_family == AF_INET6)
{
uint32_t ifindex_opt = htonl(ifindex);
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
}
#endif
}
#if defined(SO_BINDTODEVICE)
if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
@@ -1260,7 +1275,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
return NULL;
}
if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
if (!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
{
errsave = errno; /* save error from bind. */
close(sfd->fd);
@@ -1460,13 +1475,6 @@ void check_servers(void)
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
sfd->used = 0;
#ifdef HAVE_DNSSEC
/* Disable DNSSEC validation when using server=/domain/.... servers
unless there's a configured trust anchor. */
for (serv = daemon->servers; serv; serv = serv->next)
serv->flags |= SERV_DO_DNSSEC;
#endif
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
@@ -1478,6 +1486,11 @@ void check_servers(void)
#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 (serv->flags & SERV_HAS_DOMAIN)
{
struct ds_config *ds;
@@ -1494,8 +1507,6 @@ void check_servers(void)
if (!ds)
serv->flags &= ~SERV_DO_DNSSEC;
}
else if (serv->flags & SERV_FOR_NODOTS)
serv->flags &= ~SERV_DO_DNSSEC;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -882,7 +882,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
switch (msize)
{
case 32:
p += sprintf(p, "%d.", a & 0xff);
p += sprintf(p, "%u.", a & 0xff);
/* fall through */
case 24:
p += sprintf(p, "%d.", (a >> 8) & 0xff);
@@ -1163,7 +1163,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
case 'd':
case 'D':
fac *= 24;
/* fall though */
/* fall through */
case 'h':
case 'H':
fac *= 60;
@@ -1415,7 +1415,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
}
p = newp;
end = do_rfc1035_name(p + len, dom);
end = do_rfc1035_name(p + len, dom, NULL);
*end++ = 0;
len = end - p;
free(dom);
@@ -2071,7 +2071,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char *netpart;
new->prefix = NULL;
new->indexed = 0;
unhide_metas(comma);
if ((netpart = split_chr(comma, '/')))
{
@@ -2208,8 +2209,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
else
{
char *star;
new->next = daemon->synth_domains;
daemon->synth_domains = new;
if ((star = strrchr(new->prefix, '*')) && *(star+1) == 0)
{
*star = 0;
new->indexed = 1;
}
}
}
else if (option == 's')
@@ -2733,15 +2740,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_BRIDGE: /* --bridge-interface */
{
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
struct dhcp_bridge *new;
if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
ret_err(_("bad bridge-interface"));
strcpy(new->iface, arg);
new->alias = NULL;
new->next = daemon->bridges;
daemon->bridges = new;
for (new = daemon->bridges; new; new = new->next)
if (strcmp(new->iface, arg) == 0)
break;
if (!new)
{
new = opt_malloc(sizeof(struct dhcp_bridge));
strcpy(new->iface, arg);
new->alias = NULL;
new->next = daemon->bridges;
daemon->bridges = new;
}
do {
arg = comma;
comma = split(arg);
@@ -2961,7 +2977,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'd':
case 'D':
fac *= 24;
/* fall though */
/* fall through */
case 'h':
case 'H':
fac *= 60;
@@ -3847,10 +3863,14 @@ err:
while (arg != last)
{
int arglen = strlen(arg);
alias = canonicalise_opt(arg);
if (!alias || !target)
ret_err(_("bad CNAME"));
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
if (hostname_isequal(new->alias, alias))
ret_err(_("duplicate CNAME"));
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
@@ -3859,7 +3879,7 @@ err:
new->target = target;
new->ttl = ttl;
arg += strlen(arg)+1;
for (arg += arglen+1; *arg && isspace(*arg); arg++);
}
break;
@@ -4315,7 +4335,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
fclose(f);
}
#ifdef HAVE_DHCP
#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
int option_read_dynfile(char *file, int flags)
{
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
@@ -4516,86 +4536,99 @@ void read_servers_file(void)
#ifdef HAVE_DHCP
static void clear_dynamic_conf(void)
{
struct dhcp_config *configs, *cp, **up;
/* remove existing... */
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
{
cp = configs->next;
if (configs->flags & CONFIG_BANK)
{
struct hwaddr_config *mac, *tmp;
struct dhcp_netid_list *list, *tmplist;
for (mac = configs->hwaddr; mac; mac = tmp)
{
tmp = mac->next;
free(mac);
}
if (configs->flags & CONFIG_CLID)
free(configs->clid);
for (list = configs->netid; list; list = tmplist)
{
free(list->list);
tmplist = list->next;
free(list);
}
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
*up = configs->next;
free(configs);
}
else
up = &configs->next;
}
}
static void clear_dynamic_opt(void)
{
struct dhcp_opt *opts, *cp, **up;
struct dhcp_netid *id, *next;
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
{
cp = opts->next;
if (opts->flags & DHOPT_BANK)
{
if ((opts->flags & DHOPT_VENDOR))
free(opts->u.vendor_class);
free(opts->val);
for (id = opts->netid; id; id = next)
{
next = id->next;
free(id->net);
free(id);
}
*up = opts->next;
free(opts);
}
else
up = &opts->next;
}
}
void reread_dhcp(void)
{
struct hostsfile *hf;
struct hostsfile *hf;
if (daemon->dhcp_hosts_file)
/* Do these even if there is no daemon->dhcp_hosts_file or
daemon->dhcp_opts_file since entries may have been created by the
inotify dynamic file reading system. */
clear_dynamic_conf();
clear_dynamic_opt();
if (daemon->dhcp_hosts_file)
{
struct dhcp_config *configs, *cp, **up;
/* remove existing... */
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
{
cp = configs->next;
if (configs->flags & CONFIG_BANK)
{
struct hwaddr_config *mac, *tmp;
struct dhcp_netid_list *list, *tmplist;
for (mac = configs->hwaddr; mac; mac = tmp)
{
tmp = mac->next;
free(mac);
}
if (configs->flags & CONFIG_CLID)
free(configs->clid);
for (list = configs->netid; list; list = tmplist)
{
free(list->list);
tmplist = list->next;
free(list);
}
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
*up = configs->next;
free(configs);
}
else
up = &configs->next;
}
daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
if (!(hf->flags & AH_INACTIVE))
{
if (one_file(hf->fname, LOPT_BANK))
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
}
if (!(hf->flags & AH_INACTIVE))
{
if (one_file(hf->fname, LOPT_BANK))
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
}
}
if (daemon->dhcp_opts_file)
{
struct dhcp_opt *opts, *cp, **up;
struct dhcp_netid *id, *next;
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
{
cp = opts->next;
if (opts->flags & DHOPT_BANK)
{
if ((opts->flags & DHOPT_VENDOR))
free(opts->u.vendor_class);
free(opts->val);
for (id = opts->netid; id; id = next)
{
next = id->next;
free(id->net);
free(id);
}
*up = opts->next;
free(opts);
}
else
up = &opts->next;
}
daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
if (!(hf->flags & AH_INACTIVE))
@@ -4604,11 +4637,18 @@ void reread_dhcp(void)
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
}
}
# ifdef HAVE_INOTIFY
/* Setup notify and read pre-existing files. */
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
# endif
}
#endif
void read_opts(int argc, char **argv, char *compile_opts)
{
size_t argbuf_size = MAXDNAME;
char *argbuf = opt_malloc(argbuf_size);
char *buff = opt_malloc(MAXDNAME);
int option, conffile_opt = '7', testmode = 0;
char *arg, *conffile = CONFFILE;
@@ -4639,6 +4679,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT;
daemon->min_port = MIN_PORT;
#ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
@@ -4678,9 +4719,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
/* Copy optarg so that argv doesn't get changed */
if (optarg)
{
strncpy(buff, optarg, MAXDNAME);
buff[MAXDNAME-1] = 0;
arg = buff;
if (strlen(optarg) >= argbuf_size)
{
free(argbuf);
argbuf_size = strlen(optarg) + 1;
argbuf = opt_malloc(argbuf_size);
}
strncpy(argbuf, optarg, argbuf_size);
argbuf[argbuf_size-1] = 0;
arg = argbuf;
}
else
arg = NULL;
@@ -4728,6 +4775,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
}
free(argbuf);
if (conffile)
{
one_file(conffile, conffile_opt);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -198,6 +198,9 @@ void icmp6_packet(time_t now)
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
{
if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) {
return;
}
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
mac = daemon->namebuff;
}
@@ -404,7 +407,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
if (ra_param)
mtu = ra_param->mtu;
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
/* Note that IPv6 MTU is not necessarily the same as the IPv4 MTU
available from SIOCGIFMTU */
if (mtu == 0)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,8 +36,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
if ((l = *p++) == 0)
/* end marker */
{
/* check that there are the correct no of bytes after the name */
if (!CHECK_LEN(header, p, plen, extrabytes))
/* check that there are the correct no. of bytes after the name */
if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
return 0;
if (isExtract)
@@ -156,7 +156,7 @@ int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
memset(addrp, 0, sizeof(struct all_addr));
/* turn name into a series of asciiz strings */
/* j counts no of labels */
/* j counts no. of labels */
for(j = 1,cp1 = name; *namein; cp1++, namein++)
if (*namein == '.')
{
@@ -498,6 +498,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
{
unsigned int i, len = *p1;
unsigned char *p2 = p1;
if ((p1 + len - p) >= rdlen)
return 0; /* bad packet */
/* make counted string zero-term and sanitise */
for (i = 0; i < len; i++)
{
@@ -582,7 +584,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
expired and cleaned out that way.
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
int secure, int *doctored)
{
unsigned char *p, *p1, *endrr, *namep;
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
@@ -593,6 +596,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
#else
(void)ipsets; /* unused */
#endif
cache_start_insert();
@@ -601,10 +605,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{
searched_soa = 1;
ttl = find_soa(header, qlen, name, doctored);
if (*doctored)
{
if (secure)
return 0;
#ifdef HAVE_DNSSEC
if (*doctored && secure)
return 0;
if (option_bool(OPT_DNSSEC_VALID))
for (i = 0; i < ntohs(header->ancount); i++)
if (daemon->rr_status[i])
return 0;
#endif
}
}
/* go through the questions. */
@@ -615,7 +627,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
int found = 0, cname_count = CNAME_CHAIN;
struct crec *cpp = NULL;
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
int secflag = secure ? F_DNSSECOK : 0;
#ifdef HAVE_DNSSEC
int cname_short = 0;
#endif
unsigned long cttl = ULONG_MAX, attl;
namep = p;
@@ -643,8 +657,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = ntohs(header->ancount); j != 0; j--)
for (j = 0; j < ntohs(header->ancount); j++)
{
int secflag = 0;
unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
@@ -670,11 +685,24 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{
if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
{
/* validated RR anywhere in CNAME chain, don't cache. */
if (cname_short || aqtype == T_CNAME)
return 0;
secflag = F_DNSSECOK;
}
#endif
if (aqtype == T_CNAME)
{
if (!cname_count-- || secure)
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
if (!cname_count--)
return 0; /* looped CNAMES, we can't cache. */
#ifdef HAVE_DNSSEC
cname_short = 1;
#endif
goto cname_loop;
}
@@ -696,7 +724,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
ttl = find_soa(header, qlen, NULL, doctored);
}
if (ttl)
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
}
}
else
@@ -724,8 +752,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
if (!(p1 = skip_questions(header, qlen)))
return 0;
for (j = ntohs(header->ancount); j != 0; j--)
for (j = 0; j < ntohs(header->ancount); j++)
{
int secflag = 0;
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */
@@ -742,6 +772,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
{
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
secflag = F_DNSSECOK;
#endif
if (aqtype == T_CNAME)
{
if (!cname_count--)
@@ -833,7 +867,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
pointing at this, inherit its TTL */
if (ttl || cpp)
{
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
if (newc && cpp)
{
cpp->addr.cname.target.cache = newc;
@@ -913,6 +947,8 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN)
SET_RCODE(header, NXDOMAIN);
else if (flags == F_SERVFAIL)
SET_RCODE(header, SERVFAIL);
else if (flags == F_IPV4)
{ /* we know the address */
SET_RCODE(header, NOERROR);
@@ -948,7 +984,7 @@ int check_for_local_domain(char *name, time_t now)
/* Note: the call to cache_find_by_name is intended to find any record which matches
ie A, AAAA, CNAME. */
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
@@ -1062,6 +1098,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
return 0;
}
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
{
@@ -1071,29 +1108,41 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
unsigned short usval;
long lval;
char *sval;
#define CHECK_LIMIT(size) \
if (limit && p + (size) > (unsigned char*)limit) goto truncated;
if (truncp && *truncp)
return 0;
va_start(ap, format); /* make ap point to 1st unamed argument */
if (truncp && *truncp)
goto truncated;
if (nameoffset > 0)
{
CHECK_LIMIT(2);
PUTSHORT(nameoffset | 0xc000, p);
}
else
{
char *name = va_arg(ap, char *);
if (name)
p = do_rfc1035_name(p, name);
if (name && !(p = do_rfc1035_name(p, name, limit)))
goto truncated;
if (nameoffset < 0)
{
CHECK_LIMIT(2);
PUTSHORT(-nameoffset | 0xc000, p);
}
else
*p++ = 0;
{
CHECK_LIMIT(1);
*p++ = 0;
}
}
/* type (2) + class (2) + ttl (4) + rdlen (2) */
CHECK_LIMIT(10);
PUTSHORT(type, p);
PUTSHORT(class, p);
PUTLONG(ttl, p); /* TTL */
@@ -1106,6 +1155,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
{
#ifdef HAVE_IPV6
case '6':
CHECK_LIMIT(IN6ADDRSZ);
sval = va_arg(ap, char *);
memcpy(p, sval, IN6ADDRSZ);
p += IN6ADDRSZ;
@@ -1113,36 +1163,43 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
#endif
case '4':
CHECK_LIMIT(INADDRSZ);
sval = va_arg(ap, char *);
memcpy(p, sval, INADDRSZ);
p += INADDRSZ;
break;
case 'b':
CHECK_LIMIT(1);
usval = va_arg(ap, int);
*p++ = usval;
break;
case 's':
CHECK_LIMIT(2);
usval = va_arg(ap, int);
PUTSHORT(usval, p);
break;
case 'l':
CHECK_LIMIT(4);
lval = va_arg(ap, long);
PUTLONG(lval, p);
break;
case 'd':
/* get domain-name answer arg and store it in RDATA field */
if (offset)
*offset = p - (unsigned char *)header;
p = do_rfc1035_name(p, va_arg(ap, char *));
*p++ = 0;
/* get domain-name answer arg and store it in RDATA field */
if (offset)
*offset = p - (unsigned char *)header;
if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
goto truncated;
CHECK_LIMIT(1);
*p++ = 0;
break;
case 't':
usval = va_arg(ap, int);
CHECK_LIMIT(usval);
sval = va_arg(ap, char *);
if (usval != 0)
memcpy(p, sval, usval);
@@ -1154,6 +1211,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
usval = sval ? strlen(sval) : 0;
if (usval > 255)
usval = 255;
CHECK_LIMIT(usval + 1);
*p++ = (unsigned char)usval;
memcpy(p, sval, usval);
p += usval;
@@ -1162,19 +1220,20 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
va_end(ap); /* clean up variable argument pointer */
/* Now, store real RDLength. sav already checked against limit. */
j = p - sav - 2;
PUTSHORT(j, sav); /* Now, store real RDLength */
/* check for overflow of buffer */
if (limit && ((unsigned char *)limit - p) < 0)
{
if (truncp)
*truncp = 1;
return 0;
}
PUTSHORT(j, sav);
*pp = p;
return 1;
truncated:
va_end(ap);
if (truncp)
*truncp = 1;
return 0;
#undef CHECK_LIMIT
}
static unsigned long crec_ttl(struct crec *crecp, time_t now)
@@ -1223,16 +1282,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct mx_srv_record *rec;
size_t len;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(((char *)header) + qlen, 0,
(limit - ((char *)header)) - qlen);
if (ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 ||
ntohs(header->qdcount) == 0 ||
OPCODE(header) != QUERY )
return 0;
/* always servfail queries with RD unset, to avoid cache snooping. */
if (!(header->hb3 & HB3_RD))
return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
/* Don't return AD set if checking disabled. */
if (header->hb4 & HB4_CD)
@@ -1510,44 +1568,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype != type && qtype != T_ANY)
continue;
/* Check for "A for A" queries; be rather conservative
about what looks like dotted-quad. */
if (qtype == T_A)
{
char *cp;
unsigned int i, a;
int x;
for (cp = name, i = 0, a = 0; *cp; i++)
{
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
{
i = 5;
break;
}
a = (a << 8) + x;
if (*cp == '.')
cp++;
}
if (i == 4)
{
ans = 1;
sec_data = 0;
if (!dryrun)
{
addr.addr.addr4.s_addr = htonl(a);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
}
continue;
}
}
/* interface name stuff */
intname_restart:
for (intr = daemon->int_names; intr; intr = intr->next)
@@ -1716,8 +1736,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype == T_CNAME || qtype == T_ANY)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
(qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
((crecp->flags & F_CONFIG) || !do_bit || !(crecp->flags & F_DNSSECOK)))
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int i, int size);
static unsigned int option_uint(unsigned char *opt, int offset, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, char *err, u32 xid);
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
@@ -42,14 +42,14 @@ static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static int in_list(unsigned char *list, int opt);
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
unsigned char *end,
unsigned char *req_options,
char *hostname,
char *config_domain,
char *domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
int null_term, int pxearch,
int null_term, int pxe_arch,
unsigned char *uuid,
int vendor_class_len,
time_t now,
@@ -58,7 +58,7 @@ static void do_options(struct dhcp_context *context,
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
@@ -67,7 +67,8 @@ static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dh
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
size_t sz, time_t now, int unicast_dest, int loopback,
int *is_inform, int pxe, struct in_addr fallback, time_t recvtime)
{
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
@@ -156,7 +157,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
for (offset = 0; offset < (len - 5); offset += elen + 5)
{
elen = option_uint(opt, offset + 4 , 1);
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
{
unsigned char *x = option_ptr(opt, offset + 5);
unsigned char *y = option_ptr(opt, offset + elen + 5);
@@ -382,7 +383,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
len = option_uint(opt, offset + 4 , 1);
/* Need to take care that bad data can't run us off the end of the packet */
if ((offset + len + 5 <= (option_len(opt))) &&
if ((offset + len + 5 <= (unsigned)(option_len(opt))) &&
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
{
@@ -487,6 +488,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
known_id.next = netid;
netid = &known_id;
}
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len,
mess->chaddr, mess->hlen, mess->htype, NULL))
{
known_id.net = "known-othernet";
known_id.next = netid;
netid = &known_id;
}
if (mess_type == 0 && !pxe)
{
@@ -568,7 +576,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_prune(lease, now);
lease = NULL;
}
if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now))
if (!address_allocate(context, &mess->yiaddr, mess->chaddr, mess->hlen, tagif_netid, now, loopback))
message = _("no address available");
}
else
@@ -826,9 +834,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
mess->siaddr = context->local;
snprintf((char *)mess->file, sizeof(mess->file),
strchr(service->basename, '.') ? "%s" :"%s.%d",
service->basename, layer);
if (strchr(service->basename, '.'))
snprintf((char *)mess->file, sizeof(mess->file),
"%s", service->basename);
else
snprintf((char *)mess->file, sizeof(mess->file),
"%s.%d", service->basename, layer);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
@@ -898,7 +909,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!workaround && boot)
{
/* Provide the bootfile here, for gPXE, and in case we have no menu items
/* Provide the bootfile here, for iPXE, and in case we have no menu items
and set discovery_control = 8 */
if (boot->next_server.s_addr)
mess->siaddr = boot->next_server;
@@ -1029,8 +1040,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (have_config(config, CONFIG_DECLINED) &&
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
else if (!do_icmp_ping(now, config->addr, 0))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
else
conf = config->addr;
}
@@ -1043,11 +1052,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
!config_find_by_address(daemon->dhcp_conf, lease->addr))
mess->yiaddr = lease->addr;
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0))
!config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0, loopback))
mess->yiaddr = addr;
else if (emac_len == 0)
message = _("no unique-id");
else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now))
else if (!address_allocate(context, &mess->yiaddr, emac, emac_len, tagif_netid, now, loopback))
message = _("no address available");
}
@@ -2275,7 +2284,7 @@ static void do_options(struct dhcp_context *context,
/* See if we can send the boot stuff as options.
To do this we need a requested option list, BOOTP
and very old DHCP clients won't have this, we also
provide an manual option to disable it.
provide a manual option to disable it.
Some PXE ROMs have bugs (surprise!) and need zero-terminated
names, so we always send those. */
if ((boot = find_boot(tagif)))
@@ -2443,10 +2452,10 @@ static void do_options(struct dhcp_context *context,
if (fqdn_flags & 0x04)
{
p = do_rfc1035_name(p, hostname);
p = do_rfc1035_name(p, hostname, NULL);
if (domain)
{
p = do_rfc1035_name(p, domain);
p = do_rfc1035_name(p, domain, NULL);
*p++ = 0;
}
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -206,6 +206,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
/* RFC-6939 */
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
{
if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
return 0;
}
state->mac_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
@@ -213,6 +216,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
for (opt = opts; opt; opt = opt6_next(opt, end))
{
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
return 0;
int o = new_opt6(opt6_type(opt));
if (opt6_type(opt) == OPTION6_RELAY_MSG)
{
@@ -526,7 +532,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (have_config(config, CONFIG_DISABLE))
ignore = 1;
}
else if (state->clid &&
find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
{
known_id.net = "known-othernet";
known_id.next = state->tags;
state->tags = &known_id;
}
#ifdef OPTION6_PREFIX_CLASS
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
@@ -869,7 +882,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (!ia_option)
{
/* If we get a request with a IA_*A without addresses, treat it exactly like
/* If we get a request with an IA_*A without addresses, treat it exactly like
a SOLICT with rapid commit set. */
save_counter(start);
goto request_no_address;
@@ -1472,10 +1485,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
if ((p = expand(len + 2)))
{
*(p++) = state->fqdn_flags;
p = do_rfc1035_name(p, state->hostname);
p = do_rfc1035_name(p, state->hostname, NULL);
if (state->send_domain)
{
p = do_rfc1035_name(p, state->send_domain);
p = do_rfc1035_name(p, state->send_domain, NULL);
*p = 0;
}
}
@@ -1612,7 +1625,7 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
{
if (t1cntr != 0)
{
/* go back an fill in fields in IA_NA option */
/* go back and fill in fields in IA_NA option */
int sav = save_counter(t1cntr);
unsigned int t1, t2, fuzz = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Code to safely remove RRs from an DNS answer */
/* Code to safely remove RRs from a DNS answer */
#include "dnsmasq.h"
@@ -247,7 +247,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
check_rrs(p, header, plen, 1, rrs, rr_found);
/* Fouth pass, elide records */
/* Fourth pass, elide records */
for (p = rrs[0], i = 1; i < rr_found; i += 2)
{
unsigned char *start = rrs[i];
@@ -270,7 +270,7 @@ u16 *rrfilter_desc(int type)
{
/* List of RRtypes which include domains in the data.
0 -> domain
integer -> no of plain bytes
integer -> no. of plain bytes
-1 -> end
zero is not a valid RRtype, so the final entry is returned for

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
static ssize_t tftp_err_oops(char *packet, char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end);
@@ -734,7 +734,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
if (transfer->opt_blocksize)
{
p += (sprintf(p, "blksize") + 1);
p += (sprintf(p, "%d", transfer->blocksize) + 1);
p += (sprintf(p, "%u", transfer->blocksize) + 1);
}
if (transfer->opt_transize)
{

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2016 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,9 @@
#include <sys/times.h>
#endif
#if defined(LOCALEDIR) || defined(HAVE_IDN)
#if defined(HAVE_LIBIDN2)
#include <idn2.h>
#elif defined(HAVE_IDN)
#include <idna.h>
#endif
@@ -109,6 +111,7 @@ u64 rand64(void)
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
}
/* returns 2 if names is OK but contains one or more underscores */
static int check_name(char *in)
{
/* remove trailing .
@@ -116,6 +119,7 @@ static int check_name(char *in)
size_t dotgap = 0, l = strlen(in);
char c;
int nowhite = 0;
int hasuscore = 0;
if (l == 0 || l > MAXDNAME) return 0;
@@ -134,18 +138,22 @@ static int check_name(char *in)
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
/* iscntrl only gives expected results for ascii */
return 0;
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
else if (!isascii((unsigned char)c))
return 0;
#endif
else if (c != ' ')
nowhite = 1;
{
nowhite = 1;
if (c == '_')
hasuscore = 1;
}
}
if (!nowhite)
return 0;
return 1;
return hasuscore ? 2 : 1;
}
/* Hostnames have a more limited valid charset than domain names
@@ -184,49 +192,70 @@ int legal_hostname(char *name)
char *canonicalise(char *in, int *nomem)
{
char *ret = NULL;
#if defined(LOCALEDIR) || defined(HAVE_IDN)
int rc;
#endif
if (nomem)
*nomem = 0;
if (!check_name(in))
if (!(rc = check_name(in)))
return NULL;
#if defined(LOCALEDIR) || defined(HAVE_IDN)
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
/* older libidn2 strips underscores, so don't do IDN processing
if the name has an underscore (check_name() returned 2) */
if (rc != 2)
#endif
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
{
if (ret)
free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
# ifdef HAVE_LIBIDN2
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
if (rc == IDN2_DISALLOWED)
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
# else
rc = idna_to_ascii_lz(in, &ret, 0);
# endif
if (rc != IDNA_SUCCESS)
{
my_syslog(LOG_ERR, _("failed to allocate memory"));
*nomem = 1;
if (ret)
free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
{
my_syslog(LOG_ERR, _("failed to allocate memory"));
*nomem = 1;
}
return NULL;
}
return NULL;
return ret;
}
#else
#endif
if ((ret = whine_malloc(strlen(in)+1)))
strcpy(ret, in);
else if (nomem)
*nomem = 1;
#endif
return ret;
}
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
{
int j;
while (sval && *sval)
{
unsigned char *cp = p++;
if (limit && p > (unsigned char*)limit)
return NULL;
for (j = 0; *sval && (*sval != '.'); sval++, j++)
{
if (limit && p + 1 > (unsigned char*)limit)
return NULL;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
*p++ = (*(++sval))-1;
@@ -234,10 +263,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
#endif
*p++ = *sval;
}
*cp = j;
if (*sval)
sval++;
}
return p;
}
@@ -439,13 +470,13 @@ void prettyprint_time(char *buf, unsigned int t)
{
unsigned int x, p = 0;
if ((x = t/86400))
p += sprintf(&buf[p], "%dd", x);
p += sprintf(&buf[p], "%ud", x);
if ((x = (t/3600)%24))
p += sprintf(&buf[p], "%dh", x);
p += sprintf(&buf[p], "%uh", x);
if ((x = (t/60)%60))
p += sprintf(&buf[p], "%dm", x);
p += sprintf(&buf[p], "%um", x);
if ((x = t%60))
p += sprintf(&buf[p], "%ds", x);
p += sprintf(&buf[p], "%us", x);
}
}
@@ -503,7 +534,8 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
return -1;
out[i] = strtol(&in[j*2], NULL, 16);
mask = mask << 1;
i++;
if (++i == maxlen)
break;
if (j < bytes - 1)
in[(j+1)*2] = sav;
}