Compare commits

...
173 Commits
Author SHA1 Message Date
Simon Kelley 3a610a007f Finesse allocation of memory for "struct crec" cache entries.
These normally have enough space for a name of up to SMALLDNAME characters.
When used to hold /etc/hosts entries, they are allocated with just enough
bytes for the name held. When used to hold other configured stuff, (CNAMES
DS records. DHCP names etc), the name is replaced by a pointer to a string
held elsewhere, and F_NAMEP set. Hence only enough space to hold a char *
is needed, rather than SMALLDNAME bytes.
2018-09-26 16:50:35 +01:00
Simon Kelley 48b090cb5c Fix b6f926fbef to not SEGV on startup (rarely).
Many thanks to Kristian Evensen  for finding and diagnosing this.

We can't copy the whole of a crec structure in make_non_terminals, since
crec structures allocated to represent /etc/hosts entries are allocated with
just enough space for the actual name they contain, not the full
SMALLDNAME bytes declared in struct crec. Using structure copy therefore
copies beyond the end of the allocated source and, just occaisionally,
into unmapped memory, resulting in a SEGV.

Since the crecs we're making here always have F_NAMEP set, we're not
interested in copying the name field from the source anyway, we use the
namep part of the union and set it to point some way into the name
of the source crec to get the super-domain that we're representing.

The fix is therefore to copy the relevant fields of the crec, rather
than copying the whole and overwriting.
2018-09-26 12:53:59 +01:00
Simon Kelley 4139298d28 Change behavior when RD bit unset in queries.
Change anti cache-snooping behaviour with queries with the
recursion-desired bit unset. Instead to returning SERVFAIL, we
now always forward, and never answer from the cache. This
allows "dig +trace" command to work.
2018-09-19 22:27:11 +01:00
Simon Kelley 51cc10fa54 Add warning about 0.0.0.0 and :: addresses to man page. 2018-09-19 12:49:43 +01:00
Simon Kelley ea6cc33804 Handle memory allocation failure in make_non_terminals()
Thanks to Kristian Evensen for spotting the problem.
2018-09-18 23:21:17 +01:00
Simon Kelley ad03967ee4 Add debian/tmpfiles.conf 2018-09-17 23:54:13 +01:00
Simon Kelley f4fd07d303 Debian bugfix. 2018-09-17 23:45:32 +01:00
Simon Kelley e3c08a34a7 Debian packaging fix. (restorecon) 2018-09-17 23:20:00 +01:00
Simon Kelley 118011fe2b Debian packaging fix. (tmpfiles.d) 2018-09-17 23:15:37 +01:00
Simon Kelley af3bd07355 Man page typo. 2018-09-08 15:08:22 +01:00
Simon Kelley d68209978a Picky changes to 47b45b2967 2018-09-04 23:00:11 +01:00
Petr Menšík 47b45b2967 Fix lengths of interface names
Use helper function similar to copy correctly limited names into
buffers.
2018-09-04 22:47:58 +01:00
Petr Menšík 2b38e3823b Minor improvements in lease-tools
Limit max interface name to fit into buffer.
Make sure pointer have to be always positive.
Close socket after received reply.
2018-09-04 22:36:23 +01:00
Petr Menšík 282eab7952 Mark die function as never returning
Improves static analysis output and reduces false positives.
2018-09-04 22:32:51 +01:00
Simon Kelley c346f61535 Handle ANY queries in context of da8b6517de 2018-09-04 21:14:18 +01:00
Simon Kelley 03212e533b Manpage typo. 2018-09-04 17:52:28 +01:00
Simon Kelley da8b6517de Implement --address=/example.com/#
as (more efficient) syntactic sugar for --address=/example.com/0.0.0.0 and --address=/example.com/::
2018-09-03 23:18:36 +01:00
Simon Kelley c5db8f93ec Tidy 7f876b64c22b2b18412e2e3d8506ee33e42db7c 2018-08-23 23:06:00 +01:00
Simon Kelley 974a6d087a Add --caa-record 2018-08-23 23:01:16 +01:00
Simon Kelley b758b67c37 Improve logging of RRs from --dns-rr. 2018-08-23 21:41:23 +01:00
Simon Kelley 9bafdc62b7 Tidy up file parsing code. 2018-08-21 22:53:38 +01:00
Simon Kelley 97f876b64c Properly deal with unaligned addresses in DHCPv6 packets.
Thanks to Vladislav Grishenko for spotting this.
2018-08-21 22:06:36 +01:00
Simon Kelley cbfbd173c4 Fix broken DNSSEC records in previous. 2018-08-21 18:25:18 +01:00
Simon Kelley b6f926fbef Don't return NXDOMAIN to empty non-terminals.
When a record is defined locally, eg an A record for one.two.example then
we already know that if we forward, eg an AAAA query for one.two.example,
and get back NXDOMAIN, then we need to alter that to NODATA. This is handled
by  check_for_local_domain(). But, if we forward two.example, because
one.two.example exists, then the answer to two.example should also be
a NODATA.

For most local records this is easy, just to substring matching.
for A, AAAA and CNAME records that are in the cache, it's more difficult.
The cache has no efficient way to find such records. The fix is to
insert empty (none of F_IPV4, F_IPV6 F_CNAME set) records for each
non-terminal.

The same considerations apply in auth mode, and the same basic mechanism
is used there too.
2018-08-21 17:46:52 +01:00
Simon Kelley c822620967 Add --dhcp-name-match 2018-08-08 23:46:03 +01:00
Simon Kelley 397c0502e2 Handle case of --auth-zone but no --auth-server. 2018-08-04 21:04:59 +01:00
Simon Kelley 1682d15a74 Add missing EDNS0 section.
EDNS0 section missing in replies to EDNS0-containing queries where
answer generated from --local=/<domain>/
2018-08-03 20:38:18 +01:00
Simon Kelley dd33e98da0 Fix crash parsing a --synth-domain with no prefix.
Problem introduced in 2.79/6b2b564ac34cb3c862f168e6b1457f9f0b9ca69c
2018-07-30 14:55:39 +01:00
Simon Kelley c16d966ad3 Add copyright to src/metrics.h 2018-07-29 22:31:02 +01:00
Simon Kelley 1dfed16071 Remove C99 only code. 2018-07-29 22:16:41 +01:00
Simon Kelley 6f835ed6c8 Format fixes - ubus.c 2018-07-29 22:15:36 +01:00
Kevin Darbyshire-Bryant 9d6fd1727e dnsmasq.c fix OPT_UBUS option usage
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2018-07-29 22:11:12 +01:00
Simon Kelley 8c1b6a5fd7 New metrics and ubus files. 2018-07-21 22:12:32 +01:00
Julian Kornberger 8dcdb33be9 Add --enable-ubus option. 2018-07-21 22:11:08 +01:00
Julian Kornberger aba8bbb6e3 Add collection of metrics
Data can be retreived via D-Bus und U-Bus
2018-07-21 21:55:08 +01:00
Julian Kornberger caf4d571e6 Add OpenWRT ubus patch
Originally written by John Crispin <john@phrozen.org>
2018-07-21 21:45:03 +01:00
Simon Kelley 3b6eb197a8 Log DNSSEC trust anchors at startup. 2018-07-20 21:23:56 +01:00
Simon Kelley f3e57877ed Trivial comment change. 2018-07-20 21:10:48 +01:00
Simon Kelley c851c695db Log failure to confirm an address in DHCPv6. 2018-07-20 17:35:24 +01:00
Simon Kelley a3bd7e73d3 Fix missing fatal errors when parsing some command-line/config options. 2018-07-19 22:00:08 +01:00
Olivier Gayot ab5ceaf74a Document the --help option in the french manual
The option was already described in the original manual page but was not
replicated in the french translation.

Reviewed-By: Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
2018-07-19 21:17:06 +01:00
Olivier Gayot 1f2f69d4f6 Fix recurrent minor spelling mistake in french manual
The use of "peut-être" should be spelled "peut être" (without the
hyphen) unless it can be replaced by "sans doute".

It is roughly the same difference between "maybe" and "may be".

As for "doit-être", it should always be spelled "doit être".

Reviewed-By: Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
2018-07-19 21:16:41 +01:00
Olivier Gayot f361b39dea Fix some mistakes in french translation of the manual
Various typos were present along with spelling mistakes and grammar
errors. Some sentences were missing a few words to be easily
understandable.

Many of them probably remain though.

Reviewed-By: Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
2018-07-19 21:16:04 +01:00
Simon Kelley eb1fe15ca8 When replacing cache entries, preserve CNAMES which target them.
When inserting new cache records, we first delete existing records
of the same name/type, to maintain consistency. This has the side effect
of deleting any CNAMES which have the records as target. So

cname1.example CNAME record.example
cname2.example CNAME record.example

looking up cname2.example will push it into the cache, and also
push record.example. Doing that deletes any cache of cname1.example.

This changeset avoids that problem by making sure that when
deleting record.example, and re-insterting it (with the same name -important),
it uses the same struct crec, with the same uid. This preserves the existing cnames.
2018-07-18 20:59:52 +01:00
Simon Kelley 45d8a2435e Introduce UID_NONE value, for cache records which are not the target of a CNAME. 2018-07-17 21:01:14 +01:00
Simon Kelley 706d84fd10 Merge branch 'master' of ssh://thekelleys.org.uk/var/local/git/dnsmasq 2018-07-16 18:07:15 +01:00
Simon Kelley a997ca0da0 Fix sometimes missing DNSSEC RRs when DNSSEC validation not enabled.
Dnsmasq does pass on the do-bit, and return DNSSEC RRs, irrespective
of of having DNSSEC validation compiled in or enabled.

The thing to understand here is that the cache does not store all the
DNSSEC RRs, and dnsmasq doesn't have the (very complex) logic required
to determine the set of DNSSEC RRs required in an answer. Therefore if
the client wants the DNSSEC RRs, the query can not be answered from
the cache. When DNSSEC validation is enabled, any query with the
do-bit set is never answered from the cache, unless the domain is
known not to be signed: the query is always forwarded. This ensures
that the DNSEC RRs are included.

The same thing should be true when DNSSEC validation is not enabled,
but there's a bug in the logic.

line 1666 of src/rfc1035.c looks like this

 if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))

{ ...answer from cache ... }

So local stuff (hosts, DHCP, ) get answered. If the do_bit is not set
then the query is answered, and if the domain is known not to be
signed, the query is answered.

Unfortunately, if DNSSEC validation is not turned on then the
F_DNSSECOK bit is not valid, and it's always zero, so the question
always gets answered from the cache, even when the do-bit is set.

This code should look like that at line 1468, dealing with PTR queries

  if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
      !do_bit ||
      (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))

where the F_DNSSECOK bit is only used when validation is enabled.
2018-06-29 14:39:41 +01:00
Peter Pöschl 9268b5d677 Man page: uniform formatting style for options.
* Always use the long option form, except when options are introduced.
* Render options in bold, with '--' prefix.
2018-06-12 17:04:54 +01:00
Paul Maddock 51e4eeeb04 Fix address-dependent domains for IPv6.
Thanks to Paul Maddock for spotting this.
It seems to have been broken forever.
2018-06-12 16:37:40 +01:00
Simon Kelley 05ff659a3c Fix stupid infinite loop introduced by preceding commit. 2018-06-12 16:03:09 +01:00
Simon Kelley db0f488ea8 Handle some corner cases in RA contructed interfaces with addresses changing interface.
Thanks to Vladislav Grishenko for work on this.
2018-06-07 21:37:02 +01:00
Geert Stappers 7dcca6c622 Warn about the impact of cache-size on performance. 2018-06-02 18:54:04 +01:00
Simon Kelley 090856c7e6 Allow zone transfer in authoritative mode whenever auth-peer is specified. 2018-06-02 18:37:07 +01:00
Simon Kelley cc5cc8f1e0 Sane error message when pcap file header is wrong. 2018-06-02 14:45:17 +01:00
Simon Kelley c488b68e75 Handle standard and contructed dhcp-ranges on the same interface. 2018-06-02 13:06:00 +01:00
Simon Kelley 1f1873aadd Log warning on very large cachesize config, instead of truncating it. 2018-05-11 23:38:23 +01:00
Maarten de Vries 0a496f059c Do unsolicited RAs for interfaces which appear after dnsmasq startup.
I noticed that dnsmasq often wasn't sending any unsolicited RAs for me.

This turned out to happen when the interface (a bridge interface) wasn't
created yet at the time dnsmasq started. When dnsmasq is started after
the interface is created, it sends RAs as expected. I assume this also
extends to other types of virtual interfaces that are created after
dnsmasq starts.

Digging into the source, it seems to be caused by a missing call to
ra_start_unsolicited for non-template contexts in construct_worker from
src/dhcp6.c. The attached patch adds that call, but only if the
interface index or address changed to prevent doing fast RAs for no reason.

I tested it on my own server and it appears to work as expected. When
the interface is created and configured, dnsmasq does fast RAs for a
while and then settles into slow RAs.
2018-05-11 23:20:58 +01:00
Simon Kelley e27825b0ef Fix logging in previous. 2018-05-11 17:20:47 +01:00
Simon Kelley 1f60a18ea1 Retry SERVFAIL DNSSEC queries to a different server, if possible. 2018-05-11 16:44:16 +01:00
Simon Kelley a0088e8364 Handle query retry on REFUSED or SERVFAIL for DNSSEC-generated queries. 2018-05-10 21:43:14 +01:00
Simon Kelley 34e26e14c5 Retry query to other servers on receipt of SERVFAIL rcode. 2018-05-10 20:54:57 +01:00
Simon Kelley 6b17335209 Add packet-dump debugging facility. 2018-05-08 18:32:14 +01:00
Simon Kelley 07ed585c38 Add logging for DNS error returns from upstream and local configuration. 2018-05-04 21:52:22 +01:00
Simon Kelley 0669ee7a69 Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip are set. 2018-05-04 16:46:24 +01:00
Simon Kelley f84e674d8a Be persistent with broken-upstream-DNSSEC warnings. 2018-05-04 16:29:57 +01:00
Simon Kelley 7f0084316a Handle DNSSEC-unaware upstream servers better. 2018-04-15 20:01:49 +01:00
Simon Kelley a6918530ce Change default for dnssec-check-unsigned. 2018-04-15 16:20:52 +01:00
Simon Kelley 4e72fec660 Fix DNSSEC without dnssec-check-unsigned.
An oversight meant that non-existance checking was being done
anyway.

(Should probably alter the default for this.)
2018-04-11 22:49:31 +01:00
Simon Kelley 4441cf762c Fix DNS server fd garbage collection.
If we're talking to upstream servers from a fixed port, specified by query-port
we create the fds to do this once, before dropping root, so that ports <1024 can be used.

But we call check_servers() before reading /etc/resolv.conf, so if the only servers
are in resolv.conf, at that point there will be no servers, and the fds get garbage
collected away, only to be recreated (but without root) after we read /etc/resolv.conf

Make pre-allocated server fds immortal, to avoid this problem.
2018-04-10 21:39:54 +01:00
Simon Kelley e83915d10d Set V6ONLY on DNS upstream socket.
If query-port is set, we create sockets bound to the wildcard address and the query port for
IPv4 and IPv6, but the IPv6 one fails, because is covers IPv4 as well, and an IPv4 socket
already exists (it gets created first). Set V6ONLY to avoid this.
2018-04-10 21:27:26 +01:00
Kevin Darbyshire-Bryant 6d37924b86 Makefile: Stop creating '-d' directory
Install-common section was creating superfluous '-d' directory in build
location.

Split the directory creation into individual install commands to cope
with cross platform differences of interpreting subsequent '-d'
arguments.  e.g. GNU appears to be fine.  Apple creates the stray
directory.

Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2018-04-07 23:00:56 +01:00
Simon Kelley f3d7974e86 Fixed bug number in changelog s/833596/883596/ 2018-03-26 13:23:59 +01:00
Simon Kelley 734d53176f Add RFC4039 rapid commit support. 2018-03-23 23:09:53 +00:00
Simon Kelley 9a7be47614 Add lintian override in Debian package. 2018-03-23 20:45:53 +00:00
Simon Kelley 26e27d0015 Symbolic link for /usr/share/doc/dnsmasq-base-lua in Debian package. 2018-03-18 17:29:12 +00:00
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
83 changed files with 11424 additions and 8777 deletions

No files matched your search

+2 -3
View File
@@ -7,9 +7,8 @@ src/.copts_*
contrib/lease-tools/dhcp_lease_time contrib/lease-tools/dhcp_lease_time
contrib/lease-tools/dhcp_release contrib/lease-tools/dhcp_release
contrib/lease-tools/dhcp_release6 contrib/lease-tools/dhcp_release6
debian/base/
debian/daemon/
debian/files debian/files
debian/substvars debian/substvars
debian/utils-substvars debian/utils-substvars
debian/utils/ debian/trees/
debian/build/
+1952 -1733
View File
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -1010,7 +1010,7 @@ release 2.9
but to the address of another interface were ignored but to the address of another interface were ignored
unless the loopback interface was explicitly configured. unless the loopback interface was explicitly configured.
2) on OpenBSD failure to configure one interface now 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 stream of log messages. Thanks to Erik Jan Tromp for
finding that bug. finding that bug.
@@ -2067,7 +2067,7 @@ version 2.36
kernel. Thanks to Philip Wall for the bug report. kernel. Thanks to Philip Wall for the bug report.
Added --dhcp-bridge option, but only to the FreeBSD 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 network configuration on FreeBSD. Thanks to Luigi Rizzo
for the patch. for the patch.
@@ -2273,7 +2273,7 @@ version 2.40
this. this.
Use client-id as hash-seed for DHCP address allocation 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. address.
Tweaked TFTP file-open code to make it behave sensibly 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 Add --dhcp-match flag, to check for arbitrary options in
DHCP messages from clients. This enables use of dnsmasq 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 Added --dhcp-broadcast, to force broadcast replies to DHCP
clients which need them but are too dumb or too old to clients which need them but are too dumb or too old to
+3 -3
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. 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 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. which dnsmasq has forwarded, otherwise they are dropped too.
Addendum: dnsmasq now has the option "query-port" (-Q), which allows 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 by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
mode, such interfaces are handled normally. 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 error at start-up when in --bind-interfaces mode, by just generates a
warning in wildcard or bind-dynamic mode. 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? 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. 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 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. on a network, and another DHCP server may be dealing with the client.
+6 -4
View File
@@ -53,6 +53,7 @@ top?=$(CURDIR)
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1` dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1` dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS $(PKG_CONFIG) --copy -lubox -lubus`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn` 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` 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_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
@@ -76,16 +77,16 @@ 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 \ 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 \ 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 \ 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 dump.o ubus.o metrics.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h dns-protocol.h radv-protocol.h ip6addr.h metrics.h
all : $(BUILDDIR) all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \ @cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \ top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \ 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)" \ build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
-f $(top)/Makefile dnsmasq -f $(top)/Makefile dnsmasq
mostly_clean : mostly_clean :
@@ -100,7 +101,8 @@ clean : mostly_clean
install : all install-common install : all install-common
install-common : install-common :
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8 $(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8 $(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR) $(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
+2 -1
View File
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \ radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.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 dump.c ubus.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
+5 -5
View File
@@ -83,7 +83,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
if (p >= end - 2) if (p >= end - 2)
return NULL; /* malformed packet */ return NULL; /* malformed packet */
opt_len = option_len(p); opt_len = option_len(p);
if (p >= end - (2 + opt_len)) if (end - p >= (2 + opt_len))
return NULL; /* malformed packet */ return NULL; /* malformed packet */
if (*p == opt && opt_len >= minsize) if (*p == opt && opt_len >= minsize)
return p; return p;
@@ -206,13 +206,13 @@ int main(int argc, char **argv)
{ {
unsigned int x; unsigned int x;
if ((x = t/86400)) if ((x = t/86400))
printf("%dd", x); printf("%ud", x);
if ((x = (t/3600)%24)) if ((x = (t/3600)%24))
printf("%dh", x); printf("%uh", x);
if ((x = (t/60)%60)) if ((x = (t/60)%60))
printf("%dm", x); printf("%um", x);
if ((x = t%60)) if ((x = t%60))
printf("%ds", x); printf("%us", x);
} }
return 0; return 0;
} }
+2 -1
View File
@@ -270,7 +270,8 @@ int main(int argc, char **argv)
/* This voodoo fakes up a packet coming from the correct interface, which really matters for /* This voodoo fakes up a packet coming from the correct interface, which really matters for
a DHCP server */ a DHCP server */
strcpy(ifr.ifr_name, argv[1]); strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
{ {
perror("cannot setup interface"); perror("cannot setup interface");
+325 -271
View File
@@ -46,7 +46,8 @@ typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
typedef unsigned int u32; typedef unsigned int u32;
enum DHCP6_TYPES{ enum DHCP6_TYPES
{
SOLICIT = 1, SOLICIT = 1,
ADVERTISE = 2, ADVERTISE = 2,
REQUEST = 3, REQUEST = 3,
@@ -61,8 +62,10 @@ enum DHCP6_TYPES{
RELAY_FORW = 12, RELAY_FORW = 12,
RELAY_REPL = 13 RELAY_REPL = 13
}; };
enum DHCP6_OPTIONS{
enum DHCP6_OPTIONS
{
CLIENTID = 1, CLIENTID = 1,
SERVERID = 2, SERVERID = 2,
IA_NA = 3, IA_NA = 3,
@@ -82,25 +85,27 @@ enum DHCP6_OPTIONS{
INTERFACE_ID = 18, INTERFACE_ID = 18,
RECONF_MSG = 19, RECONF_MSG = 19,
RECONF_ACCEPT = 20, RECONF_ACCEPT = 20,
}; };
enum DHCP6_STATUSES{ enum DHCP6_STATUSES
{
SUCCESS = 0, SUCCESS = 0,
UNSPEC_FAIL = 1, UNSPEC_FAIL = 1,
NOADDR_AVAIL=2, NOADDR_AVAIL=2,
NO_BINDING = 3, NO_BINDING = 3,
NOT_ON_LINK = 4, NOT_ON_LINK = 4,
USE_MULTICAST =5 USE_MULTICAST =5
}; };
static struct option longopts[] = { static struct option longopts[] = {
{"ip", required_argument, 0, 'a'}, {"ip", required_argument, 0, 'a' },
{"server-id", required_argument, 0, 's'}, {"server-id", required_argument, 0, 's' },
{"client-id", required_argument, 0, 'c'}, {"client-id", required_argument, 0, 'c' },
{"iface", required_argument, 0, 'n'}, {"iface", required_argument, 0, 'n' },
{"iaid", required_argument, 0, 'i'}, {"iaid", required_argument, 0, 'i' },
{"dry-run", no_argument, 0, 'd'}, {"dry-run", no_argument, 0, 'd' },
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h' },
{0, 0, 0, 0} {0, 0, 0, 0 }
}; };
const short DHCP6_CLIENT_PORT = 546; const short DHCP6_CLIENT_PORT = 546;
@@ -108,207 +113,230 @@ const short DHCP6_SERVER_PORT = 547;
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2"; const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
struct dhcp6_option{ struct dhcp6_option {
uint16_t type; uint16_t type;
uint16_t len; uint16_t len;
char value[1024]; char value[1024];
}; };
struct dhcp6_iaaddr_option{ struct dhcp6_iaaddr_option {
uint16_t type; uint16_t type;
uint16_t len; uint16_t len;
struct in6_addr ip; struct in6_addr ip;
uint32_t preferred_lifetime; uint32_t preferred_lifetime;
uint32_t valid_lifetime; uint32_t valid_lifetime;
}; };
struct dhcp6_iana_option{ struct dhcp6_iana_option {
uint16_t type; uint16_t type;
uint16_t len; uint16_t len;
uint32_t iaid; uint32_t iaid;
uint32_t t1; uint32_t t1;
uint32_t t2; uint32_t t2;
char options[1024]; char options[1024];
}; };
struct dhcp6_packet{ struct dhcp6_packet {
size_t len; size_t len;
char buf[2048]; char buf[2048];
};
} ;
size_t pack_duid(const char* str, char* dst){ size_t pack_duid(const char* str, char* dst)
{
char* tmp = strdup(str); char* tmp = strdup(str);
char* tmp_to_free = tmp; char* tmp_to_free = tmp;
char *ptr; char *ptr;
uint8_t write_pos = 0; uint8_t write_pos = 0;
while ((ptr = strtok (tmp, ":"))) { while ((ptr = strtok (tmp, ":")))
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16); {
write_pos += 1; dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
tmp = NULL; 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 create_client_id_option(const char* duid)
struct dhcp6_option option; {
option.type = htons(CLIENTID); struct dhcp6_option option;
bzero(option.value, sizeof(option.value)); option.type = htons(CLIENTID);
option.len = htons(pack_duid(duid, option.value)); bzero(option.value, sizeof(option.value));
return option; option.len = htons(pack_duid(duid, option.value));
return option;
} }
struct dhcp6_option create_server_id_option(const char* duid){ struct dhcp6_option create_server_id_option(const char* duid)
struct dhcp6_option option; {
option.type = htons(SERVERID); struct dhcp6_option option;
bzero(option.value, sizeof(option.value)); option.type = htons(SERVERID);
option.len = htons(pack_duid(duid, option.value)); bzero(option.value, sizeof(option.value));
return option; option.len = htons(pack_duid(duid, option.value));
return option;
} }
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){ struct dhcp6_iaaddr_option create_iaadr_option(const char* ip)
struct dhcp6_iaaddr_option result; {
result.type =htons(IAADDR); struct dhcp6_iaaddr_option result;
/* no suboptions needed here, so length is 24 */ result.type =htons(IAADDR);
result.len = htons(24); /* no suboptions needed here, so length is 24 */
result.preferred_lifetime = 0; result.len = htons(24);
result.valid_lifetime = 0; result.preferred_lifetime = 0;
int s = inet_pton(AF_INET6, ip, &(result.ip)); result.valid_lifetime = 0;
if (s <= 0) { int s = inet_pton(AF_INET6, ip, &(result.ip));
if (s == 0) if (s <= 0) {
fprintf(stderr, "Not in presentation format"); if (s == 0)
else fprintf(stderr, "Not in presentation format");
perror("inet_pton"); else
exit(EXIT_FAILURE); perror("inet_pton");
} exit(EXIT_FAILURE);
return result; }
}
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){ return result;
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_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){ struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr)
struct dhcp6_packet result; {
bzero(result.buf, sizeof(result.buf)); struct dhcp6_iana_option result;
/* message_type */ result.type = htons(IA_NA);
result.buf[0] = RELEASE; result.iaid = htonl(atoi(iaid));
/* tx_id */ result.t1 = 0;
bzero(result.buf+1, 3); result.t2 = 0;
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
struct dhcp6_option client_option = create_client_id_option(client_id); memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
struct dhcp6_option server_option = create_server_id_option(server_id); return result;
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){ struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id)
size_t current_pos = 0; {
char option_value[1024]; struct dhcp6_packet result;
while (current_pos < len) { bzero(result.buf, sizeof(result.buf));
uint16_t option_type, option_len; /* message_type */
memcpy(&option_type,buf + current_pos, sizeof(uint16_t)); result.buf[0] = RELEASE;
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t)); /* tx_id */
option_type = ntohs(option_type); bzero(result.buf+1, 3);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t); struct dhcp6_option client_option = create_client_id_option(client_id);
if (option_type == STATUS_CODE){ struct dhcp6_option server_option = create_server_id_option(server_id);
uint16_t status; struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
memcpy(&status, buf + current_pos, sizeof(uint16_t)); struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
status = ntohs(status); int offset = 4;
if (status != SUCCESS){ memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t)); offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
option_value[option_len-sizeof(uint16_t)] ='\0'; memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
fprintf(stderr, "Error: %s\n", option_value); 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){ int16_t parse_packet(char* buf, size_t len)
uint8_t type = buf[0]; {
/*skipping tx id. you need it, uncomment following line int16_t ret = -1;
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]); uint8_t type = buf[0];
*/ /*skipping tx id. you need it, uncomment following line
size_t current_pos = 4; uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
if (type != REPLY ){ */
return NOT_REPLY_CODE; size_t current_pos = 4;
} if (type != REPLY )
char option_value[1024]; return NOT_REPLY_CODE;
while (current_pos < len) {
uint16_t option_type, option_len; char option_value[1024];
memcpy(&option_type,buf + current_pos, sizeof(uint16_t)); while (current_pos < len)
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t)); {
option_type = ntohs(option_type); uint16_t option_type, option_len;
option_len = ntohs(option_len); memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
current_pos += 2 * sizeof(uint16_t); memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
if (option_type == STATUS_CODE){ option_type = ntohs(option_type);
uint16_t status; option_len = ntohs(option_len);
memcpy(&status, buf + current_pos, sizeof(uint16_t)); current_pos += 2 * sizeof(uint16_t);
status = ntohs(status); if (option_type == STATUS_CODE)
if (status != SUCCESS){ {
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t)); uint16_t status;
fprintf(stderr, "Error: %d %s\n", status, option_value); memcpy(&status, buf + current_pos, sizeof(uint16_t));
return status; 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){ 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); 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){ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
{
struct sockaddr_in6 server_addr, client_addr; struct sockaddr_in6 server_addr, client_addr;
char response[1400]; char response[1400];
int sock = socket(PF_INET6, SOCK_DGRAM, 0); int sock = socket(PF_INET6, SOCK_DGRAM, 0);
int i = 0; int i = 0;
if (sock < 0) { if (sock < 0)
perror("creating socket"); {
return -1; 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"); perror("SO_BINDTODEVICE");
close(sock); close(sock);
return -1; return -1;
} }
memset(&server_addr, 0, sizeof(server_addr)); memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6; server_addr.sin6_family = AF_INET6;
client_addr.sin6_family = AF_INET6; client_addr.sin6_family = AF_INET6;
@@ -320,126 +348,152 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet){
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr); inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
server_addr.sin6_port = htons(DHCP6_SERVER_PORT); server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
int16_t recv_size = 0; int16_t recv_size = 0;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++)
if (sendto(sock, packet->buf, packet->len, 0, {
(struct sockaddr *)&server_addr, if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
sizeof(server_addr)) < 0) { {
perror("sendto failed"); perror("sendto failed");
exit(4); exit(4);
} }
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0); recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
if (recv_size == -1){ if (recv_size == -1)
if (errno == EAGAIN){ {
sleep(1); if (errno == EAGAIN)
continue; {
}else { sleep(1);
continue;
}
else
{
perror("recvfrom"); perror("recvfrom");
} }
} }
int16_t result = parse_packet(response, recv_size); int16_t result = parse_packet(response, recv_size);
if (result == NOT_REPLY_CODE){ if (result == NOT_REPLY_CODE)
{
sleep(1); sleep(1);
continue; continue;
} }
close(sock);
return result; return result;
} }
close(sock);
fprintf(stderr, "Response timed out\n"); fprintf(stderr, "Response timed out\n");
return -1; return -1;
} }
int main(int argc, char * const argv[]) { int main(int argc, char * const argv[])
const char* UNINITIALIZED = ""; {
const char* iface = UNINITIALIZED; const char* UNINITIALIZED = "";
const char* ip = UNINITIALIZED; const char* iface = UNINITIALIZED;
const char* client_id = UNINITIALIZED; const char* ip = UNINITIALIZED;
const char* server_id = UNINITIALIZED; const char* client_id = UNINITIALIZED;
const char* iaid = UNINITIALIZED; const char* server_id = UNINITIALIZED;
int dry_run = 0; const char* iaid = UNINITIALIZED;
while (1) { int dry_run = 0;
int option_index = 0; while (1)
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index); {
if (c == -1){ int option_index = 0;
break; int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
} if (c == -1)
switch(c){ break;
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();
}
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"); if (iaid == UNINITIALIZED)
usage(argv[0], stderr); {
return -1; 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"); fprintf(stderr, "Missing required server-id parameter\n");
usage(argv[0], stderr); usage(argv[0], stderr);
return -1; return -1;
} }
if (client_id == UNINITIALIZED){
if (client_id == UNINITIALIZED)
{
fprintf(stderr, "Missing required client-id parameter\n"); fprintf(stderr, "Missing required client-id parameter\n");
usage(argv[0], stderr); usage(argv[0], stderr);
return -1; return -1;
} }
if (ip == UNINITIALIZED){
if (ip == UNINITIALIZED)
{
fprintf(stderr, "Missing required ip parameter\n"); fprintf(stderr, "Missing required ip parameter\n");
usage(argv[0], stderr); usage(argv[0], stderr);
return -1; 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); usage(argv[0], stderr);
return -1; return -1;
} }
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id); struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
if (dry_run){
if (dry_run)
{
uint16_t i; 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"); printf("\n");
return 0; return 0;
} }
return send_release_packet(iface, &packet); return send_release_packet(iface, &packet);
} }
+1 -1
View File
@@ -3,7 +3,7 @@
STATUS_FILE="/tmp/dnsmasq-ip-mac.status" STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
# Script for dnsmasq lease-change hook. # 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 # one lease per line. Works with IPv4 and IPv6 leases, file is
# atomically updated, so no races for users of the data. # atomically updated, so no races for users of the data.
+10
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
@@ -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;
+4
View File
@@ -243,6 +243,10 @@ IPv4 or IPv6 address of the lease to remove.
Note that this function will trigger the DhcpLeaseRemoved signal and the Note that this function will trigger the DhcpLeaseRemoved signal and the
configured DHCP lease script will be run with the "del" action. configured DHCP lease script will be run with the "del" action.
GetMetrics
----------
Returns an array with various metrics for DNS and DHCP.
2. SIGNALS 2. SIGNALS
+49 -1
View File
@@ -1,3 +1,51 @@
dnsmasq (2.80-1) unstable; urgency=low
* New upstream. (closes: #837602) (closes: #794640) (closes: #794636)
* Close old bugs, long agp fixed. (closes: #802845) (closes: #754299)
* Provide usr/lib/tmpfiles.d/dnsmasq.conf. (closes: #872396)
* Run restorecon on /run/dnsmasq for SE Linux. (closes: #872397)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 17 Sep 2018 23:11:25 +0000
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: #883596)
* 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 dnsmasq (2.77-1) unstable; urgency=low
* New upstream. * New upstream.
@@ -5,7 +53,7 @@ dnsmasq (2.77-1) unstable; urgency=low
includes port=0 to disable DNS. includes port=0 to disable DNS.
* Handle gratuitous format change in /usr/share/dns/root.ds * Handle gratuitous format change in /usr/share/dns/root.ds
(closes: #858506) (closes: #860064) (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 -- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
+21 -3
View File
@@ -3,13 +3,15 @@ Section: net
Priority: optional Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev, 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> Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
Standards-Version: 3.9.8 Standards-Version: 3.9.8
Package: dnsmasq Package: dnsmasq
Architecture: all Architecture: all
Depends: netbase, dnsmasq-base(>= ${binary:Version}), Depends: netbase, dnsmasq-base,
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6) init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
Suggests: resolvconf Suggests: resolvconf
Conflicts: resolvconf (<<1.15) Conflicts: resolvconf (<<1.15)
@@ -27,13 +29,29 @@ Package: dnsmasq-base
Architecture: any Architecture: any
Depends: adduser, ${shlibs:Depends} Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~) Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~) Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
Recommends: dns-root-data Recommends: dns-root-data
Provides: dnsmasq-base
Conflicts: dnsmasq-base-lua
Description: Small caching DNS proxy and DHCP/TFTP server Description: Small caching DNS proxy and DHCP/TFTP server
This package contains the dnsmasq executable and documentation, but This package contains the dnsmasq executable and documentation, but
not the infrastructure required to run it as a system daemon. For not the infrastructure required to run it as a system daemon. For
that, install the dnsmasq package. 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 Package: dnsmasq-utils
Architecture: linux-any Architecture: linux-any
Depends: ${shlibs:Depends} Depends: ${shlibs:Depends}
+1 -1
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/ It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
Vendored
+3 -2
View File
@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
ROOT_DS="/usr/share/dns/root.ds" ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then 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 fi
start() start()
@@ -127,7 +127,8 @@ start()
mkdir /run/dnsmasq || return 2 mkdir /run/dnsmasq || return 2
chown dnsmasq:nogroup /run/dnsmasq || return 2 chown dnsmasq:nogroup /run/dnsmasq || return 2
fi fi
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1 start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \ start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
-x /run/dnsmasq/$NAME.pid \ -x /run/dnsmasq/$NAME.pid \
+3
View File
@@ -0,0 +1,3 @@
# dnsmasq-base and dnsmasq-base-lua are mutually exclusive and both
# provide /usr/share/doc/dnsmasq-base
dnsmasq-base-lua binary: usr-share-doc-symlink-without-dependency dnsmasq-base
+1 -1
View File
@@ -54,7 +54,7 @@ Notes on configuring dnsmasq as packaged for Debian.
nodhcp : omit DHCP support. nodhcp : omit DHCP support.
nodhcp6 : omit DHCPv6 support. nodhcp6 : omit DHCPv6 support.
noscript : omit lease-change script 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. in Lua.
noipv6 : omit IPv6 support. noipv6 : omit IPv6 support.
nodbus : omit DBus support. nodbus : omit DBus support.
+155 -111
View File
@@ -1,6 +1,6 @@
#!/usr/bin/make -f #!/usr/bin/make -f
# debian/rules file - for dnsmasq. # 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: # Based on the sample in the debian hello package which carries the following:
# Copyright 1994,1995 by Ian Jackson. # Copyright 1994,1995 by Ian Jackson.
# I hereby give you perpetual unlimited permission to copy, # I hereby give you perpetual unlimited permission to copy,
@@ -103,128 +103,172 @@ ifneq ($(DEB_HOST_ARCH_OS),linux)
LDFLAGS += -lbsd LDFLAGS += -lbsd
endif endif
clean: define build_tree
$(checkdir) rm -rf $1
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
install -m 755 \ install -m 755 \
-d debian/daemon/DEBIAN \ -d $1/DEBIAN \
-d debian/daemon/usr/share/doc \ -d $1/etc/dbus-1/system.d \
-d debian/daemon/etc/init.d \ -d $1/usr/share/doc/$(package) \
-d debian/daemon/etc/dnsmasq.d \ -d $1/usr/share/doc/$(package)/examples \
-d debian/daemon/etc/resolvconf/update.d \ -d $1/usr/share/$(package) \
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \ -d $1/var/lib/misc
-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 ..
binary-arch: checkroot endef
$(checkdir)
rm -rf debian/base define add_docs
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)))
# Need to remove paypal links in Debian Package for policy reasons. # 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 sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >$1/usr/share/doc/$(package)/doc.html
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html echo "</BODY>" >>$1/usr/share/doc/$(package)/doc.html
install -m 644 setup.html debian/base/usr/share/doc/$(package)/. install -m 644 setup.html $1/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/. install -m 644 dnsmasq.conf.example $1/usr/share/doc/$(package)/examples/.
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/. install -m 644 FAQ $1/usr/share/doc/$(package)/.
install -m 644 FAQ debian/base/usr/share/doc/$(package)/. gzip -9n $1/usr/share/doc/$(package)/FAQ
gzip -9n debian/base/usr/share/doc/$(package)/FAQ install -m 644 CHANGELOG $1/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog gzip -9n $1/usr/share/doc/$(package)/changelog
gzip -9n debian/base/usr/share/doc/$(package)/changelog install -m 644 CHANGELOG.archive $1/usr/share/doc/$(package)/changelog.archive
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive gzip -9n $1/usr/share/doc/$(package)/changelog.archive
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/. gzip -9n $1/usr/share/doc/$(package)/DBus-interface
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface gzip -9n $1/usr/share/man/man8/dnsmasq.8
endif for f in $1/usr/share/man/*; do \
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 \
if [ -f $$f/man8/dnsmasq.8 ]; then \ if [ -f $$f/man8/dnsmasq.8 ]; then \
gzip -9n $$f/man8/dnsmasq.8 ; \ gzip -9n $$f/man8/dnsmasq.8 ; \
fi \ fi \
done done
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) endef
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
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/usr/lib/tmpfiles.d \
-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/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
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 endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums $(call add_files,debian/trees/base)
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base $(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/base/usr/sbin/dnsmasq
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)' endif
chown -R root.root debian/base cd debian/trees/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
chmod -R g-ws debian/base dpkg-shlibdeps --warnings=1 debian/trees/base/usr/sbin/dnsmasq
dpkg --build debian/base .. 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)
install -m 755 -d debian/trees/lua-base/usr/share/lintian/overrides
install -m 644 debian/lintian-override debian/trees/lua-base/usr/share/lintian/overrides/dnsmasq-base-lua
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/lua-base/usr/sbin/dnsmasq
endif
ln -s $(package) debian/trees/lua-base/usr/share/doc/dnsmasq-base-lua
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) ifeq ($(DEB_HOST_ARCH_OS),linux)
rm -rf debian/utils rm -rf debian/trees/utils
install -m 755 -d debian/utils/DEBIAN \ install -m 755 -d debian/trees/utils/DEBIAN \
-d debian/utils/usr/share/man/man1 \ -d debian/trees/utils/usr/bin \
-d debian/utils/usr/bin \ -d debian/trees/utils/usr/share/doc/dnsmasq-utils
-d debian/utils/usr/share/doc/dnsmasq-utils ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
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 -d debian/trees/utils/usr/share/man/man1
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release endif
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1 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)
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1 install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6 install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1 install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1 ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time install -m 644 contrib/lease-tools/dhcp_release.1 debian/trees/utils/usr/share/man/man1/dhcp_release.1
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1 gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release.1
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright install -m 644 contrib/lease-tools/dhcp_release6.1 debian/trees/utils/usr/share/man/man1/dhcp_release6.1
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release6.1
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
gzip -9n debian/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))) 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/trees/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/trees/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_lease_time
endif endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums 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/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time 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/utils dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/trees/utils
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)' find debian/trees/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/utils chown -R root.root debian/trees/utils
chmod -R g-ws debian/utils chmod -R g-ws debian/trees/utils
dpkg --build debian/utils .. dpkg --build debian/trees/utils ..
endif endif
define checkdir define checkdir
-1
View File
@@ -1 +0,0 @@
libnettle 6 libnettle6 (>= 3.3)
+1
View File
@@ -0,0 +1 @@
d /run/dnsmasq 755 dnsmasq nogroup
+21 -13
View File
@@ -90,7 +90,7 @@
# server=10.1.2.3@eth1 # server=10.1.2.3@eth1
# and this sets the source (ie local) address used to talk to # 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). # IP on the machine, obviously).
# server=10.1.2.3@192.168.1.1#55 # server=10.1.2.3@192.168.1.1#55
@@ -288,7 +288,7 @@
# Give a fixed IPv6 address and name to client with # 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 # 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 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] #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 # 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 # Set option 58 client renewal time (T1). Defaults to half of the
# lease time if not specified. (RFC2132) # 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 # Set option 59 rebinding time (T2). Defaults to 7/8 of the
# lease time if not specified. (RFC2132) # 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 # Set the NTP time server address to be the same machine as
# is running dnsmasq # is running dnsmasq
@@ -436,22 +436,22 @@
#dhcp-option-force=211,30i #dhcp-option-force=211,30i
# Set the boot filename for netboot/PXE. You will only need # 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 # 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 # a TFTP server; either dnsmasq's built-in TFTP server or an
# external one. (See below for how to enable the TFTP server.) # external one. (See below for how to enable the TFTP server.)
#dhcp-boot=pxelinux.0 #dhcp-boot=pxelinux.0
# The same as above, but use custom tftp-server instead machine running dnsmasq # The same as above, but use custom tftp-server instead machine running dnsmasq
#dhcp-boot=pxelinux,server.name,192.168.1.100 #dhcp-boot=pxelinux,server.name,192.168.1.100
# Boot for Etherboot gPXE. The idea is to send two different # Boot for iPXE. The idea is to send two different
# filenames, the first loads gPXE, and the second tells gPXE what to # filenames, the first loads iPXE, and the second tells iPXE what to
# load. The dhcp-match sets the gpxe tag for requests from gPXE. # load. The dhcp-match sets the ipxe tag for requests from iPXE.
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option. #dhcp-boot=undionly.kpxe
#dhcp-boot=tag:!gpxe,undionly.kpxe #dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
#dhcp-boot=mybootimage #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 # encapsulated within option 175
#dhcp-option=encap:175, 1, 5b # priority code #dhcp-option=encap:175, 1, 5b # priority code
#dhcp-option=encap:175, 176, 1b # no-proxydhcp #dhcp-option=encap:175, 176, 1b # no-proxydhcp
@@ -547,6 +547,14 @@
# http://www.isc.org/files/auth.html # http://www.isc.org/files/auth.html
#dhcp-authoritative #dhcp-authoritative
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
# option with a DHCPACK including a Rapid Commit option and fully committed address
# and configuration information. This must only be enabled if either the server is
# the only server for the subnet, or multiple servers are present and they each
# commit a binding for all clients.
#dhcp-rapid-commit
# Run an executable when a DHCP lease is created or destroyed. # Run an executable when a DHCP lease is created or destroyed.
# The arguments sent to the script are "add" or "del", # The arguments sent to the script are "add" or "del",
# then the MAC address, the IP address and finally the hostname # then the MAC address, the IP address and finally the hostname
+4
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> <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> <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 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. for details.
+214 -173
View File
File diff suppressed because it is too large. Load diff
+2 -1
View File
@@ -478,7 +478,8 @@ la traza reversa direcci
.TP .TP
.B \-c, --cache-size=<tamaño de caché> .B \-c, --cache-size=<tamaño de caché>
Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres. Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres.
Fijar el tamaño a cero deshabilita el caché. Fijar el tamaño a cero deshabilita el caché. Nota: el gran tamaño de
caché afecta el rendimiento.
.TP .TP
.B \-N, --no-negcache .B \-N, --no-negcache
Deshabilitar caché negativo. El caché negativo le permite a dnsmasq Deshabilitar caché negativo. El caché negativo le permite a dnsmasq
+123 -115
View File
@@ -10,7 +10,7 @@ est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
local (LAN). local (LAN).
.PP .PP
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache Dnsmasq accepte les requêtes DNS et y répond soit en utilisant un petit cache
local, soit en effectuant une requête à un serveur DNS récursif externe (par local, soit en effectuant une requête à un serveur DNS récursif externe (par
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
@@ -19,25 +19,25 @@ pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
noms locaux d'apparaitre dans le DNS global. noms locaux d'apparaitre dans le DNS global.
.PP .PP
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les Le serveur DHCP de Dnsmasq supporte les définitions d'adresses statiques et les
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP, réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
et peut être configuré pour fournir n'importe quelle option DHCP. et peut être configuré pour fournir n'importe quelle option DHCP.
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
support PXE est complet, et comprend un mode proxy permettant de fournir des support PXE est complet, et comprend un mode proxy permettant de fournir des
informations PXE aux clients alors que l'allocation DHCP est effectuée par un informations PXE aux clients alors que l'allocation d'adresse via DHCP est
autre serveur. effectuée par un autre serveur.
.PP .PP
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionnalités
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
qu'une fonctionalité permettant l'addition de ressources AAAA pour des qu'une fonctionnalité permettant l'addition de ressources AAAA pour des
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
autoconfiguration). autoconfiguration).
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
une délégation de préfixe DHCPv6. une délégation de préfixe DHCPv6.
.PP .PP
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir Dnsmasq est développé pour de petits systèmes embarqués. Il tend à avoir
l'empreinte mémoire la plus faible possible pour les fonctions supportées, l'empreinte mémoire la plus faible possible pour les fonctions supportées,
et permet d'exclure les fonctions inutiles du binaire compilé. et permet d'exclure les fonctions inutiles du binaire compilé.
.SH OPTIONS .SH OPTIONS
@@ -46,16 +46,23 @@ Dans ce cas, la fonction correspondante sera désactivée. Par exemple
.B --pid-file= .B --pid-file=
(sans paramètre après le =) désactive l'écriture du fichier PID. (sans paramètre après le =) désactive l'écriture du fichier PID.
Sur BSD, à moins que le logiciel ne soit compilé avec la bibliothèque GNU Sur BSD, à moins que le logiciel ne soit compilé avec la bibliothèque GNU
getopt, la forme longue des options ne fonctionne pas en ligne de commande; Elle getopt, la forme longue des options ne fonctionne pas en ligne de commande; elle
est toujours supportée dans le fichier de configuration. est toujours supportée dans le fichier de configuration.
.TP .TP
.B --test .B --test
Vérifie la syntaxe du ou des fichiers de configurations. Se termine avec le Vérifie la syntaxe du ou des fichiers de configuration. Se termine avec le
code de retour 0 si tout est OK, ou un code différent de 0 dans le cas code de retour 0 si tout est OK, ou un code différent de 0 dans le cas
contraire. Ne démarre pas Dnsmasq. contraire. Ne démarre pas Dnsmasq.
.TP .TP
.B \-w, --help
Affiche toutes les options de ligne de commande.
.B --help dhcp
affiche les options de configuration connues pour DHCPv4, et
.B --help dhcp6
affiche les options de configuration connues pour DHCPv6.
.TP
.B \-h, --no-hosts .B \-h, --no-hosts
Ne pas charger les noms du fichier /etc/hosts. Ne pas charger les noms d'hôtes du fichier /etc/hosts.
.TP .TP
.B \-H, --addn-hosts=<fichier> .B \-H, --addn-hosts=<fichier>
Fichiers d'hôtes additionnels. Lire le fichier spécifié en plus de /etc/hosts. Fichiers d'hôtes additionnels. Lire le fichier spécifié en plus de /etc/hosts.
@@ -68,7 +75,7 @@ fichiers contenus dans ce répertoire.
.B \-E, --expand-hosts .B \-E, --expand-hosts
Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le
nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service
DHCP. Notez que cela ne s'applique pas au nom de domaine dans les CNAME, les DHCP. Notez que cela ne s'applique pas aux noms de domaine dans les CNAME, les
enregistrements PTR, TXT, etc... enregistrements PTR, TXT, etc...
.TP .TP
.B \-T, --local-ttl=<durée> .B \-T, --local-ttl=<durée>
@@ -86,7 +93,7 @@ Les réponses négatives provenant des serveurs amonts contiennent normalement
une information de durée de vie (time-to-live) dans les enregistrements SOA, une information de durée de vie (time-to-live) dans les enregistrements SOA,
information dont dnsmasq se sert pour mettre la réponse en cache. Si la réponse information dont dnsmasq se sert pour mettre la réponse en cache. Si la réponse
du serveur amont omet cette information, dnsmasq ne cache pas la réponse. Cette du serveur amont omet cette information, dnsmasq ne cache pas la réponse. Cette
option permet de doner une valeur de durée de vie par défaut (en secondes) que option permet de donner une valeur de durée de vie par défaut (en secondes) que
dnsmasq utilise pour mettre les réponses négatives dans son cache, même en dnsmasq utilise pour mettre les réponses négatives dans son cache, même en
l'absence d'enregistrement SOA. l'absence d'enregistrement SOA.
.TP .TP
@@ -194,7 +201,7 @@ au dessus de la valeur spécifiée. Utile pour des systèmes derrière des dispo
garde-barrières ("firewalls"). garde-barrières ("firewalls").
.TP .TP
.B \-i, --interface=<nom d'interface> .B \-i, --interface=<nom d'interface>
N'écouter que sur l'interface réseau spécifiée. Dnsmasq aujoute automatiquement N'écouter que sur l'interface réseau spécifiée. Dnsmasq ajoute automatiquement
l'interface locale ("loopback") à la liste des interfaces lorsque l'option l'interface locale ("loopback") à la liste des interfaces lorsque l'option
.B --interface .B --interface
est utilisée. est utilisée.
@@ -205,13 +212,13 @@ ou
n'est donnée, Dnsmasq écoutera sur toutes les interfaces disponibles sauf n'est donnée, Dnsmasq écoutera sur toutes les interfaces disponibles sauf
celle(s) spécifiée(s) par l'option celle(s) spécifiée(s) par l'option
.B --except-interface. .B --except-interface.
Les alias d'interfaces IP (e-g "eth1:0") ne peuvent être utilisés ni avec Les alias d'interfaces IP (par exemple "eth1:0") ne peuvent être utilisés ni avec
.B --interface .B --interface
ni ni
.B \--except-interface. .B \--except-interface.
Utiliser l'option Utiliser l'option
.B --listen-address .B --listen-address
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans à la place. Un simple joker, consistant en un '*' final, peut être utilisé dans
les options les options
.B \--interface .B \--interface
et et
@@ -229,10 +236,10 @@ sont fournies n'importe pas, et que l'option
.B --except-interface .B --except-interface
l'emporte toujours sur les autres. l'emporte toujours sur les autres.
.TP .TP
.B --auth-server=<domaine>,<interface>|<addresse IP> .B --auth-server=<domaine>,<interface>|<adresse IP>
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
pas besoin d'être mentionées ni dans pas besoin d'être mentionnées ni dans
.B --interface .B --interface
ni dans ni dans
.B --listen-address .B --listen-address
@@ -253,7 +260,7 @@ Ecouter sur la ou les adresse(s) IP spécifiée(s). Les options
.B \--interface .B \--interface
et et
.B \--listen-address .B \--listen-address
peuvent-être spécifiées simultanément, auquel cas un jeu d'interfaces et peuvent être spécifiées simultanément, auquel cas un jeu d'interfaces et
d'adresses seront utilisées. Notez que si d'adresses seront utilisées. Notez que si
aucune option aucune option
.B \--interface .B \--interface
@@ -265,7 +272,7 @@ nécessaire de fournir explicitement son adresse IP, 127.0.0.1 via l'option
.B \--listen-address. .B \--listen-address.
.TP .TP
.B \-z, --bind-interfaces .B \-z, --bind-interfaces
Sur les systèmes qui le supporte, Dnsmasq s'associe avec l'interface joker Sur les systèmes qui le supportent, Dnsmasq s'associe avec l'interface joker
("wildcard"), même lorsqu'il ne doit écouter que sur certaines interfaces. Par ("wildcard"), même lorsqu'il ne doit écouter que sur certaines interfaces. Par
la suite, il rejette les requêtes auxquelles il ne doit pas répondre. Cette la suite, il rejette les requêtes auxquelles il ne doit pas répondre. Cette
situation présente l'avantage de fonctionner même lorsque les interfaces vont situation présente l'avantage de fonctionner même lorsque les interfaces vont
@@ -302,7 +309,7 @@ le réseau auquel ils sont attachés). Cette possibilité est actuellement limit
.TP .TP
.B \-b, --bogus-priv .B \-b, --bogus-priv
Fausse résolution inverse pour les réseaux privés. Toutes les requêtes DNS Fausse résolution inverse pour les réseaux privés. Toutes les requêtes DNS
inverses pour des adresses IP privées (ie 192.168.x.x, etc...) qui ne sont pas inverses pour des adresses IP privées (192.168.x.x, etc...) qui ne sont pas
trouvées dans /etc/hosts ou dans le fichier de baux DHCP se voient retournées trouvées dans /etc/hosts ou dans le fichier de baux DHCP se voient retournées
une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises
aux serveurs de nom amont ("upstream server"). aux serveurs de nom amont ("upstream server").
@@ -317,7 +324,7 @@ modifiera 1.2.3.56 en 6.7.8.56 et 1.2.3.67 en 6.7.8.67.
Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent
"bidouillage DNS" ("DNS doctoring"). Si l'ancienne IP est donnée sous la forme "bidouillage DNS" ("DNS doctoring"). Si l'ancienne IP est donnée sous la forme
d'une gamme d'adresses, alors seules les adresses dans cette gamme seront d'une gamme d'adresses, alors seules les adresses dans cette gamme seront
réecrites, et non le sous-réseau dans son ensemble. Ainsi, réécrites, et non le sous-réseau dans son ensemble. Ainsi,
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0 .B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
fait correspondre 192.168.0.10->192.168.0.40 à 10.0.0.10->10.0.0.40 fait correspondre 192.168.0.10->192.168.0.40 à 10.0.0.10->10.0.0.40
.TP .TP
@@ -380,7 +387,7 @@ effectuer ses requêtes à tous les serveurs disponibles. Le résultat renvoyé
au client sera celui fournit par le premier serveur ayant répondu. au client sera celui fournit par le premier serveur ayant répondu.
.TP .TP
.B --stop-dns-rebind .B --stop-dns-rebind
Rejete (et enregistre dans le journal d'activité) les adresses dans la gamme Rejette (et enregistre dans le journal d'activité) les adresses dans la gamme
d'adresses IP privée (au sens RFC1918) qui pourraient être renvoyées par les d'adresses IP privée (au sens RFC1918) qui pourraient être renvoyées par les
serveurs amonts suite à une résolution de nom. Cela bloque les attaques cherchant serveurs amonts suite à une résolution de nom. Cela bloque les attaques cherchant
à détourner de leur usage les logiciels de navigation web ('browser') en s'en à détourner de leur usage les logiciels de navigation web ('browser') en s'en
@@ -389,13 +396,13 @@ servant pour découvrir les machines situées sur le réseau local.
.B --rebind-localhost-ok .B --rebind-localhost-ok
Exclue 127.0.0/8 des vérifications de réassociation DNS. Cette gamme d'adresses Exclue 127.0.0/8 des vérifications de réassociation DNS. Cette gamme d'adresses
est retournée par les serveurs Realtime Blackhole (RBL, utilisés dans la est retournée par les serveurs Realtime Blackhole (RBL, utilisés dans la
lutte contre le spam), la bloquer peut entraîner des disfonctionnements de ces lutte contre le spam), la bloquer peut entraîner des dysfonctionnements de ces
services. services.
.TP .TP
.B --rebind-domain-ok=[<domaine>]|[[/<domaine>/[<domaine>/] .B --rebind-domain-ok=[<domaine>]|[[/<domaine>/[<domaine>/]
Ne pas détecter ni bloquer les actions de type dns-rebind pour ces domaines. Ne pas détecter ni bloquer les actions de type dns-rebind pour ces domaines.
Cette option peut prendre comme valeur soit un nom de domaine soit plusieurs Cette option peut prendre comme valeur soit un nom de domaine soit plusieurs
noms de domains entourés par des '/', selon une syntaxe similaire à l'option noms de domaine entourés par des '/', selon une syntaxe similaire à l'option
--server, c-à-d : --server, c-à-d :
.B --rebind-domain-ok=/domaine1/domaine2/domaine3/ .B --rebind-domain-ok=/domaine1/domaine2/domaine3/
.TP .TP
@@ -474,7 +481,7 @@ serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine s
laquelle tourne Dnsmasq ou sinon la ligne sera ignorée et une erreur sera laquelle tourne Dnsmasq ou sinon la ligne sera ignorée et une erreur sera
consignée dans le journal des événements, ou alors d'un nom d'interface. Si un nom consignée dans le journal des événements, ou alors d'un nom d'interface. Si un nom
d'interface est donné, alors les requêtes vers le serveur de nom seront envoyées d'interface est donné, alors les requêtes vers le serveur de nom seront envoyées
depuis cette interface; si une adresse ip est donnée, alors l'adresse source de depuis cette interface; si une adresse IP est donnée, alors l'adresse source de
la requête sera l'adresse en question. L'option query-port est ignorée pour tous la requête sera l'adresse en question. L'option query-port est ignorée pour tous
les serveurs ayant une adresse source spécifiée, mais il est possible de la donner les serveurs ayant une adresse source spécifiée, mais il est possible de la donner
directement dans la spécification de l'adresse source. Forcer les requêtes à être directement dans la spécification de l'adresse source. Forcer les requêtes à être
@@ -510,7 +517,7 @@ d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
ipset(8) pour plus de détails. ipset(8) pour plus de détails.
.TP .TP
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>] .B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préférence>]
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
l'option l'option
@@ -612,7 +619,7 @@ l'enregistrement est donnée dans les données hexadécimales, qui peuvent
être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison. être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
.TP .TP
.B --interface-name=<nom>,<interface> .B --interface-name=<nom>,<interface>
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur Définit un enregistrement DNS associant le nom avec l'adresse primaire sur
l'interface donnée en argument. Cette option spécifie un enregistrement de type l'interface donnée en argument. Cette option spécifie un enregistrement de type
A pour le nom donné en argument de la même façon que s'il était défini par une A pour le nom donné en argument de la même façon que s'il était défini par une
ligne de /etc/hosts, sauf que l'adresse n'est pas constante mais dépendante de ligne de /etc/hosts, sauf que l'adresse n'est pas constante mais dépendante de
@@ -638,7 +645,7 @@ IPv6 pouvant commencer par '::', mais les noms DNS ne pouvant pas commencer
par '-', si aucun préfixe n'est donné, un zéro est ajouté en début de nom. par '-', si aucun préfixe n'est donné, un zéro est ajouté en début de nom.
Ainsi, ::1 devient 0--1. Ainsi, ::1 devient 0--1.
La plage d'adresses peut-être de la forme La plage d'adresses peut être de la forme
<adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau> <adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau>
.TP .TP
.B --add-mac .B --add-mac
@@ -647,7 +654,7 @@ amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le
même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée, utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
aussi cette fonctionalité doit être considérée comme expérimentale. Notez aussi cette fonctionnalité doit être considérée comme expérimentale. Notez
également qu'exposer les adresses MAC de la sorte peut avoir des implications également qu'exposer les adresses MAC de la sorte peut avoir des implications
en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet
s'applique également ici. s'applique également ici.
@@ -659,19 +666,20 @@ longueur du préfixe : 32 (ou 128 dans le cas d'IPv6) transmet la totalité
de l'adresse, 0 n'en transmet aucun mais marque néanmoins la requête ce qui de l'adresse, 0 n'en transmet aucun mais marque néanmoins la requête ce qui
fait qu'aucun serveur amont ne rajoutera d'adresse client. La valeur par fait qu'aucun serveur amont ne rajoutera d'adresse client. La valeur par
défaut est zéro et pour IPv4 et pour IPv6. A noter que les serveurs amonts défaut est zéro et pour IPv4 et pour IPv6. A noter que les serveurs amonts
peuvent-être configurés pour retourner des valeurs différentes en fonction peuvent être configurés pour retourner des valeurs différentes en fonction
de cette information mais que le cache de dnsmasq n'en tient pas compte. de cette information mais que le cache de dnsmasq n'en tient pas compte.
Si une instance de dnsmasq est configurée de telle maniêre que des valeurs Si une instance de dnsmasq est configurée de telle manière que des valeurs
différentes pourraient-être rencontrés, alors le cache devrait être désactivé. différentes pourraient être rencontrées, alors le cache devrait être désactivé.
.TP .TP
.B \-c, --cache-size=<taille> .B \-c, --cache-size=<taille>
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms. Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
Définir une valeur de zéro désactive le cache. Définir une valeur de zéro désactive le cache. Remarque: la taille importante
du cache a un impact sur les performances.
.TP .TP
.B \-N, --no-negcache .B \-N, --no-negcache
Désactive le "cache négatif". Le "cache négatif" permet à Dnsmasq de se souvenir Désactive le "cache négatif". Le "cache négatif" permet à Dnsmasq de se souvenir
des réponses de type "no such domain" fournies par les serveurs DNS en amont et des réponses de type "no such domain" fournies par les serveurs DNS en amont et
de fournir les réponses sans avoir à re-transmettre les requêtes aux serveurs de fournir les réponses sans avoir à retransmettre les requêtes aux serveurs
amont. amont.
.TP .TP
.B \-0, --dns-forward-max=<nombre de requêtes> .B \-0, --dns-forward-max=<nombre de requêtes>
@@ -683,17 +691,17 @@ son journal des requêtes, ce qui peut générer un nombre important de requête
simultanées. simultanées.
.TP .TP
.B --proxy-dnssec .B --proxy-dnssec
Un resolveur sur une machine cliente peut effectuer la validation DNSSEC de Un résolveur sur une machine cliente peut effectuer la validation DNSSEC de
deux façons : il peut effectuer lui-même les opérations de chiffrements sur deux façons : il peut effectuer lui-même les opérations de chiffrements sur
la réponse reçue, ou il peut laisser le serveur récursif amont faire la la réponse reçue, ou il peut laisser le serveur récursif amont faire la
validation et positionner un drapeau dans la réponse au cas où celle-ci est validation et positionner un drapeau dans la réponse au cas où celle-ci est
correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer
la validation comme un serveur de nom récursif, cependant il peut retransmettre la validation comme un serveur de nom récursif, cependant il peut retransmettre
les résultats de validation de ses serveurs amonts. Cette option permet les résultats de validation de ses serveurs amonts. Cette option permet
l'activation de cette fonctionalité. Vous ne devriez utiliser cela que si vous l'activation de cette fonctionnalité. Vous ne devriez utiliser cela que si vous
faites confiance aux serveurs amonts faites confiance aux serveurs amonts
.I ainsi que le réseau entre vous et eux. .I ainsi que le réseau entre vous et eux.
Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des Si vous utilisez le premier mode DNSSEC, la validation par le résolveur des
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
données nécessaires par un client pour effectuer la validation lui-même. données nécessaires par un client pour effectuer la validation lui-même.
.TP .TP
@@ -703,12 +711,12 @@ Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
autorité. Les enregistrements DNS définis localement et correspondant à ce autorité. Les enregistrements DNS définis localement et correspondant à ce
domaine seront fournis. Les enregistrements A et AAAA doivent se situer dans domaine seront fournis. Les enregistrements A et AAAA doivent se situer dans
l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage DHCP l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage DHCP
(ce comportement peut-être désactivé par (ce comportement peut être désactivé par
.B constructor-noauth: .B constructor-noauth:
). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines ). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines
in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait-être de 8, 16 IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait être de 8, 16
ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa
conforme au RFC 2317. conforme au RFC 2317.
.TP .TP
@@ -719,7 +727,7 @@ optionnel, les valeurs par défaut devant convenir à la majorité des cas.
.TP .TP
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]] .B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour laquelle dnsmasq fait autorité. Ces serveurs doivent être configurés pour
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
transfert de zone, et répondre aux requêtes pour toutes les zones pour transfert de zone, et répondre aux requêtes pour toutes les zones pour
lesquelles dnsmasq fait autorité. lesquelles dnsmasq fait autorité.
@@ -733,7 +741,7 @@ seront acceptées pour tous les serveurs secondaires.
.B --conntrack .B --conntrack
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
et positionne la même marque au trafic amont utilisé pour répondre à ces et positionne la même marque au trafic amont utilisé pour répondre à ces
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes requêtes. Cela permet au trafic généré par Dnsmasq d'être associé aux requêtes
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé (accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
avec le support conntrack, le noyau doit également inclure conntrack et être avec le support conntrack, le noyau doit également inclure conntrack et être
@@ -742,7 +750,7 @@ configuré pour cela. Cette option ne peut pas être combinée avec
.TP .TP
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>] .B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
.TP .TP
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>] .B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies <adresse de début> et <adresse de fin> et à partir des adresses définies
@@ -755,7 +763,7 @@ durée indéterminée. Si aucune valeur n'est donnée, une durée de bail par d
de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2 de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2
minutes. minutes.
Pour les plages IPv6, la durée de bail peut-être égale au mot-clef "deprecated" Pour les plages IPv6, la durée de bail peut être égale au mot-clef "deprecated"
(obsolète); Cela positionne la durée de vie préférée envoyée dans les baux DHCP (obsolète); Cela positionne la durée de vie préférée envoyée dans les baux DHCP
ou les annonces routeurs à zéro, ce qui incite les clients à utiliser d'autres ou les annonces routeurs à zéro, ce qui incite les clients à utiliser d'autres
adresses autant que possible, pour toute nouvelle connexion, en préalable à adresses autant que possible, pour toute nouvelle connexion, en préalable à
@@ -795,7 +803,7 @@ adresses assignées à l'interface. Par exemple
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
plus d'un réseau, les plages correspondantes seront automatiquement créées, plus d'un réseau, les plages correspondantes seront automatiquement créées,
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis rendues obsolètes puis supprimées lorsque l'adresse est rendue obsolète puis
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*' supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
final. final.
@@ -809,7 +817,7 @@ obsolètes ne conviennent pas.
Si une plage dhcp-range est uniquement utilisée pour du DHCP sans-état Si une plage dhcp-range est uniquement utilisée pour du DHCP sans-état
("stateless") ou de l'autoconfiguration sans état ("SLAAC"), alors l'adresse ("stateless") ou de l'autoconfiguration sans état ("SLAAC"), alors l'adresse
peut-être indiquée sous la forme '::' peut être indiquée sous la forme '::'
.B --dhcp-range=::,constructor:eth0 .B --dhcp-range=::,constructor:eth0
@@ -851,7 +859,7 @@ et
.B pxe-service .B pxe-service
pour plus de détails). pour plus de détails).
Pour IPv6, le mode peut-être une combinaison des valeurs Pour IPv6, le mode peut être une combinaison des valeurs
.B ra-only, slaac, ra-names, ra-stateless, off-link. .B ra-only, slaac, ra-names, ra-stateless, off-link.
.B ra-only .B ra-only
@@ -883,7 +891,7 @@ connectés (et non ceux pour lesquels DHCP se fait via relai), et ne
fonctionnera pas si un hôte utilise les "extensions de vie privée" fonctionnera pas si un hôte utilise les "extensions de vie privée"
("privacy extensions"). ("privacy extensions").
.B ra-names .B ra-names
peut-être combiné avec peut être combiné avec
.B ra-stateless .B ra-stateless
et et
.B slaac. .B slaac.
@@ -914,7 +922,7 @@ sous-réseau qu'une plage dhcp-range valide. Pour les sous-réseaux qui n'ont pa
besoin d'adresses dynamiquement allouées, utiliser le mot-clef "static" dans la besoin d'adresses dynamiquement allouées, utiliser le mot-clef "static" dans la
déclaration de plage d'adresses dhcp-range. déclaration de plage d'adresses dhcp-range.
Il est possible d'utiliser des identifiants clients (appellé "DUID client" dans Il est possible d'utiliser des identifiants clients (appelés "DUID client" dans
le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes, le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes,
en préfixant ceux-ci par 'id:'. Ainsi, en préfixant ceux-ci par 'id:'. Ainsi,
.B --dhcp-host=id:01:02:03:04,..... .B --dhcp-host=id:01:02:03:04,.....
@@ -926,7 +934,7 @@ ceci :
Un seul Un seul
.B dhcp-host .B dhcp-host
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps. peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
Les adresses IPv6 doivent-être mises entre crochets comme suit : Les adresses IPv6 doivent être mises entre crochets comme suit :
.B --dhcp-host=laptop,[1234::56] .B --dhcp-host=laptop,[1234::56]
Les adresses IPv6 peuvent ne contenir que la partie identifiant de client : Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
.B --dhcp-host=laptop,[::56] .B --dhcp-host=laptop,[::56]
@@ -945,7 +953,7 @@ identifiant client mais pas les autres.
Si un nom apparaît dans /etc/hosts, l'adresse associée peut être allouée à un Si un nom apparaît dans /etc/hosts, l'adresse associée peut être allouée à un
bail DHCP mais seulement si une option bail DHCP mais seulement si une option
.B --dhcp-host .B --dhcp-host
spécifiant le nom existe par ailleurs. Seul un nom d'hôte peut-être donné dans spécifiant le nom existe par ailleurs. Seul un nom d'hôte peut être donné dans
une option une option
.B dhcp-host .B dhcp-host
, mais les alias sont possibles au travers de l'utilisation des CNAMEs. (Voir , mais les alias sont possibles au travers de l'utilisation des CNAMEs. (Voir
@@ -973,7 +981,7 @@ Les adresses ethernet (mais pas les identifiants clients) peuvent être définie
avec des octets joker, ainsi par exemple avec des octets joker, ainsi par exemple
.B --dhcp-host=00:20:e0:3b:13:*,ignore .B --dhcp-host=00:20:e0:3b:13:*,ignore
demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est à noter demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est à noter
que "*" doit-être précédé d'un caractère d'échappement ou mis entre guillemets que "*" doit être précédé d'un caractère d'échappement ou mis entre guillemets
lorsque spécifié en option de ligne de commande, mais pas dans le fichier de lorsque spécifié en option de ligne de commande, mais pas dans le fichier de
configuration. configuration.
@@ -1059,14 +1067,14 @@ qu'aux réseaux dont tous les labels coïncident avec ceux de la requête.
Un traitement spécial est effectué sur les chaînes de caractères fournies pour Un traitement spécial est effectué sur les chaînes de caractères fournies pour
l'option 119, conformément à la RFC 3397. Les chaînes de caractères ou les l'option 119, conformément à la RFC 3397. Les chaînes de caractères ou les
adresses IP sous forme de 4 chiffres séparés par des points donnés en arguments adresses IP sous forme de 4 chiffres séparés par des points donnés en arguments
de l'option 120 sont traités conforméments à la RFC 3361. Les adresses IP sous de l'option 120 sont traités conformément à la RFC 3361. Les adresses IP sous
forme de 4 chiffres séparés par des points suivies par une barre montante "/", forme de 4 chiffres séparés par des points suivies par une barre montante "/",
puis une taille de masque sont encodés conforméments à la RFC 3442. puis une taille de masque sont encodés conformément à la RFC 3442.
Les options IPv6 sont fournies en utilisant le mot-clef Les options IPv6 sont fournies en utilisant le mot-clef
.B option6: .B option6:
suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options
IPv6 est disjint de l'espace de nommage des options IPv4. Les adresses IPv6 IPv6 est disjoint de l'espace de nommage des options IPv4. Les adresses IPv6
en option doivent être entourées de crochets, comme par exemple : en option doivent être entourées de crochets, comme par exemple :
.B --dhcp-option=option6:ntp-server,[1234::56] .B --dhcp-option=option6:ntp-server,[1234::56]
@@ -1075,7 +1083,7 @@ adéquat sont envoyées pour un numéro d'option donné, il est tout à fait pos
de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
incorrecte de cette option. Lorsque la valeur est un nombre décimal, Dnsmasq incorrecte de cette option. Lorsque la valeur est un nombre décimal, Dnsmasq
doit déterminer la taille des données. Cela est fait en examinant le numéro de doit déterminer la taille des données. Cela est fait en examinant le numéro de
l'option et/ou la valeur, mais peut-être évité en rajoutant un suffixe d'une l'option et/ou la valeur, mais peut être évité en rajoutant un suffixe d'une
lettre comme suit : lettre comme suit :
b = un octet, s = 2 octets, i = 4 octets. Cela sert essentiellement pour des b = un octet, s = 2 octets, i = 4 octets. Cela sert essentiellement pour des
options encapsulées de classes de vendeurs (voir plus bas), pour lesquelles options encapsulées de classes de vendeurs (voir plus bas), pour lesquelles
@@ -1088,7 +1096,7 @@ d'une chaîne de caractères comme nom de serveur TFTP, il est nécessaire de fa
comme suit : comme suit :
.B --dhcp-option=66,"1.2.3.4" .B --dhcp-option=66,"1.2.3.4"
Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées Les options encapsulées de classes de vendeurs peuvent être aussi spécifiées
(pour IPv4 seulement) en utilisant (pour IPv4 seulement) en utilisant
.B --dhcp-option .B --dhcp-option
: par exemple : par exemple
@@ -1105,7 +1113,7 @@ par le client. Il est possible d'omettre complètement une classe de vendeur :
.B --dhcp-option=vendor:,1,0.0.0.0 .B --dhcp-option=vendor:,1,0.0.0.0
Dans ce cas l'option encapsulée est toujours envoyée. Dans ce cas l'option encapsulée est toujours envoyée.
En IPv4, les options peuvent-être encapsulées au sein d'autres options : En IPv4, les options peuvent être encapsulées au sein d'autres options :
par exemple par exemple
.B --dhcp-option=encap:175, 190, "iscsi-client0" .B --dhcp-option=encap:175, 190, "iscsi-client0"
enverra l'option 175, au sein de laquelle se trouve l'option 190. enverra l'option 175, au sein de laquelle se trouve l'option 190.
@@ -1128,7 +1136,7 @@ une option encapsulée.
Cela fonctionne exactement de la même façon que Cela fonctionne exactement de la même façon que
.B --dhcp-option .B --dhcp-option
sauf que cette option sera toujours envoyée, même si le client ne la demande pas sauf que cette option sera toujours envoyée, même si le client ne la demande pas
dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple lors dans la liste de paramètres requis. Cela est parfois nécessaire, par exemple lors
de la fourniture d'options à PXELinux. de la fourniture d'options à PXELinux.
.TP .TP
.B --dhcp-no-override .B --dhcp-no-override
@@ -1149,10 +1157,10 @@ Toutes les requêtes DHCP arrivant sur cette interface seront relayées au
serveur DHCP distant correspondant à l'adresse de serveur indiquée. Il est serveur DHCP distant correspondant à l'adresse de serveur indiquée. Il est
possible de relayer depuis une unique adresse locale vers différents serveurs possible de relayer depuis une unique adresse locale vers différents serveurs
distant en spécifiant plusieurs fois l'option dhcp-relay avec la même adresse distant en spécifiant plusieurs fois l'option dhcp-relay avec la même adresse
locale et différentes adresses de serveur. L'adresse de serveur doit-être locale et différentes adresses de serveur. L'adresse de serveur doit être
sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut-être sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut être
l'adresse de multicast ff05::1:3 correspondant à tous les serveurs DHCP. Dans l'adresse de multicast ff05::1:3 correspondant à tous les serveurs DHCP. Dans
ce cas, l'interface doit-étre spécifiée et ne peut comporter de caractère ce cas, l'interface doit être spécifiée et ne peut comporter de caractère
joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le
multicast pourra atteindre le serveur DHCP. multicast pourra atteindre le serveur DHCP.
@@ -1181,14 +1189,14 @@ vice-versa.
Associe une chaîne de classe de vendeur à un label. La plupart Associe une chaîne de classe de vendeur à un label. La plupart
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
représente, d'une certaine façon, le type d'hôte. Cette option associe des représente, d'une certaine façon, le type d'hôte. Cette option associe des
classes de vendeur à des labels, de telle sorte que des options DHCP peuvent-être classes de vendeur à des labels, de telle sorte que des options DHCP peuvent être
fournie de manière sélective aux différentes classes d'hôtes. Par exemple, fournies de manière sélective aux différentes classes d'hôtes. Par exemple,
.B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect .B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect
ou ou
.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect .B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
permet de n'allouer des options qu'aux imprimantes HP de la manière suivante : permet de n'allouer des options qu'aux imprimantes HP de la manière suivante :
.B --dhcp-option=tag:printers,3,192.168.4.4 .B --dhcp-option=tag:printers,3,192.168.4.4
La chaîne de caractères de la classe de vendeur founie en argument est cherchée La chaîne de caractères de la classe de vendeur fournie en argument est cherchée
en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie
par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
@@ -1218,7 +1226,7 @@ matérielle coïncide avec les critères définis.
.TP .TP
.B --dhcp-circuitid=set:<label>,<identifiant de circuit>, --dhcp-remoteid=set:<label>,<identifiant distant> .B --dhcp-circuitid=set:<label>,<identifiant de circuit>, --dhcp-remoteid=set:<label>,<identifiant distant>
Associe des options de relais DHCP issus de la RFC3046 à des labels. Associe des options de relais DHCP issus de la RFC3046 à des labels.
Cette information peut-être fournie par des relais DHCP. L'identifiant Cette information peut être fournie par des relais DHCP. L'identifiant
de circuit ou l'identifiant distant est normalement fourni sous la forme d'une de circuit ou l'identifiant distant est normalement fourni sous la forme d'une
chaîne de valeurs hexadécimales séparées par des ":", mais il est également chaîne de valeurs hexadécimales séparées par des ":", mais il est également
possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
@@ -1231,7 +1239,7 @@ est supporté en IPv6 (mais non dhcp-circuitid).
(IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des (IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des
labels. labels.
.TP .TP
.B --dhcp-proxy[=<adresse ip>]...... .B --dhcp-proxy[=<adresse IP>]......
(IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire (IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire
suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois
que le client est configuré, il communique directement avec le serveur. Cela que le client est configuré, il communique directement avec le serveur. Cela
@@ -1252,7 +1260,7 @@ interactions avec les relais dont l'adresse est dans la liste seront affectées.
Si aucune valeur n'est spécifiée, associe le label si le client Si aucune valeur n'est spécifiée, associe le label si le client
envoie une option DHCP avec le numéro ou le nom spécifié. Lorsqu'une valeur est envoie une option DHCP avec le numéro ou le nom spécifié. Lorsqu'une valeur est
fournie, positionne le label seulement dans le cas où l'option est fournie et fournie, positionne le label seulement dans le cas où l'option est fournie et
correspond à la valeur. La valeur peut-être de la forme "01:ff:*:02", auquel correspond à la valeur. La valeur peut être de la forme "01:ff:*:02", auquel
cas le début de l'option doit correspondre (en respectant les jokers). La cas le début de l'option doit correspondre (en respectant les jokers). La
valeur peut aussi être de la même forme que dans valeur peut aussi être de la même forme que dans
.B dhcp-option .B dhcp-option
@@ -1262,14 +1270,14 @@ valeur peut aussi être de la même forme que dans
--dhcp-match=set:efi-ia32,option:client-arch,6 --dhcp-match=set:efi-ia32,option:client-arch,6
spécifie le label "efi-ia32" si le numéro 6 apparaît dnas la liste spécifie le label "efi-ia32" si le numéro 6 apparaît dnas la liste
d'architectures envoyé par le client au sein de l'option 93. (se réferer d'architectures envoyé par le client au sein de l'option 93. (se référer
au RFC 4578 pour plus de détails). Si la valeur est un chaine de caractères, au RFC 4578 pour plus de détails). Si la valeur est un chaine de caractères,
celle-ci est recherchée (correspondance en temps que sous-chaîne). celle-ci est recherchée (correspondance en temps que sous-chaîne).
Pour la forme particulière vi-encap:<numéro d'entreprise>, la comparaison se Pour la forme particulière vi-encap:<numéro d'entreprise>, la comparaison se
fait avec les classes de vendeur "identifiant de vendeur" ("vendor-identifying fait avec les classes de vendeur "identifiant de vendeur" ("vendor-identifying
vendor classes") pour l'entreprise dont le numéro est fourni en option. vendor classes") pour l'entreprise dont le numéro est fourni en option.
Veuillez vous réferer à la RFC 3925 pour plus de détail. Veuillez vous référer à la RFC 3925 pour plus de détails.
.TP .TP
.B --tag-if=set:<label>[,set:<label>[,tag:<label>[,tag:<label>]]] .B --tag-if=set:<label>[,set:<label>[,tag:<label>[,tag:<label>]]]
Effectue une opération booléenne sur les labels. Si tous les labels Effectue une opération booléenne sur les labels. Si tous les labels
@@ -1280,7 +1288,7 @@ Si aucun tag:<label> n'est spécifié, alors tous les labels fournis par
set:<label> sont positionnés. set:<label> sont positionnés.
N'importe quel nombre de set: ou tag: peuvent être fournis, et l'ordre est sans N'importe quel nombre de set: ou tag: peuvent être fournis, et l'ordre est sans
importance. importance.
Les lignes tag-if sont executées dans l'ordre, ce qui fait que si un label dans Les lignes tag-if sont exécutées dans l'ordre, ce qui fait que si un label dans
tag:<label> est un label positionné par une rêgle tag:<label> est un label positionné par une rêgle
.B tag-if, .B tag-if,
la ligne qui positionne le label doit précéder celle qui le teste. la ligne qui positionne le label doit précéder celle qui le teste.
@@ -1320,17 +1328,17 @@ le cas de certains vieux clients BOOTP.
(IPv4 seulement) Spécifie les options BOOTP devant être retournées par le (IPv4 seulement) Spécifie les options BOOTP devant être retournées par le
serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils
ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de
la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq fournit un service TFTP (voir
.B --enable-tftp .B --enable-tftp
), alors seul un nom de fichier est requis ici pour permettre un démarrage par ), alors seul un nom de fichier est requis ici pour permettre un démarrage par
le réseau. le réseau.
Si d'éventuels labels sont fournis, ils doivent coïncider avec Si d'éventuels labels sont fournis, ils doivent coïncider avec
ceux du client pour que cet élement de configuration lui soit envoyé. ceux du client pour que cet élément de configuration lui soit envoyé.
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP, Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts. sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
celles-ci seront utilisées tour à tour (algorithme round-robin). celles-ci seront utilisées tour à tour (algorithme round-robin).
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs. Cela peut être utilisé pour équilibrer la charge tftp sur plusieurs serveurs.
.TP .TP
.B --dhcp-sequential-ip .B --dhcp-sequential-ip
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
@@ -1357,7 +1365,7 @@ Ceci spécifie l'option de démarrage qui apparaitra dans un menu de démarrage
PXE. <CSA> est le type du système client. Seuls des types de services valides PXE. <CSA> est le type du système client. Seuls des types de services valides
apparaitront dans un menu. Les types connus sont x86PC, PC98, IA64_EFI, Alpha, apparaitront dans un menu. Les types connus sont x86PC, PC98, IA64_EFI, Alpha,
Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI et X86-64_EFI; Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI et X86-64_EFI;
D'autres types peuvent-être spécifiés sous la forme d'une valeur entière. Le D'autres types peuvent être spécifiés sous la forme d'une valeur entière. Le
paramètre après le texte correspondant à l'entrée dans le menu peut être un nom paramètre après le texte correspondant à l'entrée dans le menu peut être un nom
de fichier, auquel cas Dnsmasq agit comme un serveur de démarrage et indique au de fichier, auquel cas Dnsmasq agit comme un serveur de démarrage et indique au
client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
@@ -1376,7 +1384,7 @@ démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
service), alors l'entrée de menu provoque l'interruption du démarrage par service), alors l'entrée de menu provoque l'interruption du démarrage par
le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur
peut être donnée sous la forme de nom de domaine qui est recherché dans peut être donnée sous la forme de nom de domaine qui est recherché dans
/etc/hosts. Ce nom peut-être associé à plusieurs adresses IP, qui dans ce cas /etc/hosts. Ce nom peut être associé à plusieurs adresses IP, qui dans ce cas
sont utilisées à tour de rôle (en "round-robin"). sont utilisées à tour de rôle (en "round-robin").
.TP .TP
.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>] .B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
@@ -1435,7 +1443,7 @@ Utiliser cette option avec précaution, une adresse allouée à un client BOOTP
étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si
aucun argument n'est donné, alors cette option permet une allocation dynamique aucun argument n'est donné, alors cette option permet une allocation dynamique
dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se
fait que lorsque tous les identifiants coïncident. Il est possible de répeter fait que lorsque tous les identifiants coïncident. Il est possible de répéter
cette option avec plusieurs jeux d'arguments. cette option avec plusieurs jeux d'arguments.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
@@ -1560,7 +1568,7 @@ Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
sont ouverts sur /dev/null (sauf en mode déverminage). sont ouverts sur /dev/null (sauf en mode déverminage).
Le script n'est pas lancé de manière concurrente : au plus une instance du Le script n'est pas lancé de manière concurrente : au plus une instance du
script est executée à la fois (dnsmasq attends qu'une instance de script se script est exécutée à la fois (dnsmasq attend qu'une instance de script se
termine avant de lancer la suivante). Les changements dans la base des baux termine avant de lancer la suivante). Les changements dans la base des baux
nécessitant le lancement du script sont placé en attente dans une queue jusqu'à nécessitant le lancement du script sont placé en attente dans une queue jusqu'à
terminaison d'une instance du script en cours. Si cette mise en queue fait que terminaison d'une instance du script en cours. Si cette mise en queue fait que
@@ -1575,7 +1583,7 @@ le script sera invoqué avec une action "old" pour tous les baux existants.
Il existe deux autres actions pouvant apparaître comme argument au script : Il existe deux autres actions pouvant apparaître comme argument au script :
"init" et "tftp". D'autres sont susceptibles d'être rajoutées dans le futur, "init" et "tftp". D'autres sont susceptibles d'être rajoutées dans le futur,
aussi les scripts devraient-être écrits de sorte à ignorer les actions aussi les scripts devraient être écrits de sorte à ignorer les actions
inconnues. "init" est décrite ci-dessous dans inconnues. "init" est décrite ci-dessous dans
.B --leasefile-ro. .B --leasefile-ro.
L'action "tftp" est invoquée lorsqu'un transfert de fichier TFTP s'est L'action "tftp" est invoquée lorsqu'un transfert de fichier TFTP s'est
@@ -1588,7 +1596,7 @@ Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être
compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une
seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales
persistent entre les évênements liés aux baux. Le code Lua doit définir une persistent entre les événements liés aux baux. Le code Lua doit définir une
fonction fonction
.B lease .B lease
et peut fournir des fonctions et peut fournir des fonctions
@@ -1637,7 +1645,7 @@ et
.B --dhcp-scriptuser .B --dhcp-scriptuser
Spécifie l'utilisateur sous lequel le script shell lease-change ou le script Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
doivent être exécutés. La valeur par défaut correspond à l'utilisateur root doivent être exécutés. La valeur par défaut correspond à l'utilisateur root
mais peut-être changée par le biais de cette option. mais peut être changée par le biais de cette option.
.TP .TP
.B \-9, --leasefile-ro .B \-9, --leasefile-ro
Supprimer complètement l'usage du fichier servant de base de donnée pour les Supprimer complètement l'usage du fichier servant de base de donnée pour les
@@ -1649,8 +1657,8 @@ biais de l'option
être complètement gérée par le script sur un stockage externe. En addition aux être complètement gérée par le script sur un stockage externe. En addition aux
actions décrites dans actions décrites dans
.B --dhcp-script, .B --dhcp-script,
le script de changement d'état de bail est appellé une fois, au lancement de le script de changement d'état de bail est appelé une fois, au lancement de
Dnsmasq, avec pour seul argument "init". Lorsqu'appellé de la sorte, le script Dnsmasq, avec pour seul argument "init". Lorsqu'appelé de la sorte, le script
doit fournir l'état de la base de baux, dans le format de fichier de baux de doit fournir l'état de la base de baux, dans le format de fichier de baux de
Dnsmasq, sur sa sortie standard (stdout) et retourner un code de retour de 0. Dnsmasq, sur sa sortie standard (stdout) et retourner un code de retour de 0.
Positionner cette option provoque également une invocation du script de Positionner cette option provoque également une invocation du script de
@@ -1692,20 +1700,20 @@ positionné à la première valeur de la directive "search" du fichier
/etc/resolv.conf (ou équivalent). /etc/resolv.conf (ou équivalent).
La gamme d'adresses peut être de la forme La gamme d'adresses peut être de la forme
<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple <adresse IP>,<adresse IP> ou <adresse IP>/<masque de réseau> voire une simple
<adresse ip>. Voir <adresse IP>. Voir
.B --dhcp-fqdn .B --dhcp-fqdn
qui peut changer le comportement de dnsmasq relatif aux domaines. qui peut changer le comportement de dnsmasq relatif aux domaines.
Si la gamme d'adresse est fournie sous la forme Si la gamme d'adresse est fournie sous la forme
<adresse ip>/<taille de réseau>, alors le drapeau "local" peut-être rajouté <adresse IP>/<taille de réseau>, alors le drapeau "local" peut être rajouté
qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et qui a pour effet d'ajouter --local-declarations aux requêtes DNS directes et
inverses. C-à-d inverses. C-à-d
.B --domain=thekelleys.org.uk,192.168.0.0/24,local .B --domain=thekelleys.org.uk,192.168.0.0/24,local
est identique à est identique à
.B --domain=thekelleys.org.uk,192.168.0.0/24 .B --domain=thekelleys.org.uk,192.168.0.0/24
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/ --local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
La taille de réseau doit-être de 8, 16 ou 24 pour être valide. La taille de réseau doit être de 8, 16 ou 24 pour être valide.
.TP .TP
.B --dhcp-fqdn .B --dhcp-fqdn
Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
@@ -1717,8 +1725,8 @@ ce nom est transféré au nouveau client. Si
est spécifié, ce comportement change : les noms non qualifiés ne sont plus est spécifié, ce comportement change : les noms non qualifiés ne sont plus
rajoutés dans le DNS, seuls les noms qualifiés le sont. Deux clients DHCP rajoutés dans le DNS, seuls les noms qualifiés le sont. Deux clients DHCP
avec le même nom peuvent tous les deux garder le nom, pour peu que la partie avec le même nom peuvent tous les deux garder le nom, pour peu que la partie
relative au domaine soit différente (c-à-d que les noms pleinements qualifiés relative au domaine soit différente (c-à-d que les noms pleinement qualifiés
diffèrent). Pour d'assurer que tous les noms ont une partie domaine, il doit-y diffèrent). Pour s'assurer que tous les noms ont une partie domaine, il doit y
avoir au moins un avoir au moins un
.B --domain .B --domain
sans gamme d'adresses de spécifié lorsque l'option sans gamme d'adresses de spécifié lorsque l'option
@@ -1735,7 +1743,7 @@ Windows de la mise à jour de serveurs Active Directory. Voir la RFC 4702 pour
plus de détails. plus de détails.
.TP .TP
.B --enable-ra .B --enable-ra
Active la fonctionalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement"). Active la fonctionnalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
DHCPv6 ne gère pas la configuration complète du réseau de la même façon que DHCPv6 ne gère pas la configuration complète du réseau de la même façon que
DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour
la création autonome d'adresse sont gérées par un protocole différent. la création autonome d'adresse sont gérées par un protocole différent.
@@ -1747,7 +1755,7 @@ dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
la valeur d'adresse link-local appropriée parmi celles de la machine sur la valeur d'adresse link-local appropriée parmi celles de la machine sur
laquelle tourne dnsmasq. laquelle tourne dnsmasq.
Par défaut, les bits "managed address" sont positionnés, et le bit "use SLAAC" Par défaut, les bits "managed address" sont positionnés, et le bit "use SLAAC"
("utiliser SLAAC") est réinitialisé. Cela peut-être changé pour des ("utiliser SLAAC") est réinitialisé. Cela peut être changé pour des
sous-réseaux donnés par le biais du mot clef de mode décris dans sous-réseaux donnés par le biais du mot clef de mode décris dans
.B --dhcp-range. .B --dhcp-range.
Les paramètres DNS du RFC6106 sont inclus dans les annonces. Par défaut, Les paramètres DNS du RFC6106 sont inclus dans les annonces. Par défaut,
@@ -1759,16 +1767,16 @@ DNSSL.
.B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][high,|low,]<intervalle d'annonce routeur>[,<durée de vie route>] .B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][high,|low,]<intervalle d'annonce routeur>[,<durée de vie route>]
Configure pour une interface donnée des valeurs pour les annonces routeurs Configure pour une interface donnée des valeurs pour les annonces routeurs
différentes des valeurs par défaut. La valeur par défaut du champ priorité différentes des valeurs par défaut. La valeur par défaut du champ priorité
pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou pour le routeur peut être changée de "medium" (moyen) à "high" (haute) ou
"low" (basse). Par exemple : "low" (basse). Par exemple :
.B --ra-param=eth0,high,0. .B --ra-param=eth0,high,0.
Un intervalle (en secondes) entre les annonces routeur peut-être fourni par : Un intervalle (en secondes) entre les annonces routeur peut être fourni par :
.B --ra-param=eth0,60. .B --ra-param=eth0,60.
La durée de vie de la route peut-être changée ou mise à zéro, auquel cas La durée de vie de la route peut être changée ou mise à zéro, auquel cas
le routeur peut annoncer les préfixes mais pas de route : le routeur peut annoncer les préfixes mais pas de route :
.B --ra-parm=eth0,0,0 .B --ra-parm=eth0,0,0
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut). (une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
Ces quatre paramètres peuvent-être configurés en une fois : Ces quatre paramètres peuvent être configurés en une fois :
.B --ra-param=eth0,mtu:1280,low,60,1200 .B --ra-param=eth0,mtu:1280,low,60,1200
La valeur pour l'interface peut inclure un caractère joker. La valeur pour l'interface peut inclure un caractère joker.
.TP .TP
@@ -1776,7 +1784,7 @@ La valeur pour l'interface peut inclure un caractère joker.
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
un accès en lecture est possible; les extensions tsize et blksize sont supportées un accès en lecture est possible; les extensions tsize et blksize sont supportées
(tsize est seulement supporté en mode octet). Sans argument optionel, le service (tsize est seulement supportée en mode octet). Sans argument optionnel, le service
TFTP est fourni sur les mêmes interfaces que le service DHCP. Si une liste TFTP est fourni sur les mêmes interfaces que le service DHCP. Si une liste
d'interfaces est fournie, cela définit les interfaces sur lesquelles le d'interfaces est fournie, cela définit les interfaces sur lesquelles le
service TFTP sera activé. service TFTP sera activé.
@@ -1847,9 +1855,9 @@ Un serveur TFTP écoute sur le port prédéfini 69 ("well-known port") pour
l'initiation de la connexion, mais utilise également un port dynamiquement l'initiation de la connexion, mais utilise également un port dynamiquement
alloué pour chaque connexion. Normalement, ces ports sont alloués par alloué pour chaque connexion. Normalement, ces ports sont alloués par
le système d'exploitation, mais cette option permet de spécifier une gamme le système d'exploitation, mais cette option permet de spécifier une gamme
de ports à utiliser pour les transferts TFTP. Cela peut-être utile si de ports à utiliser pour les transferts TFTP. Cela peut être utile si
TFTP doit traverser un dispositif garde-barrière ("firewall"). La valeur TFTP doit traverser un dispositif garde-barrière ("firewall"). La valeur
de début pour la plage de port ne peut-être inférieure à 1025 sauf si de début pour la plage de port ne peut être inférieure à 1025 sauf si
dnsmasq tourne en temps que super-utilisateur ("root"). Le nombre de dnsmasq tourne en temps que super-utilisateur ("root"). Le nombre de
connexions TFTP concurrentes est limitée par la taille de la gamme de connexions TFTP concurrentes est limitée par la taille de la gamme de
ports ainsi spécifiée. ports ainsi spécifiée.
@@ -1859,8 +1867,8 @@ Un serveur TFTP écoute sur un numéro de port bien connu (69) pour l'initiation
de la connexion, et alloue dynamiquement un port pour chaque connexion. Ces de la connexion, et alloue dynamiquement un port pour chaque connexion. Ces
numéros de ports sont en principe alloués par le système d'exploitation, mais numéros de ports sont en principe alloués par le système d'exploitation, mais
cette option permet de spécifier une gamme de ports à utiliser pour les cette option permet de spécifier une gamme de ports à utiliser pour les
transferts TFTP. Cela peut-être utile lorsque ceux-ci doivent traverser un transferts TFTP. Cela peut être utile lorsque ceux-ci doivent traverser un
dispositif garde-barrière ("firewall"). Le début de la plage ne peut-être dispositif garde-barrière ("firewall"). Le début de la plage ne peut être
inférieur à 1024 à moins que Dnsmasq ne fonctionne en temps que inférieur à 1024 à moins que Dnsmasq ne fonctionne en temps que
super-utilisateur ("root"). Le nombre maximal de connexions TFTP concurrentes super-utilisateur ("root"). Le nombre maximal de connexions TFTP concurrentes
est limitée par la taille de la plage de ports ainsi définie. est limitée par la taille de la plage de ports ainsi définie.
@@ -1895,7 +1903,7 @@ par "--". Les lignes commençant par # sont des commentaires et sont ignorées.
Pour les options qui ne peuvent-être spécifiées qu'une seule fois, celle du Pour les options qui ne peuvent-être spécifiées qu'une seule fois, celle du
fichier de configuration prends le pas sur celle fournie en ligne de commande. fichier de configuration prends le pas sur celle fournie en ligne de commande.
Il est possible d'utiliser des guillemets afin d'éviter que les ",",":","." et Il est possible d'utiliser des guillemets afin d'éviter que les ",",":","." et
"#" ne soit interprêtés, et il est possible d'utiliser les séquences "#" ne soient interprétés, et il est possible d'utiliser les séquences
d'échappement suivantes : \\\\ \\" \\t \\e \\b \\r et \\n. Elles correspondent d'échappement suivantes : \\\\ \\" \\t \\e \\b \\r et \\n. Elles correspondent
respectivement à la barre oblique descendante ("anti-slash"), guillemets doubles, respectivement à la barre oblique descendante ("anti-slash"), guillemets doubles,
tabulation, caractère d'échappement ("escape"), suppression ("backspace"), retour ("return") et tabulation, caractère d'échappement ("escape"), suppression ("backspace"), retour ("return") et
@@ -1940,8 +1948,8 @@ traces dans un fichier (voir
.B --log-facility .B --log-facility
), alors ), alors
.B Dnsmasq .B Dnsmasq
ferme et re-rouvre le fichier de traces. Il faut noter que pendant cette ferme et rouvre le fichier de traces. Il faut noter que pendant cette
opération Dnsmasq ne s'exécute pas en temps que "root". Lorsqu'il créé un opération Dnsmasq ne s'exécute pas en tant que "root". Lorsqu'il créé un
fichier de traces pour la première fois, Dnsmasq change le propriétaire du fichier de traces pour la première fois, Dnsmasq change le propriétaire du
fichier afin de le faire appartenir à l'utilisateur non "root" sous lequel fichier afin de le faire appartenir à l'utilisateur non "root" sous lequel
Dnsmasq s'exécute. Le logiciel de rotation de fichiers de trace logrotate doit Dnsmasq s'exécute. Le logiciel de rotation de fichiers de trace logrotate doit
@@ -1983,7 +1991,7 @@ qu'une connexion PPP ne soit établie. Dans ce cas, Dnsmasq vérifie régulière
pour voir si un fichier pour voir si un fichier
.I /etc/resolv.conf .I /etc/resolv.conf
est créé. Dnsmasq peut être configuré pour lire plus d'un fichier resolv.conf. est créé. Dnsmasq peut être configuré pour lire plus d'un fichier resolv.conf.
Cela est utile sur un ordinateur portable où PPP et DHCP peuvent-être utilisés : Cela est utile sur un ordinateur portable où PPP et DHCP peuvent être utilisés :
Dnsmasq peut alors être configuré pour lire à la fois Dnsmasq peut alors être configuré pour lire à la fois
.I /etc/ppp/resolv.conf .I /etc/ppp/resolv.conf
et et
@@ -2007,7 +2015,7 @@ ou alors en mettant leurs adresses dans un autre fichier, par exemple
.I /etc/resolv.dnsmasq .I /etc/resolv.dnsmasq
et en lançant Dnsmasq avec l'option et en lançant Dnsmasq avec l'option
.B \-r /etc/resolv.dnsmasq. .B \-r /etc/resolv.dnsmasq.
Cette deuxième technique permet la mise-à-jour dynamique des addresses de Cette deuxième technique permet la mise-à-jour dynamique des adresses de
serveurs DNS amont par le biais de PPP ou DHCP. serveurs DNS amont par le biais de PPP ou DHCP.
.PP .PP
Les adresses dans /etc/hosts prennent le dessus sur celles fournies par le Les adresses dans /etc/hosts prennent le dessus sur celles fournies par le
@@ -2067,10 +2075,10 @@ et pour affecter l'option envoyée, sur la base de la plage sélectionnée.
Ce système a évolué d'un système plus ancien et aux possibilités plus limitées, Ce système a évolué d'un système plus ancien et aux possibilités plus limitées,
et pour des raisons de compatibilité "net:" peut être utilisé à la place de et pour des raisons de compatibilité "net:" peut être utilisé à la place de
"tag:" et "set:" peut-être omis (à l'exception de "tag:" et "set:" peut être omis (à l'exception de
.B dhcp-host, .B dhcp-host,
où "net:" peut-être utilisé à la place de "set:"). Pour les mêmes raisons, '#' où "net:" peut être utilisé à la place de "set:"). Pour les mêmes raisons, '#'
peut-être utilisé à la place de '!' pour indiquer la négation. peut être utilisé à la place de '!' pour indiquer la négation.
.PP .PP
Le serveur DHCP intégré dans Dnsmasq fonctionne également en temps que serveur Le serveur DHCP intégré dans Dnsmasq fonctionne également en temps que serveur
BOOTP, pour peu que l'adresse MAC et l'adresse IP des clients soient fournies, BOOTP, pour peu que l'adresse MAC et l'adresse IP des clients soient fournies,
@@ -2097,7 +2105,7 @@ scénarios de complexité croissante. Le pré-requis pour chacun de ces scénari
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
capable d'effectuer la délégation de la zone en question. Pour la première capable d'effectuer la délégation de la zone en question. Pour la première
partie de ces explications, nous allons appeller serveur.exemple.com partie de ces explications, nous allons appeler serveur.exemple.com
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
notre.zone.com la zone pour laquelle dnsmasq fait autorité. notre.zone.com la zone pour laquelle dnsmasq fait autorité.
@@ -2138,11 +2146,11 @@ notre.zone.com NS our.zone.com
.fi .fi
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle" L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP qui résout le problème de poule et d'oeuf consistant à trouver l'adresse IP
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
fait désormais autorité pour notre.zone.com, il doit également fournir cet fait désormais autorité pour notre.zone.com, il doit également fournir cet
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par enregistrement. Si l'adresse externe est statique, cela peut être réalisé par
le biais d'une entrée dans le biais d'une entrée dans
.B /etc/hosts .B /etc/hosts
ou via un ou via un
@@ -2194,7 +2202,7 @@ spécifiques, vous pouvez le faire via :
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
le nom) peuvent-simplement être configurées avec un enregistrement NS le nom) peuvent simplement être configurées avec un enregistrement NS
adéquat. Par exemple, comme nous définissons plus haut les adresses adéquat. Par exemple, comme nous définissons plus haut les adresses
1.2.3.0/24 : 1.2.3.0/24 :
.nf .nf
@@ -2243,7 +2251,7 @@ celui fourni par
.B --domain. .B --domain.
Si l'option Si l'option
.B --dhcp-fqdn .B --dhcp-fqdn
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP est fournie, alors les noms pleinement qualifiés associés aux baux DHCP
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
à la zone. à la zone.
@@ -2282,7 +2290,7 @@ Dnsmasq est capable de gérer le DNS et DHCP pour au moins un millier de clients
Pour cela, la durée des bail ne doit pas être très courte (moins d'une heure). Pour cela, la durée des bail ne doit pas être très courte (moins d'une heure).
La valeur de La valeur de
.B --dns-forward-max .B --dns-forward-max
peut-être augmentée : commencer par la rendre égale au nombre de clients et peut être augmentée : commencer par la rendre égale au nombre de clients et
l'augmenter si le DNS semble lent. Noter que la performance du DNS dépends l'augmenter si le DNS semble lent. Noter que la performance du DNS dépends
également de la performance des serveurs amonts. La taille du cache DNS peut- également de la performance des serveurs amonts. La taille du cache DNS peut-
être augmentée : la limite en dur est de 10000 entrées et la valeur par défaut être augmentée : la limite en dur est de 10000 entrées et la valeur par défaut
@@ -2306,7 +2314,7 @@ Il est possible d'utiliser Dnsmasq pour bloquer la publicité sur la toile
en associant des serveurs de publicité bien connus à l'adresse 127.0.0.1 ou en associant des serveurs de publicité bien connus à l'adresse 127.0.0.1 ou
0.0.0.0 par le biais du fichier 0.0.0.0 par le biais du fichier
.B /etc/hosts .B /etc/hosts
ou d'un fichier d'hôte additionnel. Cette liste peut-être très longue, Dnsmasq ou d'un fichier d'hôte additionnel. Cette liste peut être très longue, Dnsmasq
ayant été testé avec succès avec un million de noms. Cette taille de fichier ayant été testé avec succès avec un million de noms. Cette taille de fichier
nécessite un processeur à 1 Ghz et environ 60 Mo de RAM. nécessite un processeur à 1 Ghz et environ 60 Mo de RAM.
+538 -480
View File
File diff suppressed because it is too large. Load diff
+544 -498
View File
File diff suppressed because it is too large. Load diff
+547 -503
View File
File diff suppressed because it is too large. Load diff
+530 -484
View File
File diff suppressed because it is too large. Load diff
+564 -515
View File
File diff suppressed because it is too large. Load diff
+547 -503
View File
File diff suppressed because it is too large. Load diff
+558 -514
View File
File diff suppressed because it is too large. Load diff
+538 -480
View File
File diff suppressed because it is too large. Load diff
+547 -503
View File
File diff suppressed because it is too large. Load diff
+558 -514
View File
File diff suppressed because it is too large. Load diff
+1 -1
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 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 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 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 security feature to stop a machine on your network telling DHCP that
its name is "www.microsoft.com" and thereby grabbing traffic which 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 shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+23 -25
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 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 it under the terms of the GNU General Public License as published by
@@ -103,7 +103,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{ {
char *name = daemon->namebuff; char *name = daemon->namebuff;
unsigned char *p, *ansp; unsigned char *p, *ansp;
int qtype, qclass; int qtype, qclass, rc;
int nameoffset, axfroffset = 0; int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0; int q, anscount = 0, authcount = 0;
struct crec *crecp; struct crec *crecp;
@@ -119,11 +119,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
struct cname *a, *candidate; struct cname *a, *candidate;
unsigned int wclen; 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 ) if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0; return 0;
@@ -288,11 +283,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
for (rec = daemon->mxnames; rec; rec = rec->next) for (rec = daemon->mxnames; rec; rec = rec->next)
if (!rec->issrv && hostname_isequal(name, rec->name)) if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
{ {
nxdomain = 0; nxdomain = 0;
if (qtype == T_MX) if (rc == 2 && qtype == T_MX)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
@@ -303,11 +298,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next) for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
if (rec->issrv && hostname_isequal(name, rec->name)) if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
{ {
nxdomain = 0; nxdomain = 0;
if (qtype == T_SRV) if (rc == 2 && qtype == T_SRV)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
@@ -338,13 +333,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
for (txt = daemon->rr; txt; txt = txt->next) for (txt = daemon->rr; txt; txt = txt->next)
if (hostname_isequal(name, txt->name)) if ((rc = hostname_issubdomain(name, txt->name)))
{ {
nxdomain = 0; nxdomain = 0;
if (txt->class == qtype) if (rc == 2 && txt->class == qtype)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt)) NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++; anscount++;
@@ -352,10 +347,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
for (txt = daemon->txt; txt; txt = txt->next) for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && hostname_isequal(name, txt->name)) if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
{ {
nxdomain = 0; nxdomain = 0;
if (qtype == T_TXT) if (rc == 2 && qtype == T_TXT)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
@@ -366,10 +361,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} }
for (na = daemon->naptr; na; na = na->next) for (na = daemon->naptr; na; na = na->next)
if (hostname_isequal(name, na->name)) if ((rc = hostname_issubdomain(name, na->name)))
{ {
nxdomain = 0; nxdomain = 0;
if (qtype == T_NAPTR) if (rc == 2 && qtype == T_NAPTR)
{ {
found = 1; found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>"); log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
@@ -389,13 +384,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
#endif #endif
for (intr = daemon->int_names; intr; intr = intr->next) for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name)) if ((rc = hostname_issubdomain(name, intr->name)))
{ {
struct addrlist *addrlist; struct addrlist *addrlist;
nxdomain = 0; nxdomain = 0;
if (flag) if (rc == 2 && flag)
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next) for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype && if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
(local_query || filter_zone(zone, flag, &addrlist->addr))) (local_query || filter_zone(zone, flag, &addrlist->addr)))
@@ -441,8 +436,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (sockaddr_isequal(peer_addr, &peers->addr)) if (sockaddr_isequal(peer_addr, &peers->addr))
break; break;
/* Refuse all AXFR unless --auth-sec-servers is set */ /* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server) if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
(daemon->auth_peers && !peers))
{ {
if (peer_addr->sa.sa_family == AF_INET) if (peer_addr->sa.sa_family == AF_INET)
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
@@ -571,6 +567,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
goto cname_restart; goto cname_restart;
} }
else if (cache_find_non_terminal(name, now))
nxdomain = 0;
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL); log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
} }
@@ -597,12 +595,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
char *p = name; char *p = name;
if (subnet->prefixlen >= 24) if (subnet->prefixlen >= 24)
p += sprintf(p, "%d.", a & 0xff); p += sprintf(p, "%u.", a & 0xff);
a = a >> 8; a = a >> 8;
if (subnet->prefixlen >= 16 ) if (subnet->prefixlen >= 16 )
p += sprintf(p, "%d.", a & 0xff); p += sprintf(p, "%u.", a & 0xff);
a = a >> 8; a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff); p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
+4 -3
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 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 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)); struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
if (n > 0 && new) if (new)
{ {
int i; 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 */ /* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata)); blockdata_expand(daemon->cachesize);
} }
void blockdata_report(void) void blockdata_report(void)
@@ -100,6 +100,7 @@ struct blockdata *blockdata_alloc(char *data, size_t len)
return ret; return ret;
} }
void blockdata_free(struct blockdata *blocks) void blockdata_free(struct blockdata *blocks)
{ {
struct blockdata *tmp; struct blockdata *tmp;
+2 -2
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 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 it under the terms of the GNU General Public License as published by
@@ -169,7 +169,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct in6_ifreq ifr6; struct in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6)); memset(&ifr6, 0, sizeof(ifr6));
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name)); safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr); ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1) if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
+312 -134
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 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 it under the terms of the GNU General Public License as published by
@@ -21,10 +21,12 @@ static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
static struct crec *dhcp_spare = NULL; static struct crec *dhcp_spare = NULL;
#endif #endif
static struct crec *new_chain = NULL; static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error; static int insert_error;
static union bigname *big_free = NULL; static union bigname *big_free = NULL;
static int bignames_left, hash_size; static int bignames_left, hash_size;
static void make_non_terminals(struct crec *source);
/* type->string mapping: this is also used by the name-hash function as a mixing table. */ /* type->string mapping: this is also used by the name-hash function as a mixing table. */
static const struct { static const struct {
unsigned int type; unsigned int type;
@@ -45,6 +47,7 @@ static const struct {
{ 24, "SIG" }, { 24, "SIG" },
{ 25, "KEY" }, { 25, "KEY" },
{ 28, "AAAA" }, { 28, "AAAA" },
{ 29, "LOC" },
{ 33, "SRV" }, { 33, "SRV" },
{ 35, "NAPTR" }, { 35, "NAPTR" },
{ 36, "KX" }, { 36, "KX" },
@@ -57,13 +60,18 @@ static const struct {
{ 47, "NSEC" }, { 47, "NSEC" },
{ 48, "DNSKEY" }, { 48, "DNSKEY" },
{ 50, "NSEC3" }, { 50, "NSEC3" },
{ 51, "NSEC3PARAM" },
{ 52, "TLSA" },
{ 53, "SMIMEA" },
{ 55, "HIP" },
{ 249, "TKEY" }, { 249, "TKEY" },
{ 250, "TSIG" }, { 250, "TSIG" },
{ 251, "IXFR" }, { 251, "IXFR" },
{ 252, "AXFR" }, { 252, "AXFR" },
{ 253, "MAILB" }, { 253, "MAILB" },
{ 254, "MAILA" }, { 254, "MAILA" },
{ 255, "ANY" } { 255, "ANY" },
{ 257, "CAA" }
}; };
static void cache_free(struct crec *crecp); static void cache_free(struct crec *crecp);
@@ -72,17 +80,20 @@ static void cache_link(struct crec *crecp);
static void rehash(int size); static void rehash(int size);
static void cache_hash(struct crec *crecp); static void cache_hash(struct crec *crecp);
static unsigned int next_uid(void) void next_uid(struct crec *crecp)
{ {
static unsigned int uid = 0; static unsigned int uid = 0;
uid++; if (crecp->uid == UID_NONE)
{
uid++;
/* uid == 0 used to indicate CNAME to interface name. */ /* uid == 0 used to indicate CNAME to interface name. */
if (uid == SRC_INTERFACE) if (uid == UID_NONE)
uid++; uid++;
return uid; crecp->uid = uid;
}
} }
void cache_init(void) void cache_init(void)
@@ -100,7 +111,7 @@ void cache_init(void)
{ {
cache_link(crecp); cache_link(crecp);
crecp->flags = 0; crecp->flags = 0;
crecp->uid = next_uid(); crecp->uid = UID_NONE;
} }
} }
@@ -199,7 +210,7 @@ static void cache_free(struct crec *crecp)
{ {
crecp->flags &= ~F_FORWARD; crecp->flags &= ~F_FORWARD;
crecp->flags &= ~F_REVERSE; crecp->flags &= ~F_REVERSE;
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */ crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
if (cache_tail) if (cache_tail)
cache_tail->next = crecp; cache_tail->next = crecp;
@@ -317,7 +328,8 @@ static int is_expired(time_t now, struct crec *crecp)
return 1; return 1;
} }
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags) static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags,
struct crec **target_crec, unsigned int *target_uid)
{ {
/* Scan and remove old entries. /* Scan and remove old entries.
If (flags & F_FORWARD) then remove any forward entries for name and any expired If (flags & F_FORWARD) then remove any forward entries for name and any expired
@@ -330,7 +342,10 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted) to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal> We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
so that when we hit an entry which isn't reverse and is immortal, we're done. */ so that when we hit an entry which isn't reverse and is immortal, we're done.
If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
This entry will get re-used with the same name, to preserve CNAMEs. */
struct crec *crecp, **up; struct crec *crecp, **up;
@@ -338,17 +353,6 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
{ {
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next) for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
{ {
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
{
*up = crecp->hash_next;
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
{
cache_unlink(crecp);
cache_free(crecp);
}
continue;
}
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name)) if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
{ {
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */ /* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
@@ -358,6 +362,16 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
return crecp; return crecp;
*up = crecp->hash_next; *up = crecp->hash_next;
/* If this record is for the name we're inserting and is the target
of a CNAME record. Make the new record for the same name, in the same
crec, with the same uid to avoid breaking the existing CNAME. */
if (crecp->uid != UID_NONE)
{
if (target_crec)
*target_crec = crecp;
if (target_uid)
*target_uid = crecp->uid;
}
cache_unlink(crecp); cache_unlink(crecp);
cache_free(crecp); cache_free(crecp);
continue; continue;
@@ -376,6 +390,18 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
} }
#endif #endif
} }
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
{
*up = crecp->hash_next;
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
{
cache_unlink(crecp);
cache_free(crecp);
}
continue;
}
up = &crecp->hash_next; up = &crecp->hash_next;
} }
} }
@@ -442,11 +468,12 @@ void cache_start_insert(void)
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags) time_t now, unsigned long ttl, unsigned short flags)
{ {
struct crec *new; struct crec *new, *target_crec = NULL;
union bigname *big_name = NULL; union bigname *big_name = NULL;
int freed_all = flags & F_REVERSE; int freed_all = flags & F_REVERSE;
int free_avail = 0; int free_avail = 0;
unsigned int target_uid;
/* Don't log DNSSEC records here, done elsewhere */ /* Don't log DNSSEC records here, done elsewhere */
if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
{ {
@@ -464,7 +491,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
/* First remove any expired entries and entries for the name/address we /* First remove any expired entries and entries for the name/address we
are currently inserting. */ are currently inserting. */
if ((new = cache_scan_free(name, addr, now, flags))) if ((new = cache_scan_free(name, addr, now, flags, &target_crec, &target_uid)))
{ {
/* We're trying to insert a record over one from /* We're trying to insert a record over one from
/etc/hosts or DHCP, or other config. If the /etc/hosts or DHCP, or other config. If the
@@ -488,81 +515,89 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
} }
/* Now get a cache entry from the end of the LRU list */ /* Now get a cache entry from the end of the LRU list */
while (1) { if (!target_crec)
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */ while (1) {
{ if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
insert_error = 1; {
return NULL; insert_error = 1;
} return NULL;
}
/* End of LRU list is still in use: if we didn't scan all the hash
chains for expired entries do that now. If we already tried that /* Free entry at end of LRU list, use it. */
then it's time to start spilling things. */ if (!(new->flags & (F_FORWARD | F_REVERSE)))
break;
if (new->flags & (F_FORWARD | F_REVERSE))
{
/* If free_avail set, we believe that an entry has been freed.
Bugs have been known to make this not true, resulting in
a tight loop here. If that happens, abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_ERR, _("Internal error in cache."));
warned = 1;
}
insert_error = 1;
return NULL;
}
if (freed_all)
{
struct all_addr free_addr = new->addr.addr;;
/* End of LRU list is still in use: if we didn't scan all the hash
chains for expired entries do that now. If we already tried that
then it's time to start spilling things. */
/* If free_avail set, we believe that an entry has been freed.
Bugs have been known to make this not true, resulting in
a tight loop here. If that happens, abandon the
insert. Once in this state, all inserts will probably fail. */
if (free_avail)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_ERR, _("Internal error in cache."));
warned = 1;
}
insert_error = 1;
return NULL;
}
if (freed_all)
{
struct all_addr free_addr = new->addr.addr;;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* For DNSSEC records, addr holds class. */ /* For DNSSEC records, addr holds class. */
if (new->flags & (F_DS | F_DNSKEY)) if (new->flags & (F_DS | F_DNSKEY))
free_addr.addr.dnssec.class = new->uid; free_addr.addr.dnssec.class = new->uid;
#endif #endif
free_avail = 1; /* Must be free space now. */ free_avail = 1; /* Must be free space now. */
cache_scan_free(cache_get_name(new), &free_addr, now, new->flags); cache_scan_free(cache_get_name(new), &free_addr, now, new->flags, NULL, NULL);
cache_live_freed++; daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
} }
else else
{ {
cache_scan_free(NULL, NULL, now, 0); cache_scan_free(NULL, NULL, now, 0, NULL, NULL);
freed_all = 1; freed_all = 1;
} }
continue; }
}
/* Check if we need to and can allocate extra memory for a long name.
/* Check if we need to and can allocate extra memory for a long name. If that fails, give up now, always succeed for DNSSEC records. */
If that fails, give up now, always succeed for DNSSEC records. */ if (name && (strlen(name) > SMALLDNAME-1))
if (name && (strlen(name) > SMALLDNAME-1)) {
{ if (big_free)
if (big_free) {
{ big_name = big_free;
big_name = big_free; big_free = big_free->next;
big_free = big_free->next; }
} else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) || !(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname)))) {
{ insert_error = 1;
insert_error = 1; return NULL;
return NULL; }
} else if (bignames_left != 0)
else if (bignames_left != 0) bignames_left--;
bignames_left--;
}
}
/* Got the rest: finally grab entry. */ /* If we freed a cache entry for our name which was a CNAME target, use that.
cache_unlink(new); and preserve the uid, so that existing CNAMES are not broken. */
break; if (target_crec)
} {
new = target_crec;
new->uid = target_uid;
}
/* Got the rest: finally grab entry. */
cache_unlink(new);
new->flags = flags; new->flags = flags;
if (big_name) if (big_name)
@@ -609,13 +644,27 @@ void cache_end_insert(void)
{ {
cache_hash(new_chain); cache_hash(new_chain);
cache_link(new_chain); cache_link(new_chain);
cache_inserted++; daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
} }
new_chain = tmp; new_chain = tmp;
} }
new_chain = NULL; new_chain = NULL;
} }
int cache_find_non_terminal(char *name, time_t now)
{
struct crec *crecp;
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
if (!is_outdated_cname_pointer(crecp) &&
!is_expired(now, crecp) &&
(crecp->flags & F_FORWARD) &&
hostname_isequal(name, cache_get_name(crecp)))
return 1;
return 0;
}
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot) struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
{ {
struct crec *ans; struct crec *ans;
@@ -776,15 +825,18 @@ static void add_hosts_cname(struct crec *target)
for (a = daemon->cnames; a; a = a->next) for (a = daemon->cnames; a; a = a->next)
if (a->alias[1] != '*' && if (a->alias[1] != '*' &&
hostname_isequal(cache_get_name(target), a->target) && hostname_isequal(cache_get_name(target), a->target) &&
(crec = whine_malloc(sizeof(struct crec)))) (crec = whine_malloc(SIZEOF_POINTER_CREC)))
{ {
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME; crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
crec->ttd = a->ttl; crec->ttd = a->ttl;
crec->name.namep = a->alias; crec->name.namep = a->alias;
crec->addr.cname.target.cache = target; crec->addr.cname.target.cache = target;
next_uid(target);
crec->addr.cname.uid = target->uid; crec->addr.cname.uid = target->uid;
crec->uid = next_uid(); crec->uid = UID_NONE;
cache_hash(crec); cache_hash(crec);
make_non_terminals(crec);
add_hosts_cname(crec); /* handle chains */ add_hosts_cname(crec); /* handle chains */
} }
} }
@@ -856,6 +908,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
cache->uid = index; cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen); memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache); cache_hash(cache);
make_non_terminals(cache);
/* don't need to do alias stuff for second and subsequent addresses. */ /* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists) if (!nameexists)
@@ -976,8 +1029,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
{ {
/* If set, add a version of the name with a default domain appended */ /* If set, add a version of the name with a default domain appended */
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn && if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) + (cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
{ {
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
strcat(cache->name.sname, "."); strcat(cache->name.sname, ".");
@@ -987,7 +1039,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz); add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++; name_count++;
} }
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME))) if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
{ {
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
cache->flags = flags; cache->flags = flags;
@@ -1026,7 +1078,8 @@ void cache_reload(void)
struct ds_config *ds; struct ds_config *ds;
#endif #endif
cache_inserted = cache_live_freed = 0; daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
for (i=0; i<hash_size; i++) for (i=0; i<hash_size; i++)
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp) for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
@@ -1059,21 +1112,22 @@ void cache_reload(void)
for (intr = daemon->int_names; intr; intr = intr->next) for (intr = daemon->int_names; intr; intr = intr->next)
if (a->alias[1] != '*' && if (a->alias[1] != '*' &&
hostname_isequal(a->target, intr->name) && hostname_isequal(a->target, intr->name) &&
((cache = whine_malloc(sizeof(struct crec))))) ((cache = whine_malloc(SIZEOF_POINTER_CREC))))
{ {
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG; cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
cache->ttd = a->ttl; cache->ttd = a->ttl;
cache->name.namep = a->alias; cache->name.namep = a->alias;
cache->addr.cname.target.int_name = intr; cache->addr.cname.target.int_name = intr;
cache->addr.cname.uid = SRC_INTERFACE; cache->addr.cname.uid = SRC_INTERFACE;
cache->uid = next_uid(); cache->uid = UID_NONE;
cache_hash(cache); cache_hash(cache);
make_non_terminals(cache);
add_hosts_cname(cache); /* handle chains */ add_hosts_cname(cache); /* handle chains */
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
for (ds = daemon->ds; ds; ds = ds->next) for (ds = daemon->ds; ds; ds = ds->next)
if ((cache = whine_malloc(sizeof(struct crec))) && if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen))) (cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
{ {
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP; cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
@@ -1085,6 +1139,7 @@ void cache_reload(void)
cache->addr.ds.digest = ds->digest_type; cache->addr.ds.digest = ds->digest_type;
cache->uid = ds->class; cache->uid = ds->class;
cache_hash(cache); cache_hash(cache);
make_non_terminals(cache);
} }
#endif #endif
@@ -1099,7 +1154,7 @@ void cache_reload(void)
for (nl = hr->names; nl; nl = nl->next) for (nl = hr->names; nl; nl = nl->next)
{ {
if (hr->addr.s_addr != 0 && if (hr->addr.s_addr != 0 &&
(cache = whine_malloc(sizeof(struct crec)))) (cache = whine_malloc(SIZEOF_POINTER_CREC)))
{ {
cache->name.namep = nl->name; cache->name.namep = nl->name;
cache->ttd = hr->ttl; cache->ttd = hr->ttl;
@@ -1108,7 +1163,7 @@ void cache_reload(void)
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) && if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
(cache = whine_malloc(sizeof(struct crec)))) (cache = whine_malloc(SIZEOF_POINTER_CREC)))
{ {
cache->name.namep = nl->name; cache->name.namep = nl->name;
cache->ttd = hr->ttl; cache->ttd = hr->ttl;
@@ -1185,7 +1240,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
if ((aliasc = dhcp_spare)) if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next; dhcp_spare = dhcp_spare->next;
else /* need new one */ else /* need new one */
aliasc = whine_malloc(sizeof(struct crec)); aliasc = whine_malloc(SIZEOF_POINTER_CREC);
if (aliasc) if (aliasc)
{ {
@@ -1196,9 +1251,11 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
aliasc->ttd = ttd; aliasc->ttd = ttd;
aliasc->name.namep = a->alias; aliasc->name.namep = a->alias;
aliasc->addr.cname.target.cache = target; aliasc->addr.cname.target.cache = target;
next_uid(target);
aliasc->addr.cname.uid = target->uid; aliasc->addr.cname.uid = target->uid;
aliasc->uid = next_uid(); aliasc->uid = UID_NONE;
cache_hash(aliasc); cache_hash(aliasc);
make_non_terminals(aliasc);
add_dhcp_cname(aliasc, ttd); add_dhcp_cname(aliasc, ttd);
} }
} }
@@ -1238,7 +1295,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
} }
else if (!(crec->flags & F_DHCP)) else if (!(crec->flags & F_DHCP))
{ {
cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD)); cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
/* scan_free deletes all addresses associated with name */ /* scan_free deletes all addresses associated with name */
break; break;
} }
@@ -1265,7 +1322,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
if (crec->flags & F_NEG) if (crec->flags & F_NEG)
{ {
flags |= F_REVERSE; flags |= F_REVERSE;
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags); cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags, NULL, NULL);
} }
} }
else else
@@ -1274,7 +1331,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
if ((crec = dhcp_spare)) if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next; dhcp_spare = dhcp_spare->next;
else /* need new one */ else /* need new one */
crec = whine_malloc(sizeof(struct crec)); crec = whine_malloc(SIZEOF_POINTER_CREC);
if (crec) /* malloc may fail */ if (crec) /* malloc may fail */
{ {
@@ -1285,14 +1342,108 @@ void cache_add_dhcp_entry(char *host_name, int prot,
crec->ttd = ttd; crec->ttd = ttd;
crec->addr.addr = *host_address; crec->addr.addr = *host_address;
crec->name.namep = host_name; crec->name.namep = host_name;
crec->uid = next_uid(); crec->uid = UID_NONE;
cache_hash(crec); cache_hash(crec);
make_non_terminals(crec);
add_dhcp_cname(crec, ttd); add_dhcp_cname(crec, ttd);
} }
} }
#endif #endif
/* Called when we put a local or DHCP name into the cache.
Creates empty cache entries for subnames (ie,
for three.two.one, for two.one and one), without
F_IPV4 or F_IPV6 or F_CNAME set. These convert
NXDOMAIN answers to NoData ones. */
static void make_non_terminals(struct crec *source)
{
char *name = cache_get_name(source);
struct crec *crecp, *tmp, **up;
int type = F_HOSTS | F_CONFIG;
#ifdef HAVE_DHCP
if (source->flags & F_DHCP)
type = F_DHCP;
#endif
/* First delete any empty entries for our new real name. Note that
we only delete empty entries deriving from DHCP for a new DHCP-derived
entry and vice-versa for HOSTS and CONFIG. This ensures that
non-terminals from DHCP go when we reload DHCP and
for HOSTS/CONFIG when we re-read. */
for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
{
tmp = crecp->hash_next;
if (!is_outdated_cname_pointer(crecp) &&
(crecp->flags & F_FORWARD) &&
(crecp->flags & type) &&
!(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
hostname_isequal(name, cache_get_name(crecp)))
{
*up = crecp->hash_next;
#ifdef HAVE_DHCP
if (type & F_DHCP)
{
crecp->next = dhcp_spare;
dhcp_spare = crecp;
}
else
#endif
free(crecp);
break;
}
else
up = &crecp->hash_next;
}
while ((name = strchr(name, '.')))
{
name++;
/* Look for one existing, don't need another */
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
if (!is_outdated_cname_pointer(crecp) &&
(crecp->flags & F_FORWARD) &&
(crecp->flags & type) &&
hostname_isequal(name, cache_get_name(crecp)))
break;
if (crecp)
{
/* If the new name expires later, transfer that time to
empty non-terminal entry. */
if (!(crecp->flags & F_IMMORTAL))
{
if (source->flags & F_IMMORTAL)
crecp->flags |= F_IMMORTAL;
else if (difftime(crecp->ttd, source->ttd) < 0)
crecp->ttd = source->ttd;
}
continue;
}
#ifdef HAVE_DHCP
if ((source->flags & F_DHCP) && dhcp_spare)
{
crecp = dhcp_spare;
dhcp_spare = dhcp_spare->next;
}
else
#endif
crecp = whine_malloc(SIZEOF_POINTER_CREC);
if (crecp)
{
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
crecp->ttd = source->ttd;
crecp->name.namep = name;
cache_hash(crecp);
}
}
}
#ifndef NO_ID #ifndef NO_ID
int cache_make_stat(struct txt_record *t) int cache_make_stat(struct txt_record *t)
{ {
@@ -1314,24 +1465,24 @@ int cache_make_stat(struct txt_record *t)
break; break;
case TXT_STAT_INSERTS: case TXT_STAT_INSERTS:
sprintf(buff+1, "%d", cache_inserted); sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
break; break;
case TXT_STAT_EVICTIONS: case TXT_STAT_EVICTIONS:
sprintf(buff+1, "%d", cache_live_freed); sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
break; break;
case TXT_STAT_MISSES: case TXT_STAT_MISSES:
sprintf(buff+1, "%u", daemon->queries_forwarded); sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
break; break;
case TXT_STAT_HITS: case TXT_STAT_HITS:
sprintf(buff+1, "%u", daemon->local_answer); sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
break; break;
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
case TXT_STAT_AUTH: case TXT_STAT_AUTH:
sprintf(buff+1, "%u", daemon->auth_answer); sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
break; break;
#endif #endif
@@ -1408,15 +1559,14 @@ static char *sanitise(char *name)
void dump_cache(time_t now) void dump_cache(time_t now)
{ {
struct server *serv, *serv1; struct server *serv, *serv1;
char *t = "";
my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now); my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."), my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
daemon->cachesize, cache_live_freed, cache_inserted); daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"), my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
daemon->queries_forwarded, daemon->local_answer); daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer); my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
#endif #endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
blockdata_report(); blockdata_report();
@@ -1454,6 +1604,7 @@ void dump_cache(time_t now)
for (i=0; i<hash_size; i++) for (i=0; i<hash_size; i++)
for (cache = hash_table[i]; cache; cache = cache->hash_next) for (cache = hash_table[i]; cache; cache = cache->hash_next)
{ {
char *t = " ";
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache); char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
*a = 0; *a = 0;
if (strlen(n) == 0 && !(cache->flags & F_REVERSE)) if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
@@ -1511,7 +1662,7 @@ void dump_cache(time_t now)
/* ctime includes trailing \n - eat it */ /* ctime includes trailing \n - eat it */
*(p-1) = 0; *(p-1) = 0;
#endif #endif
my_syslog(LOG_INFO, daemon->namebuff); my_syslog(LOG_INFO, "%s", daemon->namebuff);
} }
} }
} }
@@ -1554,9 +1705,13 @@ char *querystr(char *desc, unsigned short type)
break; break;
} }
len += 3; /* braces, terminator */ if (desc)
len += strlen(desc); {
len += 2; /* braces */
len += strlen(desc);
}
len++; /* terminator */
if (!buff || bufflen < len) if (!buff || bufflen < len)
{ {
if (buff) if (buff)
@@ -1570,12 +1725,22 @@ char *querystr(char *desc, unsigned short type)
if (buff) if (buff)
{ {
if (types) if (desc)
sprintf(buff, "%s[%s]", desc, types); {
if (types)
sprintf(buff, "%s[%s]", desc, types);
else
sprintf(buff, "%s[type=%d]", desc, type);
}
else else
sprintf(buff, "%s[type=%d]", desc, type); {
if (types)
sprintf(buff, "<%s>", types);
else
sprintf(buff, "type=%d", type);
}
} }
return buff ? buff : ""; return buff ? buff : "";
} }
@@ -1593,6 +1758,19 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
{ {
if (flags & F_KEYTAG) if (flags & F_KEYTAG)
sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest); sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
else if (flags & F_RCODE)
{
unsigned int rcode = addr->addr.rcode.rcode;
if (rcode == SERVFAIL)
dest = "SERVFAIL";
else if (rcode == REFUSED)
dest = "REFUSED";
else if (rcode == NOTIMP)
dest = "not implemented";
else
sprintf(daemon->addrbuff, "%u", rcode);
}
else else
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
+19 -6
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 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 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 TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */ #define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 20 /* or 20 seconds */ #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 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 LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */ #define RANDOM_SOCKS 64 /* max simultaneous random ports */
@@ -93,6 +94,9 @@ HAVE_DBUS
support some methods to allow (re)configuration of the upstream DNS support some methods to allow (re)configuration of the upstream DNS
servers via DBus. servers via DBus.
HAVE_UBUS
define this if you want to link against libubus
HAVE_IDN HAVE_IDN
define this if you want international domain name 2003 support. define this if you want international domain name 2003 support.
@@ -116,6 +120,9 @@ HAVE_AUTH
HAVE_DNSSEC HAVE_DNSSEC
include DNSSEC validator. include DNSSEC validator.
HAVE_DUMPFILE
include code to dump packets to a libpcap-format file for debugging.
HAVE_LOOP HAVE_LOOP
include functionality to probe for and remove DNS forwarding loops. include functionality to probe for and remove DNS forwarding loops.
@@ -131,14 +138,12 @@ NO_DHCP6
NO_SCRIPT NO_SCRIPT
NO_LARGEFILE NO_LARGEFILE
NO_AUTH NO_AUTH
NO_DUMPFILE
NO_INOTIFY NO_INOTIFY
these are available to explicitly disable compile time options which would these are available to explicitly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq which are enabled by default in the distributed source tree. Building dnsmasq
with something like "make COPTS=-DNO_SCRIPT" will do the trick. 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 NO_GMP
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp. Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
@@ -166,6 +171,7 @@ RESOLVFILE
#define HAVE_AUTH #define HAVE_AUTH
#define HAVE_IPSET #define HAVE_IPSET
#define HAVE_LOOP #define HAVE_LOOP
#define HAVE_DUMPFILE
/* Build options which require external libraries. /* Build options which require external libraries.
@@ -365,6 +371,10 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_LOOP #undef HAVE_LOOP
#endif #endif
#ifdef NO_DUMPFILE
#undef HAVE_DUMPFILE
#endif
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY) #if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
#define HAVE_INOTIFY #define HAVE_INOTIFY
#endif #endif
@@ -453,8 +463,11 @@ static char *compile_opts =
#ifndef HAVE_INOTIFY #ifndef HAVE_INOTIFY
"no-" "no-"
#endif #endif
"inotify"; "inotify "
#ifndef HAVE_DUMPFILE
"no-"
#endif
"dumpfile";
#endif #endif
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+460
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
+32 -1
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 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 it under the terms of the GNU General Public License as published by
@@ -85,6 +85,9 @@ const char* introspection_xml_template =
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n" " <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
" </method>\n" " </method>\n"
#endif #endif
" <method name=\"GetMetrics\">\n"
" <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
" </method>\n"
" </interface>\n" " </interface>\n"
"</node>\n"; "</node>\n";
@@ -613,6 +616,30 @@ static DBusMessage *dbus_del_lease(DBusMessage* message)
} }
#endif #endif
static DBusMessage *dbus_get_metrics(DBusMessage* message)
{
DBusMessage *reply = dbus_message_new_method_return(message);
DBusMessageIter array, dict, iter;
int i;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
for (i = 0; i < __METRIC_MAX; i++) {
const char *key = get_metric_name(i);
dbus_uint32_t value = daemon->metrics[i];
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
dbus_message_iter_close_container(&array, &dict);
}
dbus_message_iter_close_container(&iter, &array);
return reply;
}
DBusHandlerResult message_handler(DBusConnection *connection, DBusHandlerResult message_handler(DBusConnection *connection,
DBusMessage *message, DBusMessage *message,
void *user_data) void *user_data)
@@ -680,6 +707,10 @@ DBusHandlerResult message_handler(DBusConnection *connection,
reply = dbus_del_lease(message); reply = dbus_del_lease(message);
} }
#endif #endif
else if (strcmp(method, "GetMetrics") == 0)
{
reply = dbus_get_metrics(message);
}
else if (strcmp(method, "ClearCache") == 0) else if (strcmp(method, "ClearCache") == 0)
clear_cache = 1; clear_cache = 1;
else else
+6 -5
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 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 it under the terms of the GNU General Public License as published by
@@ -485,11 +485,11 @@ char *whichdevice(void)
void bindtodevice(char *device, int fd) void bindtodevice(char *device, int fd)
{ {
struct ifreq ifr; size_t len = strlen(device)+1;
if (len > IFNAMSIZ)
strcpy(ifr.ifr_name, device); len = IFNAMSIZ;
/* only allowed by root. */ /* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 && if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
errno != EPERM) errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
} }
@@ -559,6 +559,7 @@ static const struct opttab_t {
{ "nntp-server", 71, OT_ADDR_LIST }, { "nntp-server", 71, OT_ADDR_LIST },
{ "irc-server", 74, OT_ADDR_LIST }, { "irc-server", 74, OT_ADDR_LIST },
{ "user-class", 77, 0 }, { "user-class", 77, 0 },
{ "rapid-commit", 80, 0 },
{ "FQDN", 81, OT_INTERNAL }, { "FQDN", 81, OT_INTERNAL },
{ "agent-id", 82, OT_INTERNAL }, { "agent-id", 82, OT_INTERNAL },
{ "client-arch", 93, 2 | OT_DEC }, { "client-arch", 93, 2 | OT_DEC },
+2 -1
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 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 it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
#define OPTION_SNAME 66 #define OPTION_SNAME 66
#define OPTION_FILENAME 67 #define OPTION_FILENAME 67
#define OPTION_USER_CLASS 77 #define OPTION_USER_CLASS 77
#define OPTION_RAPID_COMMIT 80
#define OPTION_CLIENT_FQDN 81 #define OPTION_CLIENT_FQDN 81
#define OPTION_AGENT_ID 82 #define OPTION_AGENT_ID 82
#define OPTION_ARCH 93 #define OPTION_ARCH 93
+8 -9
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 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 it under the terms of the GNU General Public License as published by
@@ -232,7 +232,7 @@ void dhcp_packet(time_t now, int pxe_fd)
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
/* ARP fiddling uses original interface even if we pretend to use a different one. */ /* ARP fiddling uses original interface even if we pretend to use a different one. */
strncpy(arp_req.arp_dev, ifr.ifr_name, 16); safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
#endif #endif
/* If the interface on which the DHCP request was received is an /* If the interface on which the DHCP request was received is an
@@ -255,7 +255,7 @@ void dhcp_packet(time_t now, int pxe_fd)
} }
else else
{ {
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE); safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
break; break;
} }
} }
@@ -273,13 +273,13 @@ void dhcp_packet(time_t now, int pxe_fd)
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name))) if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
{ {
/* Reply from server, using us as relay. */ /* Reply from server, using us as relay. */
iface_index = relay->iface_index; rcvd_iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name)) if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
return; return;
is_relay_reply = 1; is_relay_reply = 1;
iov.iov_len = sz; iov.iov_len = sz;
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
strncpy(arp_req.arp_dev, ifr.ifr_name, 16); safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
#endif #endif
} }
else else
@@ -678,7 +678,7 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
if ((count >= max) || option_bool(OPT_NO_PING) || loopback) if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
{ {
/* overloaded, or configured not to check, loopback interface, return "not in use" */ /* overloaded, or configured not to check, loopback interface, return "not in use" */
dummy.hash = 0; dummy.hash = hash;
return &dummy; return &dummy;
} }
else if (icmp_ping(addr)) else if (icmp_ping(addr))
@@ -988,8 +988,7 @@ char *host_from_dns(struct in_addr addr)
if (!legal_hostname(hostname)) if (!legal_hostname(hostname))
return NULL; return NULL;
strncpy(daemon->dhcp_buff, hostname, 256); safe_strncpy(daemon->dhcp_buff, hostname, 256);
daemon->dhcp_buff[255] = 0;
strip_hostname(daemon->dhcp_buff); strip_hostname(daemon->dhcp_buff);
return daemon->dhcp_buff; return daemon->dhcp_buff;
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+31 -15
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 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 it under the terms of the GNU General Public License as published by
@@ -640,13 +640,20 @@ static int construct_worker(struct in6_addr *local, int prefix,
return 0; return 0;
for (template = daemon->dhcp6; template; template = template->next) for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & CONTEXT_TEMPLATE)) if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED)))
{ {
/* non-template entries, just fill in interface and local addresses */ /* non-template entries, just fill in interface and local addresses */
if (prefix <= template->prefix && if (prefix <= template->prefix &&
is_same_net6(local, &template->start6, template->prefix) && is_same_net6(local, &template->start6, template->prefix) &&
is_same_net6(local, &template->end6, template->prefix)) is_same_net6(local, &template->end6, template->prefix))
{ {
/* First time found, do fast RA. */
if (template->if_index != if_index || !IN6_ARE_ADDR_EQUAL(&template->local6, local))
{
ra_start_unsolicited(param->now, template);
param->newone = 1;
}
template->if_index = if_index; template->if_index = if_index;
template->local6 = *local; template->local6 = *local;
} }
@@ -661,24 +668,33 @@ static int construct_worker(struct in6_addr *local, int prefix,
setaddr6part(&end6, addr6part(&template->end6)); setaddr6part(&end6, addr6part(&template->end6));
for (context = daemon->dhcp6; context; context = context->next) for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) && if (!(context->flags & CONTEXT_TEMPLATE) &&
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) && IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6)) IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{ {
int flags = context->flags; /* If there's an absolute address context covering this address
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD); then don't construct one as well. */
if (flags & CONTEXT_OLD) if (!(context->flags & CONTEXT_CONSTRUCTED))
break;
if (context->if_index == if_index)
{ {
/* address went, now it's back */ int cflags = context->flags;
log_context(AF_INET6, context); context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
/* fast RAs for a while */ if (cflags & CONTEXT_OLD)
ra_start_unsolicited(param->now, context); {
param->newone = 1; /* address went, now it's back, and on the same interface */
/* Add address to name again */ log_context(AF_INET6, context);
if (context->flags & CONTEXT_RA_NAME) /* fast RAs for a while */
param->newname = 1; ra_start_unsolicited(param->now, context);
param->newone = 1;
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
}
break;
} }
break;
} }
if (!context && (context = whine_malloc(sizeof (struct dhcp_context)))) if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
+3 -1
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 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 it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
#define NAMESERVER_PORT 53 #define NAMESERVER_PORT 53
#define TFTP_PORT 69 #define TFTP_PORT 69
#define MIN_PORT 1024 /* first non-reserved port */
#define MAX_PORT 65535u #define MAX_PORT 65535u
#define IN6ADDRSZ 16 #define IN6ADDRSZ 16
@@ -75,6 +76,7 @@
#define T_AXFR 252 #define T_AXFR 252
#define T_MAILB 253 #define T_MAILB 253
#define T_ANY 255 #define T_ANY 255
#define T_CAA 257
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */ #define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */ #define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
+114 -37
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 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 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); long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL; char *baduser = NULL;
int log_err; int log_err;
int chown_warn = 0;
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
cap_user_header_t hdr = NULL; cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL; cap_user_data_t data = NULL;
@@ -77,7 +78,8 @@ int main (int argc, char **argv)
sigaction(SIGTERM, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL); sigaction(SIGALRM, &sigact, NULL);
sigaction(SIGCHLD, &sigact, NULL); sigaction(SIGCHLD, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
/* ignore SIGPIPE */ /* ignore SIGPIPE */
sigact.sa_handler = SIG_IGN; sigact.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL);
@@ -118,6 +120,9 @@ int main (int argc, char **argv)
daemon->namebuff = safe_malloc(MAXDNAME * 2); daemon->namebuff = safe_malloc(MAXDNAME * 2);
daemon->keyname = safe_malloc(MAXDNAME * 2); daemon->keyname = safe_malloc(MAXDNAME * 2);
daemon->workspacename = 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 #endif
@@ -211,7 +216,7 @@ int main (int argc, char **argv)
#endif #endif
#ifndef HAVE_AUTH #ifndef HAVE_AUTH
if (daemon->authserver) if (daemon->authserver || daemon->auth_zones)
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF); die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
#endif #endif
@@ -220,16 +225,18 @@ int main (int argc, char **argv)
die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF); die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
#endif #endif
if (daemon->max_port != MAX_PORT && daemon->min_port == 0) #ifndef HAVE_UBUS
daemon->min_port = 1024u; if (option_bool(OPT_UBUS))
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
#endif
if (daemon->max_port < daemon->min_port) if (daemon->max_port < daemon->min_port)
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF); die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
now = dnsmasq_time(); now = dnsmasq_time();
/* Create a serial at startup if not configured. */ /* Create a serial at startup if not configured. */
if (daemon->authinterface && daemon->soa_sn == 0) if (daemon->auth_zones && daemon->soa_sn == 0)
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF); die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
#else #else
@@ -358,12 +365,22 @@ int main (int argc, char **argv)
} }
#ifdef HAVE_INOTIFY #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(); inotify_dnsmasq_init();
else else
daemon->inotifyfd = -1; daemon->inotifyfd = -1;
#endif #endif
if (daemon->dump_file)
#ifdef HAVE_DUMPFILE
dump_init();
else
daemon->dumpfd = -1;
#else
die(_("Packet dumps not available: set HAVE_DUMP in src/config.h"), NULL, EC_BADCONF);
#endif
if (option_bool(OPT_DBUS)) if (option_bool(OPT_DBUS))
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
{ {
@@ -386,10 +403,12 @@ int main (int argc, char **argv)
daemon->scriptuser && daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript)) (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_uid = scr_pw->pw_uid;
script_gid = ent_pw->pw_gid; script_gid = scr_pw->pw_gid;
} }
else else
baduser = daemon->scriptuser; baduser = daemon->scriptuser;
@@ -537,9 +556,18 @@ int main (int argc, char **argv)
} }
else 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)) if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
err = 1; err = 1;
else else
{ {
while (retry_send(close(fd))); while (retry_send(close(fd)));
if (errno != 0) if (errno != 0)
@@ -717,7 +745,11 @@ int main (int argc, char **argv)
else else
{ {
if (daemon->cachesize != 0) if (daemon->cachesize != 0)
my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize); {
my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
if (daemon->cachesize > 10000)
my_syslog(LOG_WARNING, _("cache size greater than 10000 may cause performance issues, and is unlikely to be useful."));
}
else else
my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION); my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
@@ -726,6 +758,9 @@ int main (int argc, char **argv)
} }
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts); my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
if (chown_warn != 0)
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
if (option_bool(OPT_DBUS)) if (option_bool(OPT_DBUS))
@@ -741,7 +776,8 @@ int main (int argc, char **argv)
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
{ {
int rc; int rc;
struct ds_config *ds;
/* Delay creating the timestamp file until here, after we've changed user, so that /* Delay creating the timestamp file until here, after we've changed user, so that
it has the correct owner to allow updating the mtime later. it has the correct owner to allow updating the mtime later.
This means we have to report fatal errors via the pipe. */ This means we have to report fatal errors via the pipe. */
@@ -751,14 +787,21 @@ int main (int argc, char **argv)
_exit(0); _exit(0);
} }
my_syslog(LOG_INFO, _("DNSSEC validation enabled")); if (option_bool(OPT_DNSSEC_IGN_NS))
my_syslog(LOG_INFO, _("DNSSEC validation enabled but all unsigned answers are trusted"));
else
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME); daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future) 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) if (rc == 1)
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid")); my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
for (ds = daemon->ds; ds; ds = ds->next)
my_syslog(LOG_INFO, _("configured with trust anchor for %s keytag %u"),
ds->name[0] == 0 ? "<root>" : ds->name, ds->keytag);
} }
#endif #endif
@@ -909,8 +952,13 @@ int main (int argc, char **argv)
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
set_dbus_listeners(); set_dbus_listeners();
#endif #endif
#ifdef HAVE_UBUS
if (option_bool(OPT_UBUS))
set_ubus_listeners();
#endif
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->relay4) if (daemon->dhcp || daemon->relay4)
{ {
@@ -1040,7 +1088,12 @@ int main (int argc, char **argv)
} }
check_dbus_listeners(); check_dbus_listeners();
#endif #endif
#ifdef HAVE_UBUS
if (option_bool(OPT_UBUS))
check_ubus_listeners();
#endif
check_dns_listeners(now); check_dns_listeners(now);
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
@@ -1079,7 +1132,7 @@ static void sig_handler(int sig)
{ {
/* ignore anything other than TERM during startup /* ignore anything other than TERM during startup
and in helper proc. (helper ignore TERM too) */ and in helper proc. (helper ignore TERM too) */
if (sig == SIGTERM) if (sig == SIGTERM || sig == SIGINT)
exit(EC_MISC); exit(EC_MISC);
} }
else if (pid != getpid()) else if (pid != getpid())
@@ -1105,6 +1158,15 @@ static void sig_handler(int sig)
event = EVENT_DUMP; event = EVENT_DUMP;
else if (sig == SIGUSR2) else if (sig == SIGUSR2)
event = EVENT_REOPEN; 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 else
return; return;
@@ -1187,31 +1249,40 @@ static void fatal_event(struct event_desc *ev, char *msg)
case EVENT_FORK_ERR: case EVENT_FORK_ERR:
die(_("cannot fork into background: %s"), NULL, EC_MISC); die(_("cannot fork into background: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_PIPE_ERR: case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC); die(_("failed to create helper: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_CAP_ERR: case EVENT_CAP_ERR:
die(_("setting capabilities failed: %s"), NULL, EC_MISC); die(_("setting capabilities failed: %s"), NULL, EC_MISC);
/* fall through */
case EVENT_USER_ERR: case EVENT_USER_ERR:
die(_("failed to change user-id to %s: %s"), msg, EC_MISC); die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
/* fall through */
case EVENT_GROUP_ERR: case EVENT_GROUP_ERR:
die(_("failed to change group-id to %s: %s"), msg, EC_MISC); die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
/* fall through */
case EVENT_PIDFILE: case EVENT_PIDFILE:
die(_("failed to open pidfile %s: %s"), msg, EC_FILE); die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
/* fall through */
case EVENT_LOG_ERR: case EVENT_LOG_ERR:
die(_("cannot open log %s: %s"), msg, EC_FILE); die(_("cannot open log %s: %s"), msg, EC_FILE);
/* fall through */
case EVENT_LUA_ERR: case EVENT_LUA_ERR:
die(_("failed to load Lua script: %s"), msg, EC_MISC); die(_("failed to load Lua script: %s"), msg, EC_MISC);
/* fall through */
case EVENT_TFTP_ERR: case EVENT_TFTP_ERR:
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE); die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
/* fall through */
case EVENT_TIME_ERR: case EVENT_TIME_ERR:
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF); die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
} }
@@ -1232,14 +1303,7 @@ static void async_event(int pipe, time_t now)
{ {
case EVENT_RELOAD: case EVENT_RELOAD:
daemon->soa_sn++; /* Bump zone serial, as it may have changed. */ 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 */ /* fall through */
case EVENT_INIT: case EVENT_INIT:
@@ -1348,6 +1412,17 @@ static void async_event(int pipe, time_t now)
poll_resolv(0, 1, now); poll_resolv(0, 1, now);
break; 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: case EVENT_TERM:
/* Knock all our children on the head. */ /* Knock all our children on the head. */
for (i = 0; i < MAX_PROCS; i++) for (i = 0; i < MAX_PROCS; i++)
@@ -1382,6 +1457,11 @@ static void async_event(int pipe, time_t now)
if (daemon->runfile) if (daemon->runfile)
unlink(daemon->runfile); unlink(daemon->runfile);
#ifdef HAVE_DUMPFILE
if (daemon->dumpfd != -1)
close(daemon->dumpfd);
#endif
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM")); my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
flush_log(); flush_log();
@@ -1472,9 +1552,6 @@ void clear_cache_and_reload(time_t now)
if (option_bool(OPT_ETHERS)) if (option_bool(OPT_ETHERS))
dhcp_read_ethers(); dhcp_read_ethers();
reread_dhcp(); reread_dhcp();
#ifdef HAVE_INOTIFY
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
#endif
dhcp_update_configs(daemon->dhcp_conf); dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs(); lease_update_from_configs();
lease_update_file(now); lease_update_file(now);
+124 -33
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 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 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/>. 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 #ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */ /* Ensure we can use files >2GB (log files may grow this big) */
@@ -36,6 +42,12 @@
# define __EXTENSIONS__ # define __EXTENSIONS__
#endif #endif
#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__clang__)
#define ATTRIBUTE_NORETURN __attribute__ ((noreturn))
#else
#define ATTRIBUTE_NORETURN
#endif
/* get these before config.h for IPv6 stuff... */ /* get these before config.h for IPv6 stuff... */
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -51,6 +63,7 @@
#include "config.h" #include "config.h"
#include "ip6addr.h" #include "ip6addr.h"
#include "metrics.h"
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
@@ -113,6 +126,9 @@ typedef unsigned long long u64;
#include <net/if_arp.h> #include <net/if_arp.h>
#include <netinet/in_systm.h> #include <netinet/in_systm.h>
#include <netinet/ip.h> #include <netinet/ip.h>
#ifdef HAVE_IPV6
#include <netinet/ip6.h>
#endif
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <syslog.h> #include <syslog.h>
@@ -136,6 +152,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
#include <priv.h> #include <priv.h>
#endif #endif
#ifdef HAVE_DNSSEC
# include <nettle/nettle-meta.h>
#endif
/* daemon is function in the C library.... */ /* daemon is function in the C library.... */
#define daemon dnsmasq_daemon #define daemon dnsmasq_daemon
@@ -169,6 +189,7 @@ struct event_desc {
#define EVENT_NEWROUTE 23 #define EVENT_NEWROUTE 23
#define EVENT_TIME_ERR 24 #define EVENT_TIME_ERR 24
#define EVENT_SCRIPT_LOG 25 #define EVENT_SCRIPT_LOG 25
#define EVENT_TIME 26
/* Exit codes. */ /* Exit codes. */
#define EC_GOOD 0 #define EC_GOOD 0
@@ -230,7 +251,7 @@ struct event_desc {
#define OPT_DNSSEC_VALID 45 #define OPT_DNSSEC_VALID 45
#define OPT_DNSSEC_TIME 46 #define OPT_DNSSEC_TIME 46
#define OPT_DNSSEC_DEBUG 47 #define OPT_DNSSEC_DEBUG 47
#define OPT_DNSSEC_NO_SIGN 48 #define OPT_DNSSEC_IGN_NS 48
#define OPT_LOCAL_SERVICE 49 #define OPT_LOCAL_SERVICE 49
#define OPT_LOOP_DETECT 50 #define OPT_LOOP_DETECT 50
#define OPT_EXTRALOG 51 #define OPT_EXTRALOG 51
@@ -239,7 +260,9 @@ struct event_desc {
#define OPT_MAC_B64 54 #define OPT_MAC_B64 54
#define OPT_MAC_HEX 55 #define OPT_MAC_HEX 55
#define OPT_TFTP_APREF_MAC 56 #define OPT_TFTP_APREF_MAC 56
#define OPT_LAST 57 #define OPT_RAPID_COMMIT 57
#define OPT_UBUS 58
#define OPT_LAST 59
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -256,7 +279,11 @@ struct all_addr {
/* for log_query */ /* for log_query */
struct { struct {
unsigned short keytag, algo, digest; unsigned short keytag, algo, digest;
} log; } log;
/* for log_query */
struct {
unsigned int rcode;
} rcode;
/* for cache_insert of DNSKEY, DS */ /* for cache_insert of DNSKEY, DS */
struct { struct {
unsigned short class, type; unsigned short class, type;
@@ -415,6 +442,9 @@ struct crec {
} name; } name;
}; };
#define SIZEOF_BARE_CREC (sizeof(struct crec) - SMALLDNAME)
#define SIZEOF_POINTER_CREC (sizeof(struct crec) + sizeof(char *) - SMALLDNAME)
#define F_IMMORTAL (1u<<0) #define F_IMMORTAL (1u<<0)
#define F_NAMEP (1u<<1) #define F_NAMEP (1u<<1)
#define F_REVERSE (1u<<2) #define F_REVERSE (1u<<2)
@@ -446,9 +476,15 @@ struct crec {
#define F_NO_RR (1u<<25) #define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26) #define F_IPSET (1u<<26)
#define F_NOEXTRA (1u<<27) #define F_NOEXTRA (1u<<27)
#define F_SERVFAIL (1u<<28)
#define F_RCODE (1u<<29)
#define UID_NONE 0
/* Values of uid in crecs with F_CONFIG bit set. */ /* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0 /* cname to uid SRC_INTERFACE are to interface names,
so use UID_NONE for that to eliminate clashes with
any other uid */
#define SRC_INTERFACE UID_NONE
#define SRC_CONFIG 1 #define SRC_CONFIG 1
#define SRC_HOSTS 2 #define SRC_HOSTS 2
#define SRC_AH 3 #define SRC_AH 3
@@ -493,7 +529,7 @@ struct serverfd {
int fd; int fd;
union mysockaddr source_addr; union mysockaddr source_addr;
char interface[IF_NAMESIZE+1]; char interface[IF_NAMESIZE+1];
unsigned int ifindex, used; unsigned int ifindex, used, preallocated;
struct serverfd *next; struct serverfd *next;
}; };
@@ -508,6 +544,7 @@ struct server {
struct serverfd *sfd; struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */ char *domain; /* set if this server only handles a domain. */
int flags, tcpfd, edns_pktsz; int flags, tcpfd, edns_pktsz;
time_t pktsz_reduced;
unsigned int queries, failed_queries; unsigned int queries, failed_queries;
#ifdef HAVE_LOOP #ifdef HAVE_LOOP
u32 uid; u32 uid;
@@ -579,6 +616,16 @@ struct hostsfile {
unsigned int index; /* matches to cache entries for logging */ unsigned int index; /* matches to cache entries for logging */
}; };
/* packet-dump flags */
#define DUMP_QUERY 0x0001
#define DUMP_REPLY 0x0002
#define DUMP_UP_QUERY 0x0004
#define DUMP_UP_REPLY 0x0008
#define DUMP_SEC_QUERY 0x0010
#define DUMP_SEC_REPLY 0x0020
#define DUMP_BOGUS 0x0040
#define DUMP_SEC_BOGUS 0x0080
/* DNSSEC status values. */ /* DNSSEC status values. */
#define STAT_SECURE 1 #define STAT_SECURE 1
@@ -784,6 +831,13 @@ struct dhcp_boot {
struct dhcp_boot *next; struct dhcp_boot *next;
}; };
struct dhcp_match_name {
char *name;
int wildcard;
struct dhcp_netid *netid;
struct dhcp_match_name *next;
};
struct pxe_service { struct pxe_service {
unsigned short CSA, type; unsigned short CSA, type;
char *menu, *basename, *sname; char *menu, *basename, *sname;
@@ -826,7 +880,7 @@ struct cond_domain {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
struct in6_addr start6, end6; struct in6_addr start6, end6;
#endif #endif
int is6; int is6, indexed;
struct cond_domain *next; struct cond_domain *next;
}; };
@@ -976,6 +1030,7 @@ extern struct daemon {
struct ra_interface *ra_interfaces; struct ra_interface *ra_interfaces;
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6; struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_match_name *dhcp_name_match;
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;
@@ -1001,14 +1056,15 @@ extern struct daemon {
unsigned int duid_enterprise, duid_config_len; unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config; unsigned char *duid_config;
char *dbus_name; char *dbus_name;
char *dump_file;
int dump_mask;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry; unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
u32 metrics[__METRIC_MAX];
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
struct prefix_class *prefix_classes; struct prefix_class *prefix_classes;
#endif #endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
struct ds_config *ds; struct ds_config *ds;
int dnssec_no_time_check;
int back_to_the_future;
char *timestamp_file; char *timestamp_file;
#endif #endif
@@ -1019,8 +1075,11 @@ extern struct daemon {
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */ char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */ char *workspacename; /* ditto */
char *rr_status; /* flags for individual RRs */
int rr_status_sz;
int dnssec_no_time_check;
int back_to_the_future;
#endif #endif
unsigned int local_answer, queries_forwarded, auth_answer;
struct frec *frec_list; struct frec *frec_list;
struct serverfd *sfds; struct serverfd *sfds;
struct irec *interfaces; struct irec *interfaces;
@@ -1073,13 +1132,19 @@ extern struct daemon {
char *addrbuff; char *addrbuff;
char *addrbuff2; /* only allocated when OPT_EXTRALOG */ char *addrbuff2; /* only allocated when OPT_EXTRALOG */
#ifdef HAVE_DUMPFILE
/* file for packet dumps. */
int dumpfd;
#endif
} *daemon; } *daemon;
/* cache.c */ /* cache.c */
void cache_init(void); void cache_init(void);
void next_uid(struct crec *crecp);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg); void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(unsigned int index); char *record_source(unsigned int index);
char *querystr(char *desc, unsigned short type); char *querystr(char *desc, unsigned short type);
int cache_find_non_terminal(char *name, time_t now);
struct crec *cache_find_by_addr(struct crec *crecp, struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now, struct all_addr *addr, time_t now,
unsigned int prot); unsigned int prot);
@@ -1130,18 +1195,18 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep); char *name, unsigned short *typep);
size_t setup_reply(struct dns_header *header, size_t qlen, size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags, struct all_addr *addrp, unsigned int flags,
unsigned long local_ttl); unsigned long ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, char **ipsets, int is_sign, int checkrebind, time_t now, char **ipsets, int is_sign, int check_rebind,
int no_cache, int secure, int *doctored); int no_cache_dnssec, int secure, int *doctored);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int have_pseudoheader); 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, 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_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
int check_for_local_domain(char *name, time_t now); 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, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int add_resource_record(struct dns_header *header, char *limit, int *truncp,
@@ -1163,29 +1228,40 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
/* dnssec.c */ /* 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); 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_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 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 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); size_t filter_rrsigs(struct dns_header *header, size_t plen);
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name); unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
int setup_timestamp(void); 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 */ /* util.c */
void rand_init(void); void rand_init(void);
unsigned short rand16(void); unsigned short rand16(void);
u32 rand32(void); u32 rand32(void);
u64 rand64(void); u64 rand64(void);
int legal_hostname(char *c); int legal_hostname(char *name);
char *canonicalise(char *s, int *nomem); char *canonicalise(char *in, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval); unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
void *safe_malloc(size_t size); void *safe_malloc(size_t size);
void safe_strncpy(char *dest, const char *src, size_t size);
void safe_pipe(int *fd, int read_noblock); void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size); void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr); int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2); int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(const char *a, const char *b); int hostname_isequal(const char *a, const char *b);
int hostname_issubdomain(char *a, char *b);
time_t dnsmasq_time(void); time_t dnsmasq_time(void);
int netmask_length(struct in_addr mask); int netmask_length(struct in_addr mask);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask); int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
@@ -1209,10 +1285,12 @@ int wildcard_match(const char* wildcard, const char* match);
int wildcard_matchn(const char* wildcard, const char* match, int num); int wildcard_matchn(const char* wildcard, const char* match, int num);
/* log.c */ /* log.c */
void die(char *message, char *arg1, int exit_code); void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN;
int log_start(struct passwd *ent_pw, int errfd); int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file); int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...); void my_syslog(int priority, const char *format, ...);
void set_log_writer(void); void set_log_writer(void);
void check_log_writer(int force); void check_log_writer(int force);
void flush_log(void); void flush_log(void);
@@ -1240,13 +1318,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, int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source, union mysockaddr *to, struct all_addr *source,
unsigned int iface); unsigned int iface);
void resend_query(); void resend_query(void);
struct randfd *allocate_rfd(int family); struct randfd *allocate_rfd(int family);
void free_rfd(struct randfd *rfd); void free_rfd(struct randfd *rfd);
/* network.c */ /* network.c */
int indextoname(int fd, int index, char *name); 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); int random_sock(int family);
void pre_allocate_sfds(void); void pre_allocate_sfds(void);
int reload_servers(char *fname); int reload_servers(char *fname);
@@ -1260,12 +1338,12 @@ void add_update_server(int flags,
void check_servers(void); void check_servers(void);
int enumerate_interfaces(int reset); int enumerate_interfaces(int reset);
void create_wildcard_listeners(void); void create_wildcard_listeners(void);
void create_bound_listeners(int die); void create_bound_listeners(int dienow);
void warn_bound_listeners(void); void warn_bound_listeners(void);
void warn_wild_labels(void); void warn_wild_labels(void);
void warn_int_names(void); void warn_int_names(void);
int is_dad_listeners(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 loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr); int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd); int fix_fd(int fd);
@@ -1286,7 +1364,7 @@ void newaddress(time_t now);
void dhcp_init(void); void dhcp_init(void);
void dhcp_packet(time_t now, int pxe_fd); void dhcp_packet(time_t now, int pxe_fd);
struct dhcp_context *address_available(struct dhcp_context *context, struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr, struct in_addr taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr, struct in_addr taddr,
@@ -1345,7 +1423,7 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int loopback, size_t sz, time_t now, int unicast_dest, int loopback,
int *is_inform, int pxe_fd, struct in_addr fallback, time_t recvtime); int *is_inform, int pxe, struct in_addr fallback, time_t recvtime);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr, unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out); int clid_len, unsigned char *clid, int *len_out);
#endif #endif
@@ -1389,6 +1467,13 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif # endif
#endif #endif
/* ubus.c */
#ifdef HAVE_UBUS
void set_ubus_listeners(void);
void check_ubus_listeners(void);
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
#endif
/* ipset.c */ /* ipset.c */
#ifdef HAVE_IPSET #ifdef HAVE_IPSET
void ipset_init(void); void ipset_init(void);
@@ -1460,10 +1545,10 @@ unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arriva
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
void dhcp_common_init(void); void dhcp_common_init(void);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg); 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_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
struct dhcp_opt *opts); 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); char *strip_hostname(char *hostname);
void log_tags(struct dhcp_netid *netid, u32 xid); void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len); int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
@@ -1521,13 +1606,13 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
/* loop.c */ /* loop.c */
#ifdef HAVE_LOOP #ifdef HAVE_LOOP
void loop_send_probes(); void loop_send_probes(void);
int detect_loop(char *query, int type); int detect_loop(char *query, int type);
#endif #endif
/* inotify.c */ /* inotify.c */
#ifdef HAVE_INOTIFY #ifdef HAVE_INOTIFY
void inotify_dnsmasq_init(); void inotify_dnsmasq_init(void);
int inotify_check(time_t now); int inotify_check(time_t now);
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz); void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#endif #endif
@@ -1556,3 +1641,9 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
/* arp.c */ /* arp.c */
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now); int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
int do_arp_script_run(void); int do_arp_script_run(void);
/* dump.c */
#ifdef HAVE_DUMPFILE
void dump_init(void);
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
#endif
+280 -456
View File
@@ -1,5 +1,5 @@
/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com> /* 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 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 it under the terms of the GNU General Public License as published by
@@ -19,332 +19,11 @@
#ifdef HAVE_DNSSEC #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_UNDEF -100
#define SERIAL_EQ 0 #define SERIAL_EQ 0
#define SERIAL_LT -1 #define SERIAL_LT -1
#define SERIAL_GT 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. /* Convert from presentation format to wire format, in place.
Also map UC -> LC. Also map UC -> LC.
Note that using extract_name to get presentation format 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) static int count_labels(char *name)
{ {
int i; int i;
char *p;
if (*name == 0) if (*name == 0)
return 0; return 0;
for (i = 0; *name; name++) for (p = name, i = 0; *p; p++)
if (*name == '.') if (*p == '.')
i++; i++;
return i+1; /* Don't count empty first label. */
return *name == '.' ? i : i+1;
} }
/* Implement RFC1982 wrapped compare for 32-bit numbers */ /* Implement RFC1982 wrapped compare for 32-bit numbers */
@@ -598,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. 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, static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
unsigned char **rrset, char *buff1, char *buff2) unsigned char **rrset, char *buff1, char *buff2)
{ {
int swap, quit, i; int swap, quit, i, j;
do do
{ {
@@ -663,11 +344,21 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
rrset[i] = tmp; rrset[i] = tmp;
swap = quit = 1; 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) else if (rc < 0)
quit = 1; quit = 1;
} }
} }
} while (swap); } while (swap);
return rrsetidx;
} }
static unsigned char **rrset = NULL, **sigs = NULL; static unsigned char **rrset = NULL, **sigs = NULL;
@@ -812,7 +503,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
/* Sort RRset records into canonical order. /* Sort RRset records into canonical order.
Note that at this point keyname and daemon->workspacename buffs are Note that at this point keyname and daemon->workspacename buffs are
unused, and used as workspace by the sort. */ 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 */ /* Now try all the sigs to try and find one which validates */
for (j = 0; j <sigidx; j++) for (j = 0; j <sigidx; j++)
@@ -866,6 +557,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
u16 len, *dp; u16 len, *dp;
p = rrset[i]; p = rrset[i];
if (!extract_name(header, plen, &p, name, 1, 10)) if (!extract_name(header, plen, &p, name, 1, 10))
return STAT_BOGUS; return STAT_BOGUS;
@@ -1120,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.keytag = keytag;
a.addr.log.algo = algo; 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"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
else else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
@@ -1181,11 +873,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
rc = STAT_BOGUS; rc = STAT_BOGUS;
else else
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons); 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) if (rc == STAT_INSECURE)
rc = STAT_BOGUS; {
my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
rc = STAT_BOGUS;
}
p = (unsigned char *)(header+1); p = (unsigned char *)(header+1);
extract_name(header, plen, &p, name, 1, 4); extract_name(header, plen, &p, name, 1, 4);
p += 4; /* qtype, qclass */ p += 4; /* qtype, qclass */
@@ -1248,7 +942,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
a.addr.log.keytag = keytag; a.addr.log.keytag = keytag;
a.addr.log.algo = algo; a.addr.log.algo = algo;
a.addr.log.digest = digest; 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"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
else else
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
@@ -1405,8 +1099,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, static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
char *workspace1, char *workspace2, char *name, int type, int *nons) char *workspace1_in, char *workspace2, char *name, int type, int *nons)
{ {
int i, rc, rdlen; int i, rc, rdlen;
unsigned char *p, *psave; unsigned char *p, *psave;
@@ -1419,6 +1113,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
/* Find NSEC record that proves name doesn't exist */ /* Find NSEC record that proves name doesn't exist */
for (i = 0; i < nsec_count; i++) for (i = 0; i < nsec_count; i++)
{ {
char *workspace1 = workspace1_in;
int sig_labels, name_labels;
p = nsecs[i]; p = nsecs[i];
if (!extract_name(header, plen, &p, workspace1, 1, 10)) if (!extract_name(header, plen, &p, workspace1, 1, 10))
return 0; return 0;
@@ -1427,7 +1124,27 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
psave = p; psave = p;
if (!extract_name(header, plen, &p, workspace2, 1, 10)) if (!extract_name(header, plen, &p, workspace2, 1, 10))
return 0; 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); rc = hostname_cmp(workspace1, name);
if (rc == 0) if (rc == 0)
@@ -1453,8 +1170,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
return 0; return 0;
/* If the SOA bit is set for a DS record, then we have the /* If the SOA bit is set for a DS record, then we have the
DS from the wrong side of the delegation. */ DS from the wrong side of the delegation. For the root DS,
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) this is expected. */
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
return 0; return 0;
} }
@@ -1559,7 +1277,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, 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; int i, hash_len, salt_len, base32_len, rdlen, flags;
unsigned char *p, *psave; unsigned char *p, *psave;
@@ -1614,8 +1332,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
return 0; return 0;
/* If the SOA bit is set for a DS record, then we have the /* If the SOA bit is set for a DS record, then we have the
DS from the wrong side of the delegation. */ DS from the wrong side of the delegation. For the root DS,
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0) this is expected. */
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
return 0; return 0;
} }
@@ -1756,7 +1475,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) if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
return 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; return 1;
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
@@ -1801,7 +1520,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) if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
return 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; return 0;
/* Finally, check that there's no seat of wildcard synthesis */ /* Finally, check that there's no seat of wildcard synthesis */
@@ -1816,7 +1535,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) if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
return 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; return 0;
} }
@@ -1825,24 +1544,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 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 unsigned char **nsecset = NULL, **rrsig_labels = NULL;
static int nsecset_sz = 0; static int nsecset_sz = 0, rrsig_labels_sz = 0;
int type_found = 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; int type, class, rdlen, i, nsecs_found;
/* Move to NS section */ /* Move to NS section */
if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen))) if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
return 0; return 0;
auth_start = p;
for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--) for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
{ {
unsigned char *pstart = p; unsigned char *pstart = p;
if (!(p = skip_name(p, header, plen, 10))) if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
return 0; return 0;
GETSHORT(type, p); GETSHORT(type, p);
GETSHORT(class, p); GETSHORT(class, p);
p += 4; /* TTL */ p += 4; /* TTL */
@@ -1859,7 +1580,69 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found)) if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
return 0; 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)) if (!ADD_RDLEN(header, p, plen, rdlen))
@@ -1867,7 +1650,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
} }
if (type_found == T_NSEC) 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) else if (type_found == T_NSEC3)
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons); return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
else else
@@ -1935,8 +1718,8 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
do do
{ {
if (crecp->uid == (unsigned int)class && if (crecp->uid == (unsigned int)class &&
hash_find(ds_digest_name(crecp->addr.ds.digest)) && ds_digest_name(crecp->addr.ds.digest) &&
verify_func(crecp->addr.ds.algo)) algo_digest_name(crecp->addr.ds.algo))
break; break;
} }
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS))); while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
@@ -1965,7 +1748,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_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_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_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 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 *class, int check_unsigned, int *neganswer, int *nons)
@@ -1974,9 +1760,25 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
static int target_sz = 0; static int target_sz = 0;
unsigned char *ans_start, *p1, *p2; 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 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) if (neganswer)
*neganswer = 0; *neganswer = 0;
@@ -2033,7 +1835,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++) 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 */ return STAT_BOGUS; /* bad packet */
GETSHORT(type1, p1); GETSHORT(type1, p1);
@@ -2042,140 +1847,159 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
GETSHORT(rdlen1, p1); GETSHORT(rdlen1, p1);
/* Don't try and validate RRSIGs! */ /* 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 */ if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
for (p2 = ans_start, j = 0; j < i; j++) return STAT_BOGUS; /* bad packet */
{
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;
}
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 */ /* 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; if (check_unsigned)
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) rc = zone_status(name, class1, keyname, now);
{ if (rc == STAT_SECURE)
rc = zone_status(name, class1, keyname, now); rc = STAT_BOGUS;
if (rc == STAT_SECURE) if (class)
rc = STAT_BOGUS; *class = class1; /* Class for NEED_DS or NEED_KEY */
if (class)
*class = class1; /* Class for NEED_DS or NEED_KEY */
}
else
rc = STAT_INSECURE;
return rc;
} }
else
rc = STAT_INSECURE;
if (rc != STAT_INSECURE)
return rc;
}
else
{
/* explore_rrset() gives us key name from sigs in keyname. /* explore_rrset() gives us key name from sigs in keyname.
Can't overwrite name here. */ Can't overwrite name here. */
strcpy(daemon->workspacename, keyname); strcpy(daemon->workspacename, keyname);
rc = zone_status(daemon->workspacename, class1, keyname, now); rc = zone_status(daemon->workspacename, class1, keyname, now);
if (rc != STAT_SECURE)
{
/* 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 (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
{ {
if (class) if (class)
*class = class1; /* Class for DS or DNSKEY */ *class = class1; /* Class for NEED_DS or NEED_KEY */
return rc; 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 */ /* 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 /* Note if we've validated either the answer to the question
or the target of a CNAME. Any not noted will need NSEC or or the target of a CNAME. Any not noted will need NSEC or
to be in unsigned space. */ to be in unsigned space. */
for (j = 0; j <targetidx; j++) for (j = 0; j <targetidx; j++)
if ((p2 = targets[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 */ 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; targets[j] = NULL;
} }
/* An attacker replay a wildcard answer with a different /* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that hasn't happened, the answer must prove that
the genuine record doesn't exist. Check that here. the genuine record doesn't exist. Check that here.
Note that we may not yet have validated the NSEC/NSEC3 RRsets. Note that we may not yet have validated the NSEC/NSEC3 RRsets.
That's not a problem since if the RRsets later fail That's not a problem since if the RRsets later fail
we'll return BOGUS then. */ we'll return BOGUS then. */
if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL)) if (rc == STAT_SECURE_WILDCARD &&
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
return STAT_BOGUS; return STAT_BOGUS;
rc = STAT_SECURE;
} }
} }
} }
if (!ADD_RDLEN(header, p1, plen, rdlen1)) if (rc == STAT_INSECURE)
return STAT_BOGUS; secure = STAT_INSECURE;
} }
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */ /* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
for (j = 0; j <targetidx; j++) if (secure == STAT_SECURE)
if ((p2 = targets[j])) for (j = 0; j <targetidx; j++)
{ if ((p2 = targets[j]))
if (neganswer) {
*neganswer = 1; if (neganswer)
*neganswer = 1;
if (!extract_name(header, plen, &p2, name, 1, 10))
return STAT_BOGUS; /* bad packet */ if (!extract_name(header, plen, &p2, name, 1, 10))
return STAT_BOGUS; /* bad packet */
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
/* For anything other than a DS record, this situation is OK if either
the answer is in an unsigned zone, or there's a NSEC records. */ /* For anything other than a DS record, this situation is OK if either
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons)) the answer is in an unsigned zone, or there's a NSEC records. */
{ if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
/* Empty DS without NSECS */ {
if (qtype == T_DS) /* Empty DS without NSECS */
return STAT_BOGUS; if (qtype == T_DS)
return STAT_BOGUS;
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
{ if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
if (class) {
*class = qclass; /* Class for NEED_DS or NEED_KEY */ if (class)
return rc; *class = qclass; /* Class for NEED_DS or NEED_KEY */
} return rc;
}
return STAT_BOGUS; /* signed zone, no NSECs */
} return STAT_BOGUS; /* signed zone, no NSECs */
} }
}
return STAT_SECURE; return secure;
} }
@@ -2230,7 +2054,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
p = (unsigned char *)(header+1); p = (unsigned char *)(header+1);
p = do_rfc1035_name(p, name); p = do_rfc1035_name(p, name, NULL);
*p++ = 0; *p++ = 0;
PUTSHORT(type, p); PUTSHORT(type, p);
PUTSHORT(class, p); PUTSHORT(class, p);
+147 -80
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 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 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) if (pref && *pref != 0)
continue; /* prefix match fail */ continue; /* prefix match fail */
/* NB, must not alter name if we return zero */ if (c->indexed)
for (p = tail; *p; p++)
{ {
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; continue;
#ifdef HAVE_IPV6 *p = 0;
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue; 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 #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 else
#endif
{ {
/* swap . or : for - */ /* NB, must not alter name if we return zero */
for (p = tail; *p; p++) for (p = tail; *p; p++)
if (*p == '-') {
{ char c = *p;
if (prot == AF_INET)
*p = '.'; if ((c >='0' && c <= '9') || c == '-')
continue;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
*p = ':'; continue;
#endif #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 */ /* restore name */
for (p = tail; *p; p++) for (p = tail; *p; p++)
if (*p == '.' || *p == ':') if (*p == '.' || *p == ':')
*p = '-'; *p = '-';
*p = '.'; *p = '.';
if (found) if (found)
return 1; return 1;
} }
@@ -149,14 +199,22 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
char *p; char *p;
*name = 0; *name = 0;
if (c->prefix) if (c->indexed)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN); {
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, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME); strncat(name, c->domain, MAXDNAME);
@@ -169,23 +227,32 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
char *p; char *p;
*name = 0; *name = 0;
if (c->prefix) if (c->indexed)
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 == ':')
{ {
*name = '0'; u64 index = addr6part(&addr->addr.addr6) - addr6part(&c->start6);
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN); 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.... */ /* IPv6 presentation address can start with ":", but valid domain names
for (p = name; *p; p++) cannot start with "-" so prepend a zero in that case. */
if (*p == ':' || *p == '.') if (!c->prefix && *name == ':')
*p = '-'; {
*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, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME); strncat(name, c->domain, MAXDNAME);
+211
View File
@@ -0,0 +1,211 @@
/* 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_DUMPFILE
static u32 packet_count;
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
struct pcap_hdr_s {
u32 magic_number; /* magic number */
u16 version_major; /* major version number */
u16 version_minor; /* minor version number */
u32 thiszone; /* GMT to local correction */
u32 sigfigs; /* accuracy of timestamps */
u32 snaplen; /* max length of captured packets, in octets */
u32 network; /* data link type */
};
struct pcaprec_hdr_s {
u32 ts_sec; /* timestamp seconds */
u32 ts_usec; /* timestamp microseconds */
u32 incl_len; /* number of octets of packet saved in file */
u32 orig_len; /* actual length of packet */
};
void dump_init(void)
{
struct stat buf;
struct pcap_hdr_s header;
struct pcaprec_hdr_s pcap_header;
packet_count = 0;
if (stat(daemon->dump_file, &buf) == -1)
{
/* doesn't exist, create and add header */
header.magic_number = 0xa1b2c3d4;
header.version_major = 2;
header.version_minor = 4;
header.thiszone = 0;
header.sigfigs = 0;
header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
if (errno != ENOENT ||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
}
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
else if (header.magic_number != 0xa1b2c3d4)
die(_("bad header in %s"), daemon->dump_file, EC_FILE);
else
{
/* count existing records */
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
{
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
packet_count++;
}
}
}
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
{
struct ip ip;
#ifdef HAVE_IPV6
struct ip6_hdr ip6;
int family;
#endif
struct udphdr {
u16 uh_sport; /* source port */
u16 uh_dport; /* destination port */
u16 uh_ulen; /* udp length */
u16 uh_sum; /* udp checksum */
} udp;
struct pcaprec_hdr_s pcap_header;
struct timeval time;
u32 i, sum;
void *iphdr;
size_t ipsz;
int rc;
if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask))
return;
/* So wireshark can Id the packet. */
udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
#ifdef HAVE_IPV6
if (src)
family = src->sa.sa_family;
else
family = dst->sa.sa_family;
if (family == AF_INET6)
{
iphdr = &ip6;
ipsz = sizeof(ip6);
memset(&ip6, 0, sizeof(ip6));
ip6.ip6_vfc = 6 << 4;
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
ip6.ip6_nxt = IPPROTO_UDP;
ip6.ip6_hops = 64;
if (src)
{
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
udp.uh_sport = src->in6.sin6_port;
}
if (dst)
{
memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
udp.uh_dport = dst->in6.sin6_port;
}
/* start UDP checksum */
for (sum = 0, i = 0; i < IN6ADDRSZ; i++)
sum += ((u16 *)&ip6.ip6_src)[i];
}
else
#endif
{
iphdr = &ip;
ipsz = sizeof(ip);
memset(&ip, 0, sizeof(ip));
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) / 4;
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
ip.ip_ttl = IPDEFTTL;
ip.ip_p = IPPROTO_UDP;
if (src)
{
ip.ip_src = src->in.sin_addr;
udp.uh_sport = src->in.sin_port;
}
if (dst)
{
ip.ip_dst = dst->in.sin_addr;
udp.uh_dport = dst->in.sin_port;
}
ip.ip_sum = 0;
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
sum += ((u16 *)&ip)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
/* start UDP checksum */
sum = ip.ip_src.s_addr & 0xffff;
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
sum += ip.ip_dst.s_addr & 0xffff;
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
}
if (len & 1)
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
udp.uh_sum = 0;
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
sum += htons(IPPROTO_UDP);
sum += htons(sizeof(struct udphdr) + len);
for (i = 0; i < sizeof(struct udphdr)/2; i++)
sum += ((u16 *)&udp)[i];
for (i = 0; i < (len + 1) / 2; i++)
sum += ((u16 *)packet)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
rc = gettimeofday(&time, NULL);
pcap_header.ts_sec = time.tv_sec;
pcap_header.ts_usec = time.tv_usec;
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
if (rc == -1 ||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
!read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
!read_write(daemon->dumpfd, (void *)packet, len, 0))
my_syslog(LOG_ERR, _("failed to write packet dump"));
else
my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
}
#endif
+24 -4
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 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 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); GETSHORT(len, p);
/* malformed option, delete the whole OPT RR and start again. */ /* malformed option, delete the whole OPT RR and start again. */
if (i + len > rdlen) if (i + 4 + len > rdlen)
{ {
rdlen = 0; rdlen = 0;
is_last = 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. */ /* delete option if we're to replace it. */
p -= 4; p -= 4;
rdlen -= len + 4; rdlen -= len + 4;
memcpy(p, p+len+4, rdlen - i); memmove(p, p+len+4, rdlen - i);
PUTSHORT(rdlen, lenp); PUTSHORT(rdlen, lenp);
lenp -= 2; lenp -= 2;
} }
@@ -192,7 +192,15 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
!(p = skip_section(p, !(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen))) header, plen)))
{
free(buff);
return plen; return plen;
}
if (p + 11 > limit)
{
free(buff);
return plen; /* Too big */
}
*p++ = 0; /* empty name */ *p++ = 0; /* empty name */
PUTSHORT(T_OPT, p); PUTSHORT(T_OPT, p);
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */ 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 */ /* Copy back any options */
if (buff) if (buff)
{ {
if (p + rdlen > limit)
{
free(buff);
return plen; /* Too big */
}
memcpy(p, buff, rdlen); memcpy(p, buff, rdlen);
free(buff); free(buff);
p += rdlen; 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))) 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 */ /* Add new option */
if (optno != 0 && replace != 2) if (optno != 0 && replace != 2)
{ {
if (p + 4 > limit)
return plen; /* Too big */
PUTSHORT(optno, p); PUTSHORT(optno, p);
PUTSHORT(optlen, p); PUTSHORT(optlen, p);
if (p + optlen > limit)
return plen; /* Too big */
memcpy(p, opt, optlen); memcpy(p, opt, optlen);
p += optlen; p += optlen;
PUTSHORT(p - datap, lenp); PUTSHORT(p - datap, lenp);
+256 -97
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 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 it under the terms of the GNU General Public License as published by
@@ -118,6 +118,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
unsigned int matchlen = 0; unsigned int matchlen = 0;
struct server *serv; struct server *serv;
unsigned int flags = 0; unsigned int flags = 0;
static struct all_addr zero;
for (serv = daemon->servers; serv; serv=serv->next) for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC)) if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
@@ -129,9 +130,16 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
*type = SERV_FOR_NODOTS; *type = SERV_FOR_NODOTS;
if (serv->flags & SERV_NO_ADDR) if (serv->flags & SERV_NO_ADDR)
flags = F_NXDOMAIN; flags = F_NXDOMAIN;
else if (serv->flags & SERV_LITERAL_ADDRESS) else if (serv->flags & SERV_LITERAL_ADDRESS)
{ {
if (sflag & qtype) /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
{
memset(&zero, 0, sizeof(zero));
flags = qtype;
*addrpp = &zero;
}
else if (sflag & qtype)
{ {
flags = sflag; flags = sflag;
if (serv->addr.sa.sa_family == AF_INET) if (serv->addr.sa.sa_family == AF_INET)
@@ -184,7 +192,14 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
flags = F_NXDOMAIN; flags = F_NXDOMAIN;
else if (serv->flags & SERV_LITERAL_ADDRESS) else if (serv->flags & SERV_LITERAL_ADDRESS)
{ {
if (sflag & qtype) /* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
{
memset(&zero, 0, sizeof(zero));
flags = qtype;
*addrpp = &zero;
}
else if (sflag & qtype)
{ {
flags = sflag; flags = sflag;
if (serv->addr.sa.sa_family == AF_INET) if (serv->addr.sa.sa_family == AF_INET)
@@ -214,12 +229,18 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
if (flags) if (flags)
{ {
int logflags = 0; if (flags == F_NXDOMAIN || flags == F_NOERR)
log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
if (flags == F_NXDOMAIN || flags == F_NOERR) else
logflags = F_NEG | qtype; {
/* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL); if (flags & F_IPV4)
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
#ifdef HAVE_IPV6
if (flags & F_IPV6)
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
#endif
}
} }
else if ((*type) & SERV_USE_RESOLV) else if ((*type) & SERV_USE_RESOLV)
{ {
@@ -246,9 +267,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int crc = questions_crc(header, plen, daemon->namebuff); unsigned int crc = questions_crc(header, plen, daemon->namebuff);
void *hash = &crc; void *hash = &crc;
#endif #endif
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL); unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
(void)do_bit; (void)do_bit;
/* may be no servers available. */ /* may be no servers available. */
if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash)))) if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
@@ -272,14 +293,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (forward->blocking_query) while (forward->blocking_query)
forward = forward->blocking_query; forward = forward->blocking_query;
forward->flags |= FREC_TEST_PKTSZ;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header); blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len; plen = forward->stash_len;
forward->flags |= FREC_TEST_PKTSZ;
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign) if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
PUTSHORT(SAFE_PKTSZ, pheader); PUTSHORT(SAFE_PKTSZ, pheader);
if (forward->sentto->addr.sa.sa_family == AF_INET) 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"); log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@@ -299,9 +319,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
fd = forward->rfd4->fd; fd = forward->rfd4->fd;
} }
while (retry_send( sendto(fd, (char *)header, plen, 0, while (retry_send(sendto(fd, (char *)header, plen, 0,
&forward->sentto->addr.sa, &forward->sentto->addr.sa,
sa_len(&forward->sentto->addr)))); sa_len(&forward->sentto->addr))));
return 1; return 1;
} }
@@ -400,31 +420,21 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct server *firstsentto = start; struct server *firstsentto = start;
int subnet, forwarded = 0; int subnet, forwarded = 0;
size_t edns0_len; size_t edns0_len;
unsigned char *pheader;
/* If a query is retried, use the log_id for the retry when logging the answer. */ /* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id; 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) if (subnet)
{ forward->flags |= FREC_HAS_SUBNET;
plen = edns0_len;
forward->flags |= FREC_ADDED_PHEADER;
if (subnet)
forward->flags |= FREC_HAS_SUBNET;
}
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec) if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
{ {
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ); plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
if (new != plen)
forward->flags |= FREC_ADDED_PHEADER;
plen = new;
/* For debugging, set Checking Disabled, otherwise, have the upstream check too, /* For debugging, set Checking Disabled, otherwise, have the upstream check too,
this allows it to select auth servers when one is returning bad data. */ this allows it to select auth servers when one is returning bad data. */
if (option_bool(OPT_DNSSEC_DEBUG)) if (option_bool(OPT_DNSSEC_DEBUG))
@@ -433,9 +443,20 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
} }
#endif #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, &pheader, NULL, NULL))
if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11) {
forward->flags |= FREC_HAS_EXTRADATA; /* 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) while (1)
{ {
@@ -507,6 +528,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (errno == 0) if (errno == 0)
{ {
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
#endif
/* Keep info in case we want to re-send this packet */ /* Keep info in case we want to re-send this packet */
daemon->srv_save = start; daemon->srv_save = start;
daemon->packet_len = plen; daemon->packet_len = plen;
@@ -549,6 +574,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (udpfd != -1) if (udpfd != -1)
{ {
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl); plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
if (oph)
plen = add_pseudoheader(header, plen, ((unsigned char *) header) + PACKETSZ, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface); send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
} }
@@ -562,8 +589,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
unsigned char *pheader, *sizep; unsigned char *pheader, *sizep;
char **sets = 0; char **sets = 0;
int munged = 0, is_sign; int munged = 0, is_sign;
unsigned int rcode = RCODE(header);
size_t plen; size_t plen;
(void)ad_reqd; (void)ad_reqd;
(void)do_bit; (void)do_bit;
(void)bogusanswer; (void)bogusanswer;
@@ -592,6 +620,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL))) if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
{ {
/* Get extended RCODE. */
rcode |= sizep[2] << 4;
if (check_subnet && !check_source(header, plen, pheader, query_source)) if (check_subnet && !check_source(header, plen, pheader, query_source))
{ {
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch")); my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
@@ -640,11 +671,20 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY)) if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
header->hb4 &= ~HB4_AD; header->hb4 &= ~HB4_AD;
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN)) if (OPCODE(header) != QUERY)
return resize_packet(header, n, pheader, plen); return resize_packet(header, n, pheader, plen);
if (rcode != NOERROR && rcode != NXDOMAIN)
{
struct all_addr a;
a.addr.rcode.rcode = rcode;
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
return resize_packet(header, n, pheader, plen);
}
/* Complain loudly if the upstream server is non-recursive. */ /* Complain loudly if the upstream server is non-recursive. */
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
server && !(server->flags & SERV_WARNED_RECURSIVE)) server && !(server->flags & SERV_WARNED_RECURSIVE))
{ {
prettyprint_addr(&server->addr, daemon->namebuff); prettyprint_addr(&server->addr, daemon->namebuff);
@@ -653,7 +693,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
server->flags |= SERV_WARNED_RECURSIVE; server->flags |= SERV_WARNED_RECURSIVE;
} }
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN && if (daemon->bogus_addr && rcode != NXDOMAIN &&
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now)) check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
{ {
munged = 1; munged = 1;
@@ -665,7 +705,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
{ {
int doctored = 0; int doctored = 0;
if (RCODE(header) == NXDOMAIN && if (rcode == NXDOMAIN &&
extract_request(header, n, daemon->namebuff, NULL) && extract_request(header, n, daemon->namebuff, NULL) &&
check_for_local_domain(daemon->namebuff, now)) check_for_local_domain(daemon->namebuff, now))
{ {
@@ -755,7 +795,7 @@ void reply_query(int fd, int family, time_t now)
#endif #endif
header = (struct dns_header *)daemon->packet; header = (struct dns_header *)daemon->packet;
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR)) if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
return; return;
@@ -767,7 +807,11 @@ void reply_query(int fd, int family, time_t now)
if (!server) if (!server)
return; 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 #ifdef HAVE_DNSSEC
hash = hash_questions(header, n, daemon->namebuff); hash = hash_questions(header, n, daemon->namebuff);
#else #else
@@ -778,6 +822,11 @@ void reply_query(int fd, int family, time_t now)
if (!(forward = lookup_frec(ntohs(header->id), hash))) if (!(forward = lookup_frec(ntohs(header->id), hash)))
return; return;
#ifdef HAVE_DUMPFILE
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
(void *)header, n, &serveraddr, NULL);
#endif
/* log_query gets called indirectly all over the place, so /* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */ pass these in global variables - sorry. */
daemon->log_display_id = forward->log_id; daemon->log_display_id = forward->log_id;
@@ -789,8 +838,7 @@ void reply_query(int fd, int family, time_t now)
/* Note: if we send extra options in the EDNS0 header, we can't recreate /* Note: if we send extra options in the EDNS0 header, we can't recreate
the query from the reply. */ the query from the reply. */
if (RCODE(header) == REFUSED && if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
!option_bool(OPT_ORDER) &&
forward->forwardall == 0 && forward->forwardall == 0 &&
!(forward->flags & FREC_HAS_EXTRADATA)) !(forward->flags & FREC_HAS_EXTRADATA))
/* for broken servers, attempt to send to another one. */ /* for broken servers, attempt to send to another one. */
@@ -798,10 +846,84 @@ void reply_query(int fd, int family, time_t now)
unsigned char *pheader; unsigned char *pheader;
size_t plen; size_t plen;
int is_sign; int is_sign;
#ifdef HAVE_DNSSEC
/* For DNSSEC originated queries, just retry the query to the same server. */
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
{
struct server *start;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
forward->forwardall = 2; /* only retry once */
start = forward->sentto;
/* for non-domain specific servers, see if we can find another to try. */
if ((forward->sentto->flags & SERV_TYPE) == 0)
while (1)
{
if (!(start = start->next))
start = daemon->servers;
if (start == forward->sentto)
break;
if ((start->flags & SERV_TYPE) == 0 &&
(start->flags & SERV_DO_DNSSEC))
break;
}
if (start->sfd)
fd = start->sfd->fd;
else
{
#ifdef HAVE_IPV6
if (start->addr.sa.sa_family == AF_INET6)
{
/* may have changed family */
if (!forward->rfd6)
forward->rfd6 = allocate_rfd(AF_INET6);
fd = forward->rfd6->fd;
}
else
#endif
{
/* may have changed family */
if (!forward->rfd4)
forward->rfd4 = allocate_rfd(AF_INET);
fd = forward->rfd4->fd;
}
}
while (retry_send(sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
sa_len(&start->addr))));
if (start->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&start->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6
else
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&start->addr.in6.sin6_addr, "dnssec");
#endif
return;
}
#endif
/* 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 */ /* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL); pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
if (!is_sign) if (!is_sign && server)
{ {
header->ancount = htons(0); header->ancount = htons(0);
header->nscount = htons(0); header->nscount = htons(0);
@@ -845,12 +967,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. /* 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. */ 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)) ((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 /* 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 we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when had replies from all to avoid filling the forwarding table when
@@ -859,7 +987,7 @@ void reply_query(int fd, int family, time_t now)
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL)) (RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
{ {
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0; int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
if (option_bool(OPT_NO_REBIND)) if (option_bool(OPT_NO_REBIND))
check_rebind = !(forward->flags & FREC_NOREBIND); check_rebind = !(forward->flags & FREC_NOREBIND);
@@ -899,7 +1027,13 @@ void reply_query(int fd, int family, time_t now)
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
else else
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, 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_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL);
#ifdef HAVE_DUMPFILE
if (status == STAT_BOGUS)
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)n, &serveraddr, NULL);
#endif
} }
/* Can't validate, as we're missing key data. Put this /* Can't validate, as we're missing key data. Put this
@@ -942,7 +1076,7 @@ void reply_query(int fd, int family, time_t now)
while (1) while (1)
{ {
if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) && if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) && ((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP))) !(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{ {
new_server = start; new_server = start;
@@ -968,7 +1102,8 @@ void reply_query(int fd, int family, time_t now)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
new->rfd6 = NULL; new->rfd6 = NULL;
#endif #endif
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY); new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
new->forwardall = 0;
new->dependent = forward; /* to find query awaiting new one. */ new->dependent = forward; /* to find query awaiting new one. */
forward->blocking_query = new; /* for garbage cleaning */ forward->blocking_query = new; /* for garbage cleaning */
@@ -1026,6 +1161,11 @@ void reply_query(int fd, int family, time_t now)
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
} }
#endif #endif
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
#endif
while (retry_send(sendto(fd, (char *)header, nn, 0, while (retry_send(sendto(fd, (char *)header, nn, 0,
&server->addr.sa, &server->addr.sa,
sa_len(&server->addr)))); sa_len(&server->addr))));
@@ -1069,7 +1209,7 @@ void reply_query(int fd, int family, time_t now)
if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL)) if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
domain = daemon->namebuff; domain = daemon->namebuff;
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result); log_query(F_SECSTAT, domain, NULL, result);
} }
if (status == STAT_SECURE) if (status == STAT_SECURE)
@@ -1080,8 +1220,8 @@ void reply_query(int fd, int family, time_t now)
bogusanswer = 1; bogusanswer = 1;
} }
} }
#endif #endif
/* restore CD bit to the value in the query */ /* restore CD bit to the value in the query */
if (forward->flags & FREC_CHECKING_DISABLED) if (forward->flags & FREC_CHECKING_DISABLED)
header->hb4 |= HB4_CD; header->hb4 |= HB4_CD;
@@ -1096,7 +1236,7 @@ void reply_query(int fd, int family, time_t now)
header->hb4 |= HB4_RA; /* recursion if available */ header->hb4 |= HB4_RA; /* recursion if available */
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size /* 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. */ 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)) if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
{ {
@@ -1107,6 +1247,11 @@ void reply_query(int fd, int family, time_t now)
nn = resize_packet(header, nn, NULL, 0); nn = resize_packet(header, nn, NULL, 0);
} }
#endif #endif
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
#endif
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn, send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
&forward->source, &forward->dest, forward->iface); &forward->source, &forward->dest, forward->iface);
} }
@@ -1189,6 +1334,10 @@ void receive_query(struct listener *listen, time_t now)
(msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_TRUNC) ||
(header->hb3 & HB3_QR)) (header->hb3 & HB3_QR))
return; 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; source_addr.sa.sa_family = listen->family;
@@ -1356,7 +1505,11 @@ void receive_query(struct listener *listen, time_t now)
pass these in global variables - sorry. */ pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id; daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &source_addr; daemon->log_source_addr = &source_addr;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
#endif
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
@@ -1409,6 +1562,8 @@ void receive_query(struct listener *listen, time_t now)
defaults to 512 */ defaults to 512 */
if (udp_size > daemon->edns_pktsz) if (udp_size > daemon->edns_pktsz)
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 #ifdef HAVE_AUTH
@@ -1420,7 +1575,7 @@ void receive_query(struct listener *listen, time_t now)
{ {
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index); (char *)header, m, &source_addr, &dst_addr, if_index);
daemon->auth_answer++; daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
} }
} }
else else
@@ -1438,13 +1593,13 @@ void receive_query(struct listener *listen, time_t now)
{ {
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index); (char *)header, m, &source_addr, &dst_addr, if_index);
daemon->local_answer++; daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
} }
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
header, (size_t)n, now, NULL, ad_reqd, do_bit)) header, (size_t)n, now, NULL, ad_reqd, do_bit))
daemon->queries_forwarded++; daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
else else
daemon->local_answer++; daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
} }
} }
@@ -1477,7 +1632,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); new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
else else
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, 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_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
NULL, NULL);
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY) if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
break; break;
@@ -1546,7 +1702,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif #endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{ {
close(server->tcpfd); close(server->tcpfd);
@@ -1689,6 +1845,10 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header)) if (size < (int)sizeof(struct dns_header))
continue; continue;
/* Clear buffer beyond request to avoid risk of
information disclosure. */
memset(payload + size, 0, 65536 - size);
query_count++; query_count++;
@@ -1774,17 +1934,30 @@ unsigned char *tcp_request(int confd, time_t now,
struct all_addr *addrp = NULL; struct all_addr *addrp = NULL;
int type = SERV_DO_DNSSEC; int type = SERV_DO_DNSSEC;
char *domain = NULL; 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) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); 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; type &= ~SERV_DO_DNSSEC;
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
@@ -1838,7 +2011,7 @@ unsigned char *tcp_request(int confd, time_t now,
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif #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)) connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{ {
close(last_server->tcpfd); close(last_server->tcpfd);
@@ -1849,24 +2022,6 @@ unsigned char *tcp_request(int confd, time_t now,
last_server->flags &= ~SERV_GOT_TCP; 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); *length = htons(size);
/* get query name again for logging - may have been overwritten */ /* get query name again for logging - may have been overwritten */
@@ -1921,7 +2076,7 @@ unsigned char *tcp_request(int confd, time_t now,
if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL)) if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
domain = daemon->namebuff; domain = daemon->namebuff;
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result); log_query(F_SECSTAT, domain, NULL, result);
if (status == STAT_BOGUS) if (status == STAT_BOGUS)
{ {
@@ -1971,7 +2126,11 @@ unsigned char *tcp_request(int confd, time_t now,
/* In case of local answer or no connections made. */ /* In case of local answer or no connections made. */
if (m == 0) if (m == 0)
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl); {
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
if (have_pseudoheader)
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
}
} }
} }
+3 -3
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 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 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/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_SCRIPT #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]; 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() */ and SIGALRM so that we can use sleep() */
sigact.sa_handler = SIG_IGN; sigact.sa_handler = SIG_IGN;
sigact.sa_flags = 0; sigact.sa_flags = 0;
sigemptyset(&sigact.sa_mask); sigemptyset(&sigact.sa_mask);
sigaction(SIGTERM, &sigact, NULL); sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGALRM, &sigact, NULL); sigaction(SIGALRM, &sigact, NULL);
sigaction(SIGINT, &sigact, NULL);
if (!option_bool(OPT_DEBUG) && uid != 0) if (!option_bool(OPT_DEBUG) && uid != 0)
{ {
+12 -10
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 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 it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
#include <sys/inotify.h> #include <sys/inotify.h>
#include <sys/param.h> /* For MAXSYMLINKS */ #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 resolv files, for any files in the directory which are close-write
or moved into the directory. 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) 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; 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 */ /* ignore emacs backups and dotfiles */
if (in->len == 0 || if (in->len == 0 || (namelen = strlen(in->name)) == 0 ||
in->name[in->len - 1] == '~' || in->name[namelen - 1] == '~' ||
(in->name[0] == '#' && in->name[in->len - 1] == '#') || (in->name[0] == '#' && in->name[namelen - 1] == '#') ||
in->name[0] == '.') in->name[0] == '.')
continue; 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) for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
if (ah->wd == in->wd) if (ah->wd == in->wd)
{ {
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+12 -5
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 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 it under the terms of the GNU General Public License as published by
@@ -87,7 +87,7 @@ static int read_leases(time_t now, FILE *leasestream)
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type))) if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{ {
lease_set_iaid(lease, strtoul(s, NULL, 10)); lease_set_iaid(lease, strtoul(s, NULL, 10));
domain = get_domain6((struct in6_addr *)lease->hwaddr); domain = get_domain6(&lease->addr6);
} }
} }
#endif #endif
@@ -229,7 +229,7 @@ void lease_update_from_configs(void)
else if ((name = host_from_dns(lease->addr))) else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */ lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
} }
static void ourprintf(int *errp, char *format, ...) static void ourprintf(int *errp, char *format, ...)
{ {
va_list ap; va_list ap;
@@ -555,7 +555,9 @@ void lease_prune(struct dhcp_lease *target, time_t now)
file_dirty = 1; file_dirty = 1;
if (lease->hostname) if (lease->hostname)
dns_dirty = 1; dns_dirty = 1;
daemon->metrics[lease->addr.s_addr ? METRIC_LEASES_PRUNED_4 : METRIC_LEASES_PRUNED_6]++;
*up = lease->next; /* unlink */ *up = lease->next; /* unlink */
/* Put on old_leases list 'till we /* Put on old_leases list 'till we
@@ -773,7 +775,10 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
{ {
struct dhcp_lease *lease = lease_allocate(); struct dhcp_lease *lease = lease_allocate();
if (lease) if (lease)
lease->addr = addr; {
lease->addr = addr;
daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
}
return lease; return lease;
} }
@@ -788,6 +793,8 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
lease->addr6 = *addrp; lease->addr6 = *addrp;
lease->flags |= lease_type; lease->flags |= lease_type;
lease->iaid = 0; lease->iaid = 0;
daemon->metrics[METRIC_LEASES_ALLOCATED_6]++;
} }
return lease; return lease;
+2 -2
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 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 it under the terms of the GNU General Public License as published by
@@ -232,7 +232,7 @@ static void log_write(void)
logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1; logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
#endif #endif
logaddr.sun_family = AF_UNIX; logaddr.sun_family = AF_UNIX;
strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path)); safe_strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
/* Got connection back? try again. */ /* Got connection back? try again. */
if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1) if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+44
View File
@@ -0,0 +1,44 @@
/* 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"
const char * metric_names[] = {
"dns_cache_inserted",
"dns_cache_live_freed",
"dns_queries_forwarded",
"dns_auth_answered",
"dns_local_answered",
"bootp",
"pxe",
"dhcp_ack",
"dhcp_decline",
"dhcp_discover",
"dhcp_inform",
"dhcp_nak",
"dhcp_offer",
"dhcp_release",
"dhcp_request",
"noanswer",
"leases_allocated_4",
"leases_pruned_4",
"leases_allocated_6",
"leases_pruned_6",
};
const char* get_metric_name(int i) {
return metric_names[i];
}
+43
View File
@@ -0,0 +1,43 @@
/* 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/>.
*/
/* If you modify this list, please keep the labels in metrics.c in sync. */
enum {
METRIC_DNS_CACHE_INSERTED,
METRIC_DNS_CACHE_LIVE_FREED,
METRIC_DNS_QUERIES_FORWARDED,
METRIC_DNS_AUTH_ANSWERED,
METRIC_DNS_LOCAL_ANSWERED,
METRIC_BOOTP,
METRIC_PXE,
METRIC_DHCPACK,
METRIC_DHCPDECLINE,
METRIC_DHCPDISCOVER,
METRIC_DHCPINFORM,
METRIC_DHCPNAK,
METRIC_DHCPOFFER,
METRIC_DHCPRELEASE,
METRIC_DHCPREQUEST,
METRIC_NOANSWER,
METRIC_LEASES_ALLOCATED_4,
METRIC_LEASES_PRUNED_4,
METRIC_LEASES_ALLOCATED_6,
METRIC_LEASES_PRUNED_6,
__METRIC_MAX,
};
const char* get_metric_name(int);
+4 -4
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 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 it under the terms of the GNU General Public License as published by
@@ -149,10 +149,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct rtgenmsg g; struct rtgenmsg g;
} req; } req;
memset(&req, 0, sizeof(req));
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK; addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_groups = 0;
addr.nl_pid = 0; /* address to kernel */
again: again:
if (family == AF_UNSPEC) if (family == AF_UNSPEC)
+48 -30
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 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 it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@ int indextoname(int fd, int index, char *name)
if (ioctl(fd, SIOCGIFNAME, &ifr) == -1) if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
return 0; return 0;
strncpy(name, ifr.ifr_name, IF_NAMESIZE); safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
return 1; return 1;
} }
@@ -82,12 +82,12 @@ int indextoname(int fd, int index, char *name)
for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++) for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
{ {
struct lifreq lifr; struct lifreq lifr;
strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE); safe_strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0) if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
return 0; return 0;
if (lifr.lifr_index == index) { if (lifr.lifr_index == index) {
strncpy(name, lifr.lifr_name, IF_NAMESIZE); safe_strncpy(name, lifr.lifr_name, IF_NAMESIZE);
return 1; return 1;
} }
} }
@@ -188,7 +188,7 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
struct ifreq ifr; struct ifreq ifr;
struct irec *iface; struct irec *iface;
strncpy(ifr.ifr_name, name, IF_NAMESIZE); safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 && if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
ifr.ifr_flags & IFF_LOOPBACK) ifr.ifr_flags & IFF_LOOPBACK)
{ {
@@ -1149,10 +1149,7 @@ int random_sock(int family)
if (fix_fd(fd)) if (fix_fd(fd))
while(tries--) while(tries--)
{ {
unsigned short port = rand16(); unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
if (family == AF_INET) 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; 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) if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
return 0; 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 defined(SO_BINDTODEVICE)
if (intname[0] != 0 && if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1) setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
@@ -1219,7 +1234,8 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
struct serverfd *sfd; struct serverfd *sfd;
unsigned int ifindex = 0; unsigned int ifindex = 0;
int errsave; int errsave;
int opt = 1;
/* when using random ports, servers which would otherwise use /* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL */ the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport && intname[0] == 0) if (!daemon->osport && intname[0] == 0)
@@ -1259,20 +1275,22 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
free(sfd); free(sfd);
return NULL; return NULL;
} }
if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd)) if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
{ {
errsave = errno; /* save error from bind. */ errsave = errno; /* save error from bind/setsockopt. */
close(sfd->fd); close(sfd->fd);
free(sfd); free(sfd);
errno = errsave; errno = errsave;
return NULL; return NULL;
} }
strcpy(sfd->interface, intname); safe_strncpy(sfd->interface, intname, sizeof(sfd->interface));
sfd->source_addr = *addr; sfd->source_addr = *addr;
sfd->next = daemon->sfds; sfd->next = daemon->sfds;
sfd->ifindex = ifindex; sfd->ifindex = ifindex;
sfd->preallocated = 0;
daemon->sfds = sfd; daemon->sfds = sfd;
return sfd; return sfd;
@@ -1283,6 +1301,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
void pre_allocate_sfds(void) void pre_allocate_sfds(void)
{ {
struct server *srv; struct server *srv;
struct serverfd *sfd;
if (daemon->query_port != 0) if (daemon->query_port != 0)
{ {
@@ -1294,7 +1313,8 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
addr.in.sin_len = sizeof(struct sockaddr_in); addr.in.sin_len = sizeof(struct sockaddr_in);
#endif #endif
allocate_sfd(&addr, ""); if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.in6.sin6_family = AF_INET6; addr.in6.sin6_family = AF_INET6;
@@ -1303,7 +1323,8 @@ void pre_allocate_sfds(void)
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6); addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif #endif
allocate_sfd(&addr, ""); if ((sfd = allocate_sfd(&addr, "")))
sfd->preallocated = 1;
#endif #endif
} }
@@ -1437,7 +1458,7 @@ void add_update_server(int flags,
serv->flags |= SERV_HAS_DOMAIN; serv->flags |= SERV_HAS_DOMAIN;
if (interface) if (interface)
strcpy(serv->interface, interface); safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr) if (addr)
serv->addr = *addr; serv->addr = *addr;
if (source_addr) if (source_addr)
@@ -1456,16 +1477,10 @@ void check_servers(void)
/* interface may be new since startup */ /* interface may be new since startup */
if (!option_bool(OPT_NOWILD)) if (!option_bool(OPT_NOWILD))
enumerate_interfaces(0); enumerate_interfaces(0);
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
sfd->used = 0;
#ifdef HAVE_DNSSEC /* don't garbage collect pre-allocated sfds. */
/* Disable DNSSEC validation when using server=/domain/.... servers for (sfd = daemon->sfds; sfd; sfd = sfd->next)
unless there's a configured trust anchor. */ sfd->used = sfd->preallocated;
for (serv = daemon->servers; serv; serv = serv->next)
serv->flags |= SERV_DO_DNSSEC;
#endif
for (count = 0, serv = daemon->servers; serv; serv = serv->next) for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{ {
@@ -1478,6 +1493,11 @@ void check_servers(void)
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) 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) if (serv->flags & SERV_HAS_DOMAIN)
{ {
struct ds_config *ds; struct ds_config *ds;
@@ -1494,8 +1514,6 @@ void check_servers(void)
if (!ds) if (!ds)
serv->flags &= ~SERV_DO_DNSSEC; serv->flags &= ~SERV_DO_DNSSEC;
} }
else if (serv->flags & SERV_FOR_NODOTS)
serv->flags &= ~SERV_DO_DNSSEC;
} }
#endif #endif
+250 -129
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 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 it under the terms of the GNU General Public License as published by
@@ -160,6 +160,12 @@ struct myoption {
#define LOPT_DHCPTTL 348 #define LOPT_DHCPTTL 348
#define LOPT_TFTP_MTU 349 #define LOPT_TFTP_MTU 349
#define LOPT_REPLY_DELAY 350 #define LOPT_REPLY_DELAY 350
#define LOPT_RAPID_COMMIT 351
#define LOPT_DUMPFILE 352
#define LOPT_DUMPMASK 353
#define LOPT_UBUS 354
#define LOPT_NAME_MATCH 355
#define LOPT_CAA 356
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -228,8 +234,10 @@ static const struct myoption opts[] =
{ "srv-host", 1, 0, 'W' }, { "srv-host", 1, 0, 'W' },
{ "localise-queries", 0, 0, 'y' }, { "localise-queries", 0, 0, 'y' },
{ "txt-record", 1, 0, 'Y' }, { "txt-record", 1, 0, 'Y' },
{ "caa-record", 1, 0 , LOPT_CAA },
{ "dns-rr", 1, 0, LOPT_RR }, { "dns-rr", 1, 0, LOPT_RR },
{ "enable-dbus", 2, 0, '1' }, { "enable-dbus", 2, 0, '1' },
{ "enable-ubus", 0, 0, LOPT_UBUS },
{ "bootp-dynamic", 2, 0, '3' }, { "bootp-dynamic", 2, 0, '3' },
{ "dhcp-mac", 1, 0, '4' }, { "dhcp-mac", 1, 0, '4' },
{ "no-ping", 0, 0, '5' }, { "no-ping", 0, 0, '5' },
@@ -268,7 +276,8 @@ static const struct myoption opts[] =
{ "stop-dns-rebind", 0, 0, LOPT_REBIND }, { "stop-dns-rebind", 0, 0, LOPT_REBIND },
{ "rebind-domain-ok", 1, 0, LOPT_NO_REBIND }, { "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
{ "all-servers", 0, 0, LOPT_NOLAST }, { "all-servers", 0, 0, LOPT_NOLAST },
{ "dhcp-match", 1, 0, LOPT_MATCH }, { "dhcp-match", 1, 0, LOPT_MATCH },
{ "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST }, { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
{ "neg-ttl", 1, 0, LOPT_NEGTTL }, { "neg-ttl", 1, 0, LOPT_NEGTTL },
{ "max-ttl", 1, 0, LOPT_MAXTTL }, { "max-ttl", 1, 0, LOPT_MAXTTL },
@@ -310,7 +319,7 @@ static const struct myoption opts[] =
{ "dnssec", 0, 0, LOPT_SEC_VALID }, { "dnssec", 0, 0, LOPT_SEC_VALID },
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR }, { "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG }, { "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK }, { "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME }, { "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP }, { "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
@@ -325,6 +334,9 @@ static const struct myoption opts[] =
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP }, { "script-arp", 0, 0, LOPT_SCRIPT_ARP },
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL }, { "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY }, { "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
{ "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
@@ -414,6 +426,7 @@ static struct {
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL }, { 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE }, { 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
{ '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL }, { '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
{ LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL }, { '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL }, { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL }, { '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
@@ -447,6 +460,7 @@ static struct {
{ LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL }, { LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL }, { LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
{ LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL }, { LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
{ LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL }, { LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL }, { LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL }, { LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
@@ -469,6 +483,7 @@ static struct {
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL }, { LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, { LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL }, { LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL }, { LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL }, { LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL }, { LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
@@ -482,7 +497,7 @@ static struct {
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL }, { LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL }, { LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL }, { LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL }, { LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL }, { LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL }, { LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
@@ -497,6 +512,9 @@ static struct {
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL }, { LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL }, { LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
{ LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL }, { LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
{ LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
@@ -792,7 +810,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (interface_opt) if (interface_opt)
{ {
#if defined(SO_BINDTODEVICE) #if defined(SO_BINDTODEVICE)
strncpy(interface, interface_opt, IF_NAMESIZE - 1); safe_strncpy(interface, interface_opt, IF_NAMESIZE);
#else #else
return _("interface binding not supported"); return _("interface binding not supported");
#endif #endif
@@ -821,7 +839,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return _("interface can only be specified once"); return _("interface can only be specified once");
source_addr->in.sin_addr.s_addr = INADDR_ANY; source_addr->in.sin_addr.s_addr = INADDR_ANY;
strncpy(interface, source, IF_NAMESIZE - 1); safe_strncpy(interface, source, IF_NAMESIZE);
#else #else
return _("interface binding not supported"); return _("interface binding not supported");
#endif #endif
@@ -856,7 +874,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return _("interface can only be specified once"); return _("interface can only be specified once");
source_addr->in6.sin6_addr = in6addr_any; source_addr->in6.sin6_addr = in6addr_any;
strncpy(interface, source, IF_NAMESIZE - 1); safe_strncpy(interface, source, IF_NAMESIZE);
#else #else
return _("interface binding not supported"); return _("interface binding not supported");
#endif #endif
@@ -882,7 +900,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
switch (msize) switch (msize)
{ {
case 32: case 32:
p += sprintf(p, "%d.", a & 0xff); p += sprintf(p, "%u.", a & 0xff);
/* fall through */ /* fall through */
case 24: case 24:
p += sprintf(p, "%d.", (a >> 8) & 0xff); p += sprintf(p, "%d.", (a >> 8) & 0xff);
@@ -1163,7 +1181,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
case 'd': case 'd':
case 'D': case 'D':
fac *= 24; fac *= 24;
/* fall though */ /* fall through */
case 'h': case 'h':
case 'H': case 'H':
fac *= 60; fac *= 60;
@@ -1415,7 +1433,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
} }
p = newp; p = newp;
end = do_rfc1035_name(p + len, dom); end = do_rfc1035_name(p + len, dom, NULL);
*end++ = 0; *end++ = 0;
len = end - p; len = end - p;
free(dom); free(dom);
@@ -1737,7 +1755,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
#endif #endif
} }
break; break;
case 'x': /* --pid-file */ case 'x': /* --pid-file */
daemon->runfile = opt_string_alloc(arg); daemon->runfile = opt_string_alloc(arg);
break; break;
@@ -1808,6 +1826,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(_("bad MX target")); ret_err(_("bad MX target"));
break; break;
case LOPT_DUMPFILE: /* --dumpfile */
daemon->dump_file = opt_string_alloc(arg);
break;
case LOPT_DUMPMASK: /* --dumpmask */
daemon->dump_mask = strtol(arg, NULL, 0);
break;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
case 'l': /* --dhcp-leasefile */ case 'l': /* --dhcp-leasefile */
daemon->lease_file = opt_string_alloc(arg); daemon->lease_file = opt_string_alloc(arg);
@@ -1875,8 +1901,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
} }
#ifdef HAVE_AUTH
case LOPT_AUTHSERV: /* --auth-server */ case LOPT_AUTHSERV: /* --auth-server */
if (!(comma = split(arg))) if (!(comma = split(arg)))
ret_err(gen_err); ret_err(gen_err);
@@ -2051,7 +2075,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
break; break;
#endif
case 's': /* --domain */ case 's': /* --domain */
case LOPT_SYNTH: /* --synth-domain */ case LOPT_SYNTH: /* --synth-domain */
@@ -2071,7 +2094,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
char *netpart; char *netpart;
new->prefix = NULL; new->prefix = NULL;
new->indexed = 0;
unhide_metas(comma); unhide_metas(comma);
if ((netpart = split_chr(comma, '/'))) if ((netpart = split_chr(comma, '/')))
{ {
@@ -2208,8 +2232,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
else else
{ {
char *star;
new->next = daemon->synth_domains; new->next = daemon->synth_domains;
daemon->synth_domains = new; daemon->synth_domains = new;
if (new->prefix &&
(star = strrchr(new->prefix, '*'))
&& *(star+1) == 0)
{
*star = 0;
new->indexed = 1;
}
} }
} }
else if (option == 's') else if (option == 's')
@@ -2393,7 +2425,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(arg, "#") == 0) if (strcmp(arg, "#") == 0)
domain = ""; domain = "";
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg))) else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
option = '?'; ret_err(gen_err);
serv = opt_malloc(sizeof(struct server)); serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server)); memset(serv, 0, sizeof(struct server));
serv->next = newlist; serv->next = newlist;
@@ -2435,11 +2467,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} }
else if (strcmp(arg, "#") == 0) else if (strcmp(arg, "#") == 0)
{ newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
if (newlist->flags & SERV_LITERAL_ADDRESS)
ret_err(gen_err);
}
else else
{ {
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags); char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
@@ -2525,7 +2553,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(arg, "#") == 0 || !*arg) if (strcmp(arg, "#") == 0 || !*arg)
domain = ""; domain = "";
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg))) else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
option = '?'; ret_err(gen_err);
ipsets->next = opt_malloc(sizeof(struct ipsets)); ipsets->next = opt_malloc(sizeof(struct ipsets));
ipsets = ipsets->next; ipsets = ipsets->next;
memset(ipsets, 0, sizeof(struct ipsets)); memset(ipsets, 0, sizeof(struct ipsets));
@@ -2540,13 +2568,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset(ipsets, 0, sizeof(struct ipsets)); memset(ipsets, 0, sizeof(struct ipsets));
ipsets->domain = ""; ipsets->domain = "";
} }
if (!arg || !*arg) if (!arg || !*arg)
{ ret_err(gen_err);
option = '?';
break; for (size = 2, end = arg; *end; ++end)
}
size = 2;
for (end = arg; *end; ++end)
if (*end == ',') if (*end == ',')
++size; ++size;
@@ -2579,8 +2605,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (size < 0) if (size < 0)
size = 0; size = 0;
else if (size > 10000)
size = 10000;
daemon->cachesize = size; daemon->cachesize = size;
} }
@@ -2733,15 +2757,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_BRIDGE: /* --bridge-interface */ 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 ) if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
ret_err(_("bad bridge-interface")); 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 { do {
arg = comma; arg = comma;
comma = split(arg); comma = split(arg);
@@ -2767,12 +2800,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
memset (new, 0, sizeof(*new)); memset (new, 0, sizeof(*new));
new->lease_time = DEFLEASE; new->lease_time = DEFLEASE;
if (!arg)
{
option = '?';
break;
}
while(1) while(1)
{ {
for (cp = arg; *cp; cp++) for (cp = arg; *cp; cp++)
@@ -2961,7 +2988,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'd': case 'd':
case 'D': case 'D':
fac *= 24; fac *= 24;
/* fall though */ /* fall through */
case 'h': case 'h':
case 'H': case 'H':
fac *= 60; fac *= 60;
@@ -3261,7 +3288,33 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
option == LOPT_FORCE ? DHOPT_FORCE : option == LOPT_FORCE ? DHOPT_FORCE :
(option == LOPT_MATCH ? DHOPT_MATCH : (option == LOPT_MATCH ? DHOPT_MATCH :
(option == LOPT_OPTS ? DHOPT_BANK : 0))); (option == LOPT_OPTS ? DHOPT_BANK : 0)));
case LOPT_NAME_MATCH: /* --dhcp-name-match */
{
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
ssize_t len;
if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
ret_err(gen_err);
new->wildcard = 0;
new->netid = id;
id->net = opt_string_alloc(set_prefix(arg));
if (comma[len-1] == '*')
{
comma[len-1] = 0;
new->wildcard = 1;
}
new->name = opt_string_alloc(comma);
new->next = daemon->dhcp_name_match;
daemon->dhcp_name_match = new;
break;
}
case 'M': /* --dhcp-boot */ case 'M': /* --dhcp-boot */
{ {
struct dhcp_netid *id = NULL; struct dhcp_netid *id = NULL;
@@ -3774,11 +3827,9 @@ err:
if ((k < 2) || if ((k < 2) ||
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) || (!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
(!(inet_pton(AF_INET, a[1], &new->out) > 0))) (!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
option = '?'; (k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
ret_err(_("missing address in alias"));
if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
option = '?';
if (dash && if (dash &&
(!(inet_pton(AF_INET, dash, &new->end) > 0) || (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
@@ -3847,6 +3898,7 @@ err:
while (arg != last) while (arg != last)
{ {
int arglen = strlen(arg);
alias = canonicalise_opt(arg); alias = canonicalise_opt(arg);
if (!alias || !target) if (!alias || !target)
@@ -3862,7 +3914,7 @@ err:
new->target = target; new->target = target;
new->ttl = ttl; new->ttl = ttl;
arg += strlen(arg)+1; for (arg += arglen+1; *arg && isspace(*arg); arg++);
} }
break; break;
@@ -3949,7 +4001,7 @@ err:
if (data) if (data)
{ {
new->txt=opt_malloc(len); new->txt = opt_malloc(len);
new->len = len; new->len = len;
memcpy(new->txt, data, len); memcpy(new->txt, data, len);
} }
@@ -3957,6 +4009,37 @@ err:
break; break;
} }
case LOPT_CAA: /* --caa-record */
{
struct txt_record *new;
char *tag, *value;
int flags;
comma = split(arg);
tag = split(comma);
value = split(tag);
new = opt_malloc(sizeof(struct txt_record));
new->next = daemon->rr;
daemon->rr = new;
if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
ret_err(_("bad CAA record"));
unhide_metas(tag);
unhide_metas(value);
new->len = strlen(tag) + strlen(value) + 2;
new->txt = opt_malloc(new->len);
new->txt[0] = flags;
new->txt[1] = strlen(tag);
memcpy(&new->txt[2], tag, strlen(tag));
memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
new->class = T_CAA;
break;
}
case 'Y': /* --txt-record */ case 'Y': /* --txt-record */
{ {
struct txt_record *new; struct txt_record *new;
@@ -4115,11 +4198,21 @@ err:
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
case LOPT_DNSSEC_STAMP: case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
daemon->timestamp_file = opt_string_alloc(arg); daemon->timestamp_file = opt_string_alloc(arg);
break; break;
case LOPT_TRUST_ANCHOR: case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
if (arg)
{
if (strcmp(arg, "no") == 0)
set_option_bool(OPT_DNSSEC_IGN_NS);
else
ret_err(_("bad value for dnssec-check-unsigned"));
}
break;
case LOPT_TRUST_ANCHOR: /* --trust-anchor */
{ {
struct ds_config *new = opt_malloc(sizeof(struct ds_config)); struct ds_config *new = opt_malloc(sizeof(struct ds_config));
char *cp, *cp1, *keyhex, *digest, *algo = NULL; char *cp, *cp1, *keyhex, *digest, *algo = NULL;
@@ -4304,7 +4397,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
if (errmess) if (errmess)
strcpy(daemon->namebuff, errmess); strcpy(daemon->namebuff, errmess);
if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV)) if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
{ {
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file); sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
if (hard_opt != 0) if (hard_opt != 0)
@@ -4318,7 +4411,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
fclose(f); fclose(f);
} }
#ifdef HAVE_DHCP #if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
int option_read_dynfile(char *file, int flags) int option_read_dynfile(char *file, int flags)
{ {
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file); my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
@@ -4519,86 +4612,99 @@ void read_servers_file(void)
#ifdef HAVE_DHCP #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) 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); daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next) for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
if (!(hf->flags & AH_INACTIVE)) if (!(hf->flags & AH_INACTIVE))
{ {
if (one_file(hf->fname, LOPT_BANK)) if (one_file(hf->fname, LOPT_BANK))
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname); my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
} }
} }
if (daemon->dhcp_opts_file) 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); daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
for (hf = daemon->dhcp_opts_file; hf; hf = hf->next) for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
if (!(hf->flags & AH_INACTIVE)) if (!(hf->flags & AH_INACTIVE))
@@ -4607,11 +4713,18 @@ void reread_dhcp(void)
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname); 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 #endif
void read_opts(int argc, char **argv, char *compile_opts) 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); char *buff = opt_malloc(MAXDNAME);
int option, conffile_opt = '7', testmode = 0; int option, conffile_opt = '7', testmode = 0;
char *arg, *conffile = CONFFILE; char *arg, *conffile = CONFFILE;
@@ -4642,6 +4755,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_retry = SOA_RETRY; daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY; daemon->soa_expiry = SOA_EXPIRY;
daemon->max_port = MAX_PORT; daemon->max_port = MAX_PORT;
daemon->min_port = MIN_PORT;
#ifndef NO_ID #ifndef NO_ID
add_txt("version.bind", "dnsmasq-" VERSION, 0 ); add_txt("version.bind", "dnsmasq-" VERSION, 0 );
@@ -4681,9 +4795,14 @@ void read_opts(int argc, char **argv, char *compile_opts)
/* Copy optarg so that argv doesn't get changed */ /* Copy optarg so that argv doesn't get changed */
if (optarg) if (optarg)
{ {
strncpy(buff, optarg, MAXDNAME); if (strlen(optarg) >= argbuf_size)
buff[MAXDNAME-1] = 0; {
arg = buff; free(argbuf);
argbuf_size = strlen(optarg) + 1;
argbuf = opt_malloc(argbuf_size);
}
safe_strncpy(argbuf, optarg, argbuf_size);
arg = argbuf;
} }
else else
arg = NULL; arg = NULL;
@@ -4731,6 +4850,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
} }
} }
free(argbuf);
if (conffile) if (conffile)
{ {
one_file(conffile, conffile_opt); one_file(conffile, conffile_opt);
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+5 -2
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 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 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 */ /* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz) 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); print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
mac = daemon->namebuff; 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) if (ra_param)
mtu = ra_param->mtu; mtu = ra_param->mtu;
#ifdef HAVE_LINUX_NETWORK #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 */ available from SIOCGIFMTU */
if (mtu == 0) if (mtu == 0)
{ {
+148 -116
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 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 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) if ((l = *p++) == 0)
/* end marker */ /* end marker */
{ {
/* check that there are the correct no of bytes after the name */ /* check that there are the correct no. of bytes after the name */
if (!CHECK_LEN(header, p, plen, extrabytes)) if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
return 0; return 0;
if (isExtract) 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)); memset(addrp, 0, sizeof(struct all_addr));
/* turn name into a series of asciiz strings */ /* 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++) for(j = 1,cp1 = name; *namein; cp1++, namein++)
if (*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 int i, len = *p1;
unsigned char *p2 = p1; unsigned char *p2 = p1;
if ((p1 + len - p) >= rdlen)
return 0; /* bad packet */
/* make counted string zero-term and sanitise */ /* make counted string zero-term and sanitise */
for (i = 0; i < len; i++) 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. expired and cleaned out that way.
Return 1 if we reject an address because it look like part of dns-rebinding attack. */ 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, 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; unsigned char *p, *p1, *endrr, *namep;
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0; 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 #else
(void)ipsets; /* unused */ (void)ipsets; /* unused */
#endif #endif
cache_start_insert(); cache_start_insert();
@@ -601,10 +605,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{ {
searched_soa = 1; searched_soa = 1;
ttl = find_soa(header, qlen, name, doctored); ttl = find_soa(header, qlen, name, doctored);
if (*doctored)
{
if (secure)
return 0;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (*doctored && secure) if (option_bool(OPT_DNSSEC_VALID))
return 0; for (i = 0; i < ntohs(header->ancount); i++)
if (daemon->rr_status[i])
return 0;
#endif #endif
}
} }
/* go through the questions. */ /* 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; int found = 0, cname_count = CNAME_CHAIN;
struct crec *cpp = NULL; struct crec *cpp = NULL;
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0; 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; unsigned long cttl = ULONG_MAX, attl;
namep = p; 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))) if (!(p1 = skip_questions(header, qlen)))
return 0; 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; unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */ /* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1, 0) || 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)) if (!extract_name(header, qlen, &p1, name, 1, 0))
return 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 (aqtype == T_CNAME)
{ {
if (!cname_count-- || secure) if (!cname_count--)
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */ return 0; /* looped CNAMES, we can't cache. */
#ifdef HAVE_DNSSEC
cname_short = 1;
#endif
goto cname_loop; 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); ttl = find_soa(header, qlen, NULL, doctored);
} }
if (ttl) 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 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))) if (!(p1 = skip_questions(header, qlen)))
return 0; 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))) if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */ 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)) 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 (aqtype == T_CNAME)
{ {
if (!cname_count--) if (!cname_count--)
@@ -754,6 +788,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
newc->addr.cname.uid = 1; newc->addr.cname.uid = 1;
if (cpp) if (cpp)
{ {
next_uid(newc);
cpp->addr.cname.target.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
@@ -810,6 +845,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag); newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
if (newc && cpp) if (newc && cpp)
{ {
next_uid(newc);
cpp->addr.cname.target.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
@@ -833,9 +869,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
pointing at this, inherit its TTL */ pointing at this, inherit its TTL */
if (ttl || cpp) 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) if (newc && cpp)
{ {
next_uid(newc);
cpp->addr.cname.target.cache = newc; cpp->addr.cname.target.cache = newc;
cpp->addr.cname.uid = newc->uid; cpp->addr.cname.uid = newc->uid;
} }
@@ -892,12 +929,11 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
return F_QUERY; return F_QUERY;
} }
size_t setup_reply(struct dns_header *header, size_t qlen, size_t setup_reply(struct dns_header *header, size_t qlen,
struct all_addr *addrp, unsigned int flags, unsigned long ttl) struct all_addr *addrp, unsigned int flags, unsigned long ttl)
{ {
unsigned char *p; unsigned char *p;
if (!(p = skip_questions(header, qlen))) if (!(p = skip_questions(header, qlen)))
return 0; return 0;
@@ -913,65 +949,76 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
SET_RCODE(header, NOERROR); /* empty domain */ SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN) else if (flags == F_NXDOMAIN)
SET_RCODE(header, NXDOMAIN); SET_RCODE(header, NXDOMAIN);
else if (flags == F_IPV4) else if (flags == F_SERVFAIL)
{ /* we know the address */
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
}
#ifdef HAVE_IPV6
else if (flags == F_IPV6)
{ {
SET_RCODE(header, NOERROR); struct all_addr a;
header->ancount = htons(1); a.addr.rcode.rcode = SERVFAIL;
header->hb3 |= HB3_AA; log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp); SET_RCODE(header, SERVFAIL);
} }
else if (flags & ( F_IPV4 | F_IPV6))
{
if (flags & F_IPV4)
{ /* we know the address */
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
}
#ifdef HAVE_IPV6
if (flags & F_IPV6)
{
SET_RCODE(header, NOERROR);
header->ancount = htons(ntohs(header->ancount) + 1);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
}
#endif #endif
}
else /* nowhere to forward to */ else /* nowhere to forward to */
SET_RCODE(header, REFUSED); {
struct all_addr a;
a.addr.rcode.rcode = REFUSED;
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
SET_RCODE(header, REFUSED);
}
return p - (unsigned char *)header; return p - (unsigned char *)header;
} }
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */ /* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
int check_for_local_domain(char *name, time_t now) int check_for_local_domain(char *name, time_t now)
{ {
struct crec *crecp;
struct mx_srv_record *mx; struct mx_srv_record *mx;
struct txt_record *txt; struct txt_record *txt;
struct interface_name *intr; struct interface_name *intr;
struct ptr_record *ptr; struct ptr_record *ptr;
struct naptr *naptr; struct naptr *naptr;
/* 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)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
for (naptr = daemon->naptr; naptr; naptr = naptr->next) for (naptr = daemon->naptr; naptr; naptr = naptr->next)
if (hostname_isequal(name, naptr->name)) if (hostname_issubdomain(name, naptr->name))
return 1; return 1;
for (mx = daemon->mxnames; mx; mx = mx->next) for (mx = daemon->mxnames; mx; mx = mx->next)
if (hostname_isequal(name, mx->name)) if (hostname_issubdomain(name, mx->name))
return 1; return 1;
for (txt = daemon->txt; txt; txt = txt->next) for (txt = daemon->txt; txt; txt = txt->next)
if (hostname_isequal(name, txt->name)) if (hostname_issubdomain(name, txt->name))
return 1; return 1;
for (intr = daemon->int_names; intr; intr = intr->next) for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name)) if (hostname_issubdomain(name, intr->name))
return 1; return 1;
for (ptr = daemon->ptr; ptr; ptr = ptr->next) for (ptr = daemon->ptr; ptr; ptr = ptr->next)
if (hostname_isequal(name, ptr->name)) if (hostname_issubdomain(name, ptr->name))
return 1; return 1;
if (cache_find_non_terminal(name, now))
return 1;
return 0; return 0;
} }
@@ -1062,6 +1109,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
return 0; return 0;
} }
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, 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, ...) unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
{ {
@@ -1071,29 +1119,41 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
unsigned short usval; unsigned short usval;
long lval; long lval;
char *sval; 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 */ va_start(ap, format); /* make ap point to 1st unamed argument */
if (truncp && *truncp)
goto truncated;
if (nameoffset > 0) if (nameoffset > 0)
{ {
CHECK_LIMIT(2);
PUTSHORT(nameoffset | 0xc000, p); PUTSHORT(nameoffset | 0xc000, p);
} }
else else
{ {
char *name = va_arg(ap, char *); char *name = va_arg(ap, char *);
if (name) if (name && !(p = do_rfc1035_name(p, name, limit)))
p = do_rfc1035_name(p, name); goto truncated;
if (nameoffset < 0) if (nameoffset < 0)
{ {
CHECK_LIMIT(2);
PUTSHORT(-nameoffset | 0xc000, p); PUTSHORT(-nameoffset | 0xc000, p);
} }
else else
*p++ = 0; {
CHECK_LIMIT(1);
*p++ = 0;
}
} }
/* type (2) + class (2) + ttl (4) + rdlen (2) */
CHECK_LIMIT(10);
PUTSHORT(type, p); PUTSHORT(type, p);
PUTSHORT(class, p); PUTSHORT(class, p);
PUTLONG(ttl, p); /* TTL */ PUTLONG(ttl, p); /* TTL */
@@ -1106,6 +1166,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
case '6': case '6':
CHECK_LIMIT(IN6ADDRSZ);
sval = va_arg(ap, char *); sval = va_arg(ap, char *);
memcpy(p, sval, IN6ADDRSZ); memcpy(p, sval, IN6ADDRSZ);
p += IN6ADDRSZ; p += IN6ADDRSZ;
@@ -1113,36 +1174,43 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
#endif #endif
case '4': case '4':
CHECK_LIMIT(INADDRSZ);
sval = va_arg(ap, char *); sval = va_arg(ap, char *);
memcpy(p, sval, INADDRSZ); memcpy(p, sval, INADDRSZ);
p += INADDRSZ; p += INADDRSZ;
break; break;
case 'b': case 'b':
CHECK_LIMIT(1);
usval = va_arg(ap, int); usval = va_arg(ap, int);
*p++ = usval; *p++ = usval;
break; break;
case 's': case 's':
CHECK_LIMIT(2);
usval = va_arg(ap, int); usval = va_arg(ap, int);
PUTSHORT(usval, p); PUTSHORT(usval, p);
break; break;
case 'l': case 'l':
CHECK_LIMIT(4);
lval = va_arg(ap, long); lval = va_arg(ap, long);
PUTLONG(lval, p); PUTLONG(lval, p);
break; break;
case 'd': case 'd':
/* get domain-name answer arg and store it in RDATA field */ /* get domain-name answer arg and store it in RDATA field */
if (offset) if (offset)
*offset = p - (unsigned char *)header; *offset = p - (unsigned char *)header;
p = do_rfc1035_name(p, va_arg(ap, char *)); if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
*p++ = 0; goto truncated;
CHECK_LIMIT(1);
*p++ = 0;
break; break;
case 't': case 't':
usval = va_arg(ap, int); usval = va_arg(ap, int);
CHECK_LIMIT(usval);
sval = va_arg(ap, char *); sval = va_arg(ap, char *);
if (usval != 0) if (usval != 0)
memcpy(p, sval, usval); memcpy(p, sval, usval);
@@ -1154,6 +1222,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
usval = sval ? strlen(sval) : 0; usval = sval ? strlen(sval) : 0;
if (usval > 255) if (usval > 255)
usval = 255; usval = 255;
CHECK_LIMIT(usval + 1);
*p++ = (unsigned char)usval; *p++ = (unsigned char)usval;
memcpy(p, sval, usval); memcpy(p, sval, usval);
p += usval; p += usval;
@@ -1162,19 +1231,20 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
va_end(ap); /* clean up variable argument pointer */ va_end(ap); /* clean up variable argument pointer */
/* Now, store real RDLength. sav already checked against limit. */
j = p - sav - 2; j = p - sav - 2;
PUTSHORT(j, sav); /* Now, store real RDLength */ PUTSHORT(j, sav);
/* check for overflow of buffer */
if (limit && ((unsigned char *)limit - p) < 0)
{
if (truncp)
*truncp = 1;
return 0;
}
*pp = p; *pp = p;
return 1; 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) static unsigned long crec_ttl(struct crec *crecp, time_t now)
@@ -1223,17 +1293,14 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct mx_srv_record *rec; struct mx_srv_record *rec;
size_t len; size_t len;
/* Clear buffer beyond request to avoid risk of /* never answer queries with RD unset, to avoid cache snooping. */
information disclosure. */ if (!(header->hb3 & HB3_RD) ||
memset(((char *)header) + qlen, 0, ntohs(header->ancount) != 0 ||
(limit - ((char *)header)) - qlen);
if (ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 || ntohs(header->nscount) != 0 ||
ntohs(header->qdcount) == 0 || ntohs(header->qdcount) == 0 ||
OPCODE(header) != QUERY ) OPCODE(header) != QUERY )
return 0; return 0;
/* Don't return AD set if checking disabled. */ /* Don't return AD set if checking disabled. */
if (header->hb4 & HB4_CD) if (header->hb4 & HB4_CD)
sec_data = 0; sec_data = 0;
@@ -1312,11 +1379,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
sec_data = 0; sec_data = 0;
if (!dryrun) if (!dryrun)
{ {
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>"); log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, daemon->local_ttl, NULL,
t->class, C_IN, "t", t->len, t->txt)) t->class, C_IN, "t", t->len, t->txt))
anscount ++; anscount++;
} }
} }
@@ -1510,44 +1577,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype != type && qtype != T_ANY) if (qtype != type && qtype != T_ANY)
continue; 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 */ /* interface name stuff */
intname_restart: intname_restart:
for (intr = daemon->int_names; intr; intr = intr->next) for (intr = daemon->int_names; intr; intr = intr->next)
@@ -1634,7 +1663,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
/* If the client asked for DNSSEC don't use cached data. */ /* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK)) if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
!do_bit ||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
do do
{ {
/* don't answer wildcard queries with data not from /etc/hosts /* don't answer wildcard queries with data not from /etc/hosts
@@ -1716,8 +1747,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype == T_CNAME || qtype == T_ANY) if (qtype == T_CNAME || qtype == T_ANY)
{ {
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) && if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0))))) (qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
{ {
if (!(crecp->flags & F_DNSSECOK)) if (!(crecp->flags & F_DNSSECOK))
sec_data = 0; sec_data = 0;
+91 -29
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 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 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, static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term); int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt); 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, static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, char *err, u32 xid); 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); 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 int in_list(unsigned char *list, int opt);
static void do_options(struct dhcp_context *context, static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess, struct dhcp_packet *mess,
unsigned char *real_end, unsigned char *end,
unsigned char *req_options, unsigned char *req_options,
char *hostname, char *hostname,
char *config_domain, char *domain,
struct dhcp_netid *netid, struct dhcp_netid *netid,
struct in_addr subnet_addr, struct in_addr subnet_addr,
unsigned char fqdn_flags, unsigned char fqdn_flags,
int null_term, int pxearch, int null_term, int pxe_arch,
unsigned char *uuid, unsigned char *uuid,
int vendor_class_len, int vendor_class_len,
time_t now, 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 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 void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid); 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); static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
@@ -75,7 +75,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_vendor *vendor; struct dhcp_vendor *vendor;
struct dhcp_mac *mac; struct dhcp_mac *mac;
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1; int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
unsigned char *end = (unsigned char *)(mess + 1); unsigned char *end = (unsigned char *)(mess + 1);
unsigned char *real_end = (unsigned char *)(mess + 1); unsigned char *real_end = (unsigned char *)(mess + 1);
@@ -157,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) for (offset = 0; offset < (len - 5); offset += elen + 5)
{ {
elen = option_uint(opt, offset + 4 , 1); 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 *x = option_ptr(opt, offset + 5);
unsigned char *y = option_ptr(opt, offset + elen + 5); unsigned char *y = option_ptr(opt, offset + elen + 5);
@@ -626,6 +626,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
} }
daemon->metrics[METRIC_BOOTP]++;
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid); log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end); return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
@@ -699,8 +700,39 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
client_hostname = daemon->dhcp_buff; client_hostname = daemon->dhcp_buff;
} }
if (client_hostname && option_bool(OPT_LOG_OPTS)) if (client_hostname)
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname); {
struct dhcp_match_name *m;
size_t nl = strlen(client_hostname);
if (option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
for (m = daemon->dhcp_name_match; m; m = m->next)
{
size_t ml = strlen(m->name);
char save = 0;
if (nl < ml)
continue;
if (nl > ml)
{
save = client_hostname[ml];
client_hostname[ml] = 0;
}
if (hostname_isequal(client_hostname, m->name) &&
(save == 0 || m->wildcard))
{
m->netid->next = netid;
netid = m->netid;
}
if (save != 0)
client_hostname[ml] = save;
}
}
if (have_config(config, CONFIG_NAME)) if (have_config(config, CONFIG_NAME))
{ {
@@ -836,10 +868,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (strchr(service->basename, '.')) if (strchr(service->basename, '.'))
snprintf((char *)mess->file, sizeof(mess->file), snprintf((char *)mess->file, sizeof(mess->file),
"%s.%d", service->basename, layer); "%s", service->basename);
else else
snprintf((char *)mess->file, sizeof(mess->file), snprintf((char *)mess->file, sizeof(mess->file),
"%s", service->basename); "%s.%d", service->basename, layer);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK); option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr)); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
@@ -909,7 +941,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!workaround && boot) 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 */ and set discovery_control = 8 */
if (boot->next_server.s_addr) if (boot->next_server.s_addr)
mess->siaddr = boot->next_server; mess->siaddr = boot->next_server;
@@ -917,7 +949,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now); mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
if (boot->file) if (boot->file)
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1); safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
} }
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
@@ -928,6 +960,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if ((pxe && !workaround) || !redirect4011) if ((pxe && !workaround) || !redirect4011)
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0); do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
daemon->metrics[METRIC_PXE]++;
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid); log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
log_tags(tagif_netid, ntohl(mess->xid)); log_tags(tagif_netid, ntohl(mess->xid));
if (!ignore) if (!ignore)
@@ -962,6 +995,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ))) if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
return 0; return 0;
daemon->metrics[METRIC_DHCPDECLINE]++;
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid); log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
if (lease && lease->addr.s_addr == option_addr(opt).s_addr) if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
@@ -994,6 +1028,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else else
message = _("unknown lease"); message = _("unknown lease");
daemon->metrics[METRIC_DHCPRELEASE]++;
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid); log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
return 0; return 0;
@@ -1040,8 +1075,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (have_config(config, CONFIG_DECLINED) && else if (have_config(config, CONFIG_DECLINED) &&
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF) 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); 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, loopback))
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
else else
conf = config->addr; conf = config->addr;
} }
@@ -1062,6 +1095,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
message = _("no address available"); message = _("no address available");
} }
daemon->metrics[METRIC_DHCPDISCOVER]++;
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid); log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid))) if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
@@ -1075,6 +1109,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_tags(tagif_netid, ntohl(mess->xid)); log_tags(tagif_netid, ntohl(mess->xid));
apply_delay(mess->xid, recvtime, tagif_netid); apply_delay(mess->xid, recvtime, tagif_netid);
if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0))
{
rapid_commit = 1;
goto rapid_commit;
}
daemon->metrics[METRIC_DHCPOFFER]++;
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4)); time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
@@ -1087,7 +1129,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
case DHCPREQUEST: case DHCPREQUEST:
if (ignore || have_config(config, CONFIG_DISABLE)) if (ignore || have_config(config, CONFIG_DISABLE))
return 0; return 0;
@@ -1185,9 +1228,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
fuzz = rand16(); fuzz = rand16();
mess->yiaddr = mess->ciaddr; mess->yiaddr = mess->ciaddr;
} }
daemon->metrics[METRIC_DHCPREQUEST]++;
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid); log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
rapid_commit:
if (!message) if (!message)
{ {
struct dhcp_config *addr_config; struct dhcp_config *addr_config;
@@ -1258,7 +1303,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (message) if (message)
{ {
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid); daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++;
log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
/* rapid commit case: lease allocate failed but don't send DHCPNAK */
if (rapid_commit)
return 0;
mess->yiaddr.s_addr = 0; mess->yiaddr.s_addr = 0;
clear_packet(mess, end); clear_packet(mess, end);
@@ -1415,13 +1465,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else else
override = lease->override; override = lease->override;
daemon->metrics[METRIC_DHCPACK]++;
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
clear_packet(mess, end); clear_packet(mess, end);
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK); option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr)); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time); option_put(mess, end, OPTION_LEASE_TIME, 4, time);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), if (rapid_commit)
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz); netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
} }
@@ -1431,6 +1484,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (ignore || have_config(config, CONFIG_DISABLE)) if (ignore || have_config(config, CONFIG_DISABLE))
message = _("ignored"); message = _("ignored");
daemon->metrics[METRIC_DHCPINFORM]++;
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid); log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
if (message || mess->ciaddr.s_addr == 0) if (message || mess->ciaddr.s_addr == 0)
@@ -1457,6 +1511,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_tags(tagif_netid, ntohl(mess->xid)); log_tags(tagif_netid, ntohl(mess->xid));
daemon->metrics[METRIC_DHCPACK]++;
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid); log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
if (lease) if (lease)
@@ -1623,6 +1678,13 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
daemon->namebuff, daemon->namebuff,
string ? string : "", string ? string : "",
err ? err : ""); err ? err : "");
#ifdef HAVE_UBUS
if (!strcmp(type, "DHCPACK"))
ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
else if (!strcmp(type, "DHCPRELEASE"))
ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
#endif
} }
static void log_options(unsigned char *start, u32 xid) static void log_options(unsigned char *start, u32 xid)
@@ -2286,7 +2348,7 @@ static void do_options(struct dhcp_context *context,
/* See if we can send the boot stuff as options. /* See if we can send the boot stuff as options.
To do this we need a requested option list, BOOTP To do this we need a requested option list, BOOTP
and very old DHCP clients won't have this, we also 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 Some PXE ROMs have bugs (surprise!) and need zero-terminated
names, so we always send those. */ names, so we always send those. */
if ((boot = find_boot(tagif))) if ((boot = find_boot(tagif)))
@@ -2298,7 +2360,7 @@ static void do_options(struct dhcp_context *context,
in_list(req_options, OPTION_SNAME)) in_list(req_options, OPTION_SNAME))
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1); option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
else else
strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1); safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname));
} }
if (boot->file) if (boot->file)
@@ -2308,7 +2370,7 @@ static void do_options(struct dhcp_context *context,
in_list(req_options, OPTION_FILENAME)) in_list(req_options, OPTION_FILENAME))
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1); option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
else else
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1); safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
} }
if (boot->next_server.s_addr) if (boot->next_server.s_addr)
@@ -2325,14 +2387,14 @@ static void do_options(struct dhcp_context *context,
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) && if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE)) (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
{ {
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1); safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file));
done_file = 1; done_file = 1;
} }
if ((!req_options || !in_list(req_options, OPTION_SNAME)) && if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE)) (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
{ {
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1); safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname));
done_server = 1; done_server = 1;
} }
@@ -2454,10 +2516,10 @@ static void do_options(struct dhcp_context *context,
if (fqdn_flags & 0x04) if (fqdn_flags & 0x04)
{ {
p = do_rfc1035_name(p, hostname); p = do_rfc1035_name(p, hostname, NULL);
if (domain) if (domain)
{ {
p = do_rfc1035_name(p, domain); p = do_rfc1035_name(p, domain, NULL);
*p++ = 0; *p++ = 0;
} }
} }
+72 -47
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 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 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 */ /* RFC-6939 */
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3))) 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_type = opt6_uint(opt, 0, 2);
state->mac_len = opt6_len(opt) - 2; state->mac_len = opt6_len(opt) - 2;
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len); 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)) 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)); int o = new_opt6(opt6_type(opt));
if (opt6_type(opt) == OPTION6_RELAY_MSG) if (opt6_type(opt) == OPTION6_RELAY_MSG)
{ {
@@ -633,9 +639,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
int plain_range = 1; int plain_range = 1;
u32 lease_time; u32 lease_time;
struct dhcp_lease *ltmp; struct dhcp_lease *ltmp;
struct in6_addr *req_addr; struct in6_addr req_addr, addr;
struct in6_addr addr;
if (!check_ia(state, opt, &ia_end, &ia_option)) if (!check_ia(state, opt, &ia_end, &ia_option))
continue; continue;
@@ -703,9 +708,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
req_addr = opt6_ptr(ia_option, 0); /* worry about alignment here. */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range))) if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
{ {
lease_time = c->lease_time; lease_time = c->lease_time;
/* If the client asks for an address on the same network as a configured address, /* If the client asks for an address on the same network as a configured address,
@@ -713,14 +719,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
addresses automatic. */ addresses automatic. */
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr)) if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
{ {
req_addr = &addr; req_addr = addr;
mark_config_used(c, &addr); mark_config_used(c, &addr);
if (have_config(config, CONFIG_TIME)) if (have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
} }
else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range))) else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
continue; /* not an address we're allowed */ continue; /* not an address we're allowed */
else if (!check_address(state, req_addr)) else if (!check_address(state, &req_addr))
continue; /* address leased elsewhere */ continue; /* address leased elsewhere */
/* add address to output packet */ /* add address to output packet */
@@ -728,8 +734,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c); state->send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(state, c, lease_time, ia_option, &min_time, req_addr, now); add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
mark_context_used(state, req_addr); mark_context_used(state, &req_addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
@@ -762,15 +768,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ltmp = NULL; ltmp = NULL;
while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid))) while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
{ {
req_addr = &ltmp->addr6; req_addr = ltmp->addr6;
if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range))) if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
{ {
#ifdef OPTION6_PREFIX_CLASS #ifdef OPTION6_PREFIX_CLASS
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c); state->send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now); add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
mark_context_used(state, req_addr); mark_context_used(state, &req_addr);
get_context_tag(state, c); get_context_tag(state, c);
address_assigned = 1; address_assigned = 1;
} }
@@ -876,7 +882,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (!ia_option) 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. */ a SOLICT with rapid commit set. */
save_counter(start); save_counter(start);
goto request_no_address; goto request_no_address;
@@ -886,16 +892,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr req_addr;
struct dhcp_context *dynamic, *c; struct dhcp_context *dynamic, *c;
unsigned int lease_time; unsigned int lease_time;
struct in6_addr addr; struct in6_addr addr;
int config_ok = 0; int config_ok = 0;
/* align. */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((c = address6_valid(state->context, req_addr, tagif, 1))) if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr); config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c) if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
{ {
if (!dynamic && !config_ok) if (!dynamic && !config_ok)
{ {
@@ -905,7 +914,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
put_opt6_string(_("address unavailable")); put_opt6_string(_("address unavailable"));
end_opt6(o1); end_opt6(o1);
} }
else if (!check_address(state, req_addr)) else if (!check_address(state, &req_addr))
{ {
/* Address leased to another DUID/IAID */ /* Address leased to another DUID/IAID */
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
@@ -927,7 +936,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA) if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
state->send_prefix_class = prefix_class_from_context(c); state->send_prefix_class = prefix_class_from_context(c);
#endif #endif
add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now); add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
get_context_tag(state, dynamic); get_context_tag(state, dynamic);
address_assigned = 1; address_assigned = 1;
} }
@@ -990,15 +999,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct dhcp_lease *lease = NULL; struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr req_addr;
unsigned int preferred_time = opt6_uint(ia_option, 16, 4); unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
unsigned int valid_time = opt6_uint(ia_option, 20, 4); unsigned int valid_time = opt6_uint(ia_option, 20, 4);
char *message = NULL; char *message = NULL;
struct dhcp_context *this_context; struct dhcp_context *this_context;
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if (!(lease = lease6_find(state->clid, state->clid_len, if (!(lease = lease6_find(state->clid, state->clid_len,
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, req_addr))) state->iaid, &req_addr)))
{ {
/* If the server cannot find a client entry for the IA the server /* If the server cannot find a client entry for the IA the server
returns the IA containing no addresses with a Status Code option set returns the IA containing no addresses with a Status Code option set
@@ -1006,7 +1017,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
save_counter(iacntr); save_counter(iacntr);
t1cntr = 0; t1cntr = 0;
log6_packet(state, "DHCPREPLY", req_addr, _("lease not found")); log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING); put_opt6_short(DHCP6NOBINDING);
@@ -1018,15 +1029,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
} }
if ((this_context = address6_available(state->context, req_addr, tagif, 1)) || if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
(this_context = address6_valid(state->context, req_addr, tagif, 1))) (this_context = address6_valid(state->context, &req_addr, tagif, 1)))
{ {
struct in6_addr addr; struct in6_addr addr;
unsigned int lease_time; unsigned int lease_time;
get_context_tag(state, this_context); get_context_tag(state, this_context);
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME)) if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
lease_time = config->lease_time; lease_time = config->lease_time;
else else
lease_time = this_context->lease_time; lease_time = this_context->lease_time;
@@ -1039,7 +1050,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0); lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
if (state->ia_type == OPTION6_IA_NA && state->hostname) if (state->ia_type == OPTION6_IA_NA && state->hostname)
{ {
char *addr_domain = get_domain6(req_addr); char *addr_domain = get_domain6(&req_addr);
if (!state->send_domain) if (!state->send_domain)
state->send_domain = addr_domain; state->send_domain = addr_domain;
lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain); lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
@@ -1057,12 +1068,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
} }
if (message && (message != state->hostname)) if (message && (message != state->hostname))
log6_packet(state, "DHCPREPLY", req_addr, message); log6_packet(state, "DHCPREPLY", &req_addr, message);
else else
log6_quiet(state, "DHCPREPLY", req_addr, message); log6_quiet(state, "DHCPREPLY", &req_addr, message);
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr)); put_opt6(&req_addr, sizeof(req_addr));
put_opt6_long(preferred_time); put_opt6_long(preferred_time);
put_opt6_long(valid_time); put_opt6_long(valid_time);
end_opt6(o1); end_opt6(o1);
@@ -1094,19 +1105,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option; ia_option;
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); struct in6_addr req_addr;
/* alignment */
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if (!address6_valid(state->context, req_addr, tagif, 1)) if (!address6_valid(state->context, &req_addr, tagif, 1))
{ {
o1 = new_opt6(OPTION6_STATUS_CODE); o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK); put_opt6_short(DHCP6NOTONLINK);
put_opt6_string(_("confirm failed")); put_opt6_string(_("confirm failed"));
end_opt6(o1); end_opt6(o1);
log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
return 1; return 1;
} }
good_addr = 1; good_addr = 1;
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname); log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
} }
} }
@@ -1165,9 +1180,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct in6_addr addr;
/* align */
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0)))) state->iaid, &addr)))
lease_prune(lease, now); lease_prune(lease, now);
else else
{ {
@@ -1184,7 +1202,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
} }
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ); put_opt6(&addr, IN6ADDRSZ);
put_opt6_long(0); put_opt6_long(0);
put_opt6_long(0); put_opt6_long(0);
end_opt6(o1); end_opt6(o1);
@@ -1227,12 +1245,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24)) ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct in6_addr *addrp = opt6_ptr(ia_option, 0); struct in6_addr addr;
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp)) /* align */
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
{ {
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF); prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN); inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"), my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
daemon->addrbuff, daemon->dhcp_buff3); daemon->addrbuff, daemon->dhcp_buff3);
config->flags |= CONFIG_DECLINED; config->flags |= CONFIG_DECLINED;
@@ -1244,7 +1265,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
context_tmp->addr_epoch++; context_tmp->addr_epoch++;
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, opt6_ptr(ia_option, 0)))) state->iaid, &addr)))
lease_prune(lease, now); lease_prune(lease, now);
else else
{ {
@@ -1261,7 +1282,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
} }
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ); put_opt6(&addr, IN6ADDRSZ);
put_opt6_long(0); put_opt6_long(0);
put_opt6_long(0); put_opt6_long(0);
end_opt6(o1); end_opt6(o1);
@@ -1479,10 +1500,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
if ((p = expand(len + 2))) if ((p = expand(len + 2)))
{ {
*(p++) = state->fqdn_flags; *(p++) = state->fqdn_flags;
p = do_rfc1035_name(p, state->hostname); p = do_rfc1035_name(p, state->hostname, NULL);
if (state->send_domain) if (state->send_domain)
{ {
p = do_rfc1035_name(p, state->send_domain); p = do_rfc1035_name(p, state->send_domain, NULL);
*p = 0; *p = 0;
} }
} }
@@ -1619,7 +1640,7 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
{ {
if (t1cntr != 0) 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); int sav = save_counter(t1cntr);
unsigned int t1, t2, fuzz = 0; unsigned int t1, t2, fuzz = 0;
@@ -1929,7 +1950,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
} }
else if (type == OPTION6_IAADDR) else if (type == OPTION6_IAADDR)
{ {
inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN); struct in6_addr addr;
/* align */
memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
sprintf(daemon->namebuff, "%s PL=%u VL=%u", sprintf(daemon->namebuff, "%s PL=%u VL=%u",
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4)); daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
optname = "iaaddr"; optname = "iaaddr";
+4 -4
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 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 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/>. 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" #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); 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) for (p = rrs[0], i = 1; i < rr_found; i += 2)
{ {
unsigned char *start = rrs[i]; unsigned char *start = rrs[i];
@@ -270,7 +270,7 @@ u16 *rrfilter_desc(int type)
{ {
/* List of RRtypes which include domains in the data. /* List of RRtypes which include domains in the data.
0 -> domain 0 -> domain
integer -> no of plain bytes integer -> no. of plain bytes
-1 -> end -1 -> end
zero is not a valid RRtype, so the final entry is returned for zero is not a valid RRtype, so the final entry is returned for
+1 -1
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 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 it under the terms of the GNU General Public License as published by
+4 -4
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 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 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 struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static void free_transfer(struct tftp_transfer *transfer); 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 tftp_err_oops(char *packet, char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer); static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end); static char *next(char **p, char *end);
@@ -234,7 +234,7 @@ void tftp_request(struct listener *listen, time_t now)
#endif #endif
} }
strncpy(ifr.ifr_name, name, IF_NAMESIZE); safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1) if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
{ {
mtu = ifr.ifr_mtu; mtu = ifr.ifr_mtu;
@@ -734,7 +734,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
if (transfer->opt_blocksize) if (transfer->opt_blocksize)
{ {
p += (sprintf(p, "blksize") + 1); p += (sprintf(p, "blksize") + 1);
p += (sprintf(p, "%d", transfer->blocksize) + 1); p += (sprintf(p, "%u", transfer->blocksize) + 1);
} }
if (transfer->opt_transize) if (transfer->opt_transize)
{ {
+107
View File
@@ -0,0 +1,107 @@
/* 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_UBUS
#include <libubus.h>
static struct ubus_context *ubus = NULL;
static struct blob_buf b;
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
static struct ubus_method ubus_object_methods[] = {
{.name = "metrics", .handler = ubus_handle_metrics},
};
static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
static struct ubus_object ubus_object = {
.name = "dnsmasq",
.type = &ubus_object_type,
.methods = ubus_object_methods,
.n_methods = ARRAY_SIZE(ubus_object_methods),
};
void set_ubus_listeners()
{
if (!ubus)
return;
poll_listen(ubus->sock.fd, POLLIN);
poll_listen(ubus->sock.fd, POLLERR);
poll_listen(ubus->sock.fd, POLLHUP);
}
void check_ubus_listeners()
{
if (!ubus)
{
ubus = ubus_connect(NULL);
if (!ubus)
return;
ubus_add_object(ubus, &ubus_object);
}
if (poll_check(ubus->sock.fd, POLLIN))
ubus_handle_event(ubus);
if (poll_check(ubus->sock.fd, POLLHUP))
{
ubus_free(ubus);
ubus = NULL;
}
}
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int i;
blob_buf_init(&b, 0);
for(i=0; i < __METRIC_MAX; i++)
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
ubus_send_reply(ctx, req, b.head);
return 0;
}
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
{
if (!ubus || !ubus_object.has_subscribers)
return;
blob_buf_init(&b, 0);
if (mac)
blobmsg_add_string(&b, "mac", mac);
if (ip)
blobmsg_add_string(&b, "ip", ip);
if (name)
blobmsg_add_string(&b, "name", name);
if (interface)
blobmsg_add_string(&b, "interface", interface);
ubus_notify(ubus, &ubus_object, type, b.head, -1);
}
#endif /* HAVE_UBUS */
+102 -31
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 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 it under the terms of the GNU General Public License as published by
@@ -111,6 +111,7 @@ u64 rand64(void)
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32); 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) static int check_name(char *in)
{ {
/* remove trailing . /* remove trailing .
@@ -118,6 +119,7 @@ static int check_name(char *in)
size_t dotgap = 0, l = strlen(in); size_t dotgap = 0, l = strlen(in);
char c; char c;
int nowhite = 0; int nowhite = 0;
int hasuscore = 0;
if (l == 0 || l > MAXDNAME) return 0; if (l == 0 || l > MAXDNAME) return 0;
@@ -141,13 +143,17 @@ static int check_name(char *in)
return 0; return 0;
#endif #endif
else if (c != ' ') else if (c != ' ')
nowhite = 1; {
nowhite = 1;
if (c == '_')
hasuscore = 1;
}
} }
if (!nowhite) if (!nowhite)
return 0; return 0;
return 1; return hasuscore ? 2 : 1;
} }
/* Hostnames have a more limited valid charset than domain names /* Hostnames have a more limited valid charset than domain names
@@ -186,56 +192,70 @@ int legal_hostname(char *name)
char *canonicalise(char *in, int *nomem) char *canonicalise(char *in, int *nomem)
{ {
char *ret = NULL; char *ret = NULL;
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
int rc; int rc;
#endif
if (nomem) if (nomem)
*nomem = 0; *nomem = 0;
if (!check_name(in)) if (!(rc = check_name(in)))
return NULL; return NULL;
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) #if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
#ifdef HAVE_LIBIDN2 /* older libidn2 strips underscores, so don't do IDN processing
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL); if the name has an underscore (check_name() returned 2) */
if (rc == IDN2_DISALLOWED) if (rc != 2)
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
#else
rc = idna_to_ascii_lz(in, &ret, 0);
#endif #endif
if (rc != IDNA_SUCCESS) #if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
{ {
if (ret) # ifdef HAVE_LIBIDN2
free(ret); rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
if (rc == IDN2_DISALLOWED)
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR)) 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")); if (ret)
*nomem = 1; 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))) if ((ret = whine_malloc(strlen(in)+1)))
strcpy(ret, in); strcpy(ret, in);
else if (nomem) else if (nomem)
*nomem = 1; *nomem = 1;
#endif
return ret; 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; int j;
while (sval && *sval) while (sval && *sval)
{ {
unsigned char *cp = p++; unsigned char *cp = p++;
if (limit && p > (unsigned char*)limit)
return NULL;
for (j = 0; *sval && (*sval != '.'); sval++, j++) for (j = 0; *sval && (*sval != '.'); sval++, j++)
{ {
if (limit && p + 1 > (unsigned char*)limit)
return NULL;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE) if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
*p++ = (*(++sval))-1; *p++ = (*(++sval))-1;
@@ -243,10 +263,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
#endif #endif
*p++ = *sval; *p++ = *sval;
} }
*cp = j; *cp = j;
if (*sval) if (*sval)
sval++; sval++;
} }
return p; return p;
} }
@@ -259,7 +281,18 @@ void *safe_malloc(size_t size)
die(_("could not get memory"), NULL, EC_NOMEM); die(_("could not get memory"), NULL, EC_NOMEM);
return ret; return ret;
} }
/* Ensure limited size string is always terminated.
* Can be replaced by (void)strlcpy() on some platforms */
void safe_strncpy(char *dest, const char *src, size_t size)
{
if (size != 0)
{
dest[size-1] = '\0';
strncpy(dest, src, size-1);
}
}
void safe_pipe(int *fd, int read_noblock) void safe_pipe(int *fd, int read_noblock)
{ {
@@ -333,6 +366,44 @@ int hostname_isequal(const char *a, const char *b)
return 1; return 1;
} }
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
int hostname_issubdomain(char *a, char *b)
{
char *ap, *bp;
unsigned int c1, c2;
/* move to the end */
for (ap = a; *ap; ap++);
for (bp = b; *bp; bp++);
/* a shorter than b or a empty. */
if ((bp - b) < (ap - a) || ap == a)
return 0;
do
{
c1 = (unsigned char) *(--ap);
c2 = (unsigned char) *(--bp);
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
return 0;
} while (ap != a);
if (bp == b)
return 2;
if (*(--bp) == '.')
return 1;
return 0;
}
time_t dnsmasq_time(void) time_t dnsmasq_time(void)
{ {
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
@@ -448,13 +519,13 @@ void prettyprint_time(char *buf, unsigned int t)
{ {
unsigned int x, p = 0; unsigned int x, p = 0;
if ((x = t/86400)) if ((x = t/86400))
p += sprintf(&buf[p], "%dd", x); p += sprintf(&buf[p], "%ud", x);
if ((x = (t/3600)%24)) if ((x = (t/3600)%24))
p += sprintf(&buf[p], "%dh", x); p += sprintf(&buf[p], "%uh", x);
if ((x = (t/60)%60)) if ((x = (t/60)%60))
p += sprintf(&buf[p], "%dm", x); p += sprintf(&buf[p], "%um", x);
if ((x = t%60)) if ((x = t%60))
p += sprintf(&buf[p], "%ds", x); p += sprintf(&buf[p], "%us", x);
} }
} }