Compare commits

...

601 Commits

Author SHA1 Message Date
Simon Kelley
f6381cf482 Declare utime(). 2015-07-27 19:48:43 +01:00
Kevin Darbyshire-Bryant
34b5d19488 Update DNSSEC timestamp file on process TERM. 2015-07-27 19:34:23 +01:00
Conrad Kostecki
d6cb7e4815 Update german translation 2015-07-27 19:22:49 +01:00
Simon Kelley
d389e0191b DNSSEC fix: correct logic for signed records in unsigned DNS space. 2015-07-27 18:56:43 +01:00
Simon Kelley
d3699bb6bc Small tweak to DNSSEC fix. 2015-07-16 22:37:37 +01:00
Simon Kelley
13480e8c2a DNSSEC fix, signed wildcard CNAME to unsigned domain. 2015-07-16 22:23:13 +01:00
Jan Psota
5b3b93f80a Update Polish translation. 2015-07-15 19:57:47 +01:00
Simon Kelley
b69e845b1c Close Lauchpad bug in Debian changelog. 2015-07-15 19:54:50 +01:00
Simon Kelley
90c3822bfa Grow pollfds array exponentially. 2015-07-13 12:47:52 +01:00
Simon Kelley
c895a0626d Merge messages for translations. 2015-07-12 21:27:40 +01:00
Simon Kelley
b842bc97bb Use poll() instead of select() to remove limits on open file descriptors. 2015-07-12 21:09:11 +01:00
Simon Kelley
0f38fa05a6 Log message typo. 2015-07-08 22:42:14 +01:00
Simon Kelley
45c5cb1f8f Fix compilation warning. 2015-07-08 22:40:57 +01:00
Simon Kelley
f6d6956261 Test for overflowing platform FD_SET size. 2015-07-08 22:38:13 +01:00
Simon Kelley
60176c7bf4 Bump version in Debian changelog. 2015-07-07 21:54:55 +01:00
Simon Kelley
362c9303da Fix inotify code to handle dangling symlinks better. 2015-07-06 21:48:49 +01:00
Simon Kelley
5e95a552ee Avoid hanngs in DHCP ping code when system time goes backwards. 2015-07-05 22:31:30 +01:00
Simon Kelley
90cb222551 --conf-file should read no file, not try and read the default file. 2015-07-05 21:59:10 +01:00
Ján Sáreník
850163288d Manpage typo fix. 2015-07-05 21:23:27 +01:00
Simon Kelley
e3ec6f0bd7 Handle CNAMEs to DS records when confirming absence of DS for DNSSEC. 2015-06-12 21:39:11 +01:00
Simon Kelley
f7bfbdc872 Merge messages and fix makefile process to do this. 2015-06-10 22:31:02 +01:00
Neil Jerram
4918bd5505 Documenation updates for --bridge-interface and "off-link". 2015-06-10 22:23:20 +01:00
Neil Jerram
9bad339af8 Apply --bridge-interfaces to unsolicited router advertisements. 2015-06-10 22:16:35 +01:00
Neil Jerram
ba4fc0f996 Upply --bridge-interface aliasing to solicited router advertisements. 2015-06-10 22:14:49 +01:00
Neil Jerram
2fd5bc952d Allow router advertisements to have the "off-link" bit set. 2015-06-10 22:13:06 +01:00
Neil Jerram
0ddb8769bb Extend --bridge-interface aliasing to DHCPv6. 2015-06-10 22:11:06 +01:00
Neil Jerram
654f59e762 Fix logging of unknown interface in --bridge-interface, DHPCv4. 2015-06-10 22:06:33 +01:00
Simon Kelley
d91b1fd402 Add a couple of missed logging strings to the catalogue. 2015-06-09 20:45:07 +01:00
Nicolas Cavallari
c6d82c9ba6 Add Dbus methods to create and delete DHCP leases. 2015-06-09 20:42:20 +01:00
Simon Kelley
4d25cf89d5 Handle corner cases in NSEC coverage checks. 2015-06-06 23:13:57 +01:00
Simon Kelley
24e9207e13 More reproducibility fixes for Debian package. 2015-06-04 22:32:43 +01:00
Simon Kelley
89130d91d6 DHCPv6: DHCPCONFIRM should be OK for any address on link, not just dynamic addresses. 2015-06-03 22:34:14 +01:00
Simon Kelley
d644b2a17d Close Debian bug for bug fixed upstream. 2015-06-01 21:00:16 +01:00
swigger
bd7bfa21c4 Correctly sanitise DNS header bits in answer when recreating query for retry. 2015-06-01 20:54:59 +01:00
Simon Kelley
403de05925 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2015-05-26 22:12:01 +01:00
John Hanks
46c89f2bd0 Add infiniband to example config file. 2015-05-26 22:07:57 +01:00
Christian Demsar
23facf0d77 Man page typo. 2015-05-20 20:26:23 +01:00
Simon Kelley
549b1a478c Tweak immediately previous patch. 2015-05-20 20:20:24 +01:00
Simon Kelley
7f8565b94c Select correct DHCP context when in PXE bootserver mode. 2015-05-19 23:01:27 +01:00
Simon Kelley
06568c6636 Remove support for DNS Extended Label Types.
The support was only partial, and the whole concept is
now deprecated in the standards.
2015-05-15 20:43:48 +01:00
Simon Kelley
5d07d77e75 Fix buffer overflow introduced in 2.73rc6.
Fix off-by-one in code which checks for over-long domain names
in received DNS packets. This enables buffer overflow attacks
which can certainly crash dnsmasq and may allow for arbitrary
code execution. The problem was introduced in commit b8f16556d,
release 2.73rc6, so has not escaped into any stable release.
Note that the off-by-one was in the label length determination,
so the buffer can be overflowed by as many bytes as there are
labels in the name - ie, many.

Thanks to Ron Bowes, who used lcmatuf's afl-fuzz tool to find
the problem.
2015-05-15 18:13:06 +01:00
Simon Kelley
62018e1f72 Use correct DHCP context for PXE-proxy server-id. 2015-05-14 21:30:00 +01:00
Simon Kelley
7c0f2543a7 Tweak last commit. 2015-05-14 21:16:18 +01:00
Simon Kelley
ca85a28241 Allow T1 and T2 DHCPv4 options to be set. 2015-05-13 22:33:04 +01:00
Simon Kelley
585840b033 Pointer to mail-archive mailing list mirror in doc.html. 2015-05-13 12:35:57 +01:00
Simon Kelley
dec180ac00 Tweak Debian systemd unit file. 2015-05-13 12:16:13 +01:00
Simon Kelley
86fa104692 Tweak EDNS timeout code. 2015-05-10 14:04:06 +01:00
Simon Kelley
b059c96dc6 Check IPv4-mapped IPv6 addresses with --stop-rebind. 2015-05-08 20:25:51 +01:00
Simon Kelley
a77cec8d58 Handle UDP packet loss when fragmentation of large packets is broken. 2015-05-08 16:25:38 +01:00
Nicolas Cavallari
64bcff1c7c Constify some DHCP lease management functions. 2015-04-28 21:55:18 +01:00
Simon Kelley
2ed162ac20 Don't remove RRSIG RR from answers to ANY queries when the do bit is not set. 2015-04-28 21:26:35 +01:00
Simon Kelley
e66b4dff3c Fix argument-order botch which broke DNSSEC for TCP queries. 2015-04-28 20:45:57 +01:00
Johnny S. Lee
8efd731cc4 Make get-version work when repo is a git submodule. 2015-04-26 22:23:57 +01:00
Simon Kelley
a5ae1f8587 Logs in DHCPv6 not suppressed by dhcp6-quiet. 2015-04-25 21:46:10 +01:00
Simon Kelley
b8f16556d3 Tweaks to previous, DNS label charset commit. 2015-04-22 21:14:31 +01:00
Simon Kelley
cbe379ad6b Handle domain names with '.' or /000 within labels.
Only in DNSSEC mode, where we might need to validate or store
such names. In none-DNSSEC mode, simply don't cache these, as before.
2015-04-21 22:57:06 +01:00
Simon Kelley
338b340be9 Revert 61b838dd57 and just quieten log instead. 2015-04-20 21:34:05 +01:00
Moshe Levi
a006eb7e14 Check IP address command line arg in dhcp_release.c 2015-04-19 22:10:40 +01:00
Simon Kelley
554b580e97 Log domain when reporting DNSSEC validation failure. 2015-04-17 22:50:20 +01:00
Simon Kelley
0df29f5e23 Note CVE-2015-3294 2015-04-16 15:24:52 +01:00
Stefan Tomanek
b4c0f092d8 Fix (srk induced) crash in new tftp_no_fail code. 2015-04-16 15:20:59 +01:00
Simon Kelley
78c6184752 Auth: correct replies to NS and SOA in .arpa zones. 2015-04-16 15:05:30 +01:00
Simon Kelley
38440b204d Fix crash in auth code with odd configuration. 2015-04-12 21:52:47 +01:00
Simon Kelley
ad4a8ff7d9 Fix crash on receipt of certain malformed DNS requests. 2015-04-09 21:48:00 +01:00
Simon Kelley
04b0ac0537 Fix crash caused by looking up servers.bind when many servers defined. 2015-04-06 17:19:13 +01:00
Simon Kelley
982faf4024 Fix compiler warning when not including DNSSEC. 2015-04-03 21:42:30 +01:00
Simon Kelley
fe3992f9fa Return INSECURE, rather than BOGUS when DS proved not to exist.
Return INSECURE when validating DNS replies which have RRSIGs, but
when a needed DS record in the trust chain is proved not to exist.
It's allowed for a zone to set up DNSKEY and RRSIG records first, then
add a DS later, completing the chain of trust.

Also, since we don't have the infrastructure to track that these
non-validated replies have RRSIGS, don't cache them, so we don't
provide answers with missing RRSIGS from the cache.
2015-04-03 21:25:05 +01:00
Stefan Tomanek
7aa970e2c7 Whitespace fixes. 2015-04-01 17:55:07 +01:00
Stefan Tomanek
30d0879ed5 add --tftp-no-fail to ignore missing tftp root 2015-03-31 22:32:11 +01:00
Simon Kelley
fd6ad9e481 Merge message translations. 2015-03-30 07:52:21 +01:00
Simon Kelley
794fccca7f Fix crash in last commit. 2015-03-29 22:35:44 +01:00
Simon Kelley
394ff492da Allow control characters in names in the cache, handle when logging. 2015-03-29 22:17:14 +01:00
Simon Kelley
1e153945de DNSSEC fix for non-ascii characters in labels. 2015-03-28 21:34:07 +00:00
Simon Kelley
0b8a5a30a7 Protect against broken DNSSEC upstreams. 2015-03-27 11:44:55 +00:00
Simon Kelley
150162bc37 Return SERVFAIL when validation abandoned. 2015-03-27 09:58:26 +00:00
Simon Kelley
8805283088 Don't fail DNSSEC when a signed CNAME dangles into an unsigned zone. 2015-03-26 21:15:43 +00:00
Lung-Pin Chang
65c7212000 dhcp: set outbound interface via cmsg in unicast reply
If multiple routes to the same network exist, Linux blindly picks
  the first interface (route) based on destination address, which might not be
  the one we're actually offering leases. Rather than relying on this,
  always set the interface for outgoing unicast DHCP packets.
2015-03-19 23:22:21 +00:00
Simon Kelley
979fe86bc8 Make --address=/example.com/ equivalent to --server=/example.com/ 2015-03-19 22:50:22 +00:00
Simon Kelley
ff841ebf5a Fix boilerplate code for re-running system calls on EINTR and EAGAIN etc.
The nasty code with static variable in retry_send() which
avoids looping forever needs to be called on success of the syscall,
to reset the static variable.
2015-03-11 21:36:30 +00:00
Simon Kelley
360f2513ab Tweak DNSSEC timestamp code to create file later, removing need to chown it. 2015-03-07 18:28:06 +00:00
Simon Kelley
4c960fa90a New version of contrib/reverse-dns 2015-03-04 20:32:26 +00:00
Simon Kelley
9003b50b13 Fix last commit to not crash if uid changing not configured. 2015-03-02 22:47:23 +00:00
Simon Kelley
f6e62e2af9 Add --dnssec-timestamp option and facility. 2015-03-01 18:17:54 +00:00
Joachim Zobel
47b9ac59c7 Log parsing utils in contrib/reverse-dns 2015-02-23 21:38:11 +00:00
Tomas Hozza
0705a7e2d5 Fix uninitialized value used in get_client_mac() 2015-02-23 21:26:26 +00:00
Chen Wei
28b879ac47 Fix trivial memory leaks to quieten valgrind. 2015-02-17 22:07:35 +00:00
Simon Kelley
caeea190f1 Make dynamic hosts files work when --no-hosts set. 2015-02-14 20:08:56 +00:00
Simon Kelley
8ff70de618 Typos. 2015-02-14 20:02:37 +00:00
Simon Kelley
ee4d1cea92 Debian systemd fixes. 2015-02-12 18:30:32 +00:00
Shantanu Gadgil
f4f400776b Fix get-version script which returned wrong tag in some situations. 2015-02-11 20:16:59 +00:00
Chris Lamb
b467a454b4 Make Debian build reproducible. 2015-02-09 11:52:30 +00:00
Simon Kelley
efb8b5566a man page typo. 2015-02-07 22:36:34 +00:00
Simon Kelley
f9c863708c Extra logging for inotify code. 2015-02-03 21:52:48 +00:00
Simon Kelley
2941d3ac89 Fixup dhcp-configs after reading extra hostfiles with inotify. 2015-02-02 22:36:42 +00:00
Thiébaud Weksteen
d36b732c4c Manpage typo fix. 2015-02-02 21:38:27 +00:00
Simon Kelley
d2c5458e31 Debian changelog bugfix. 2015-02-02 21:27:39 +00:00
Simon Kelley
8d8a54ec79 Fix build failure on openBSD. 2015-02-01 21:48:46 +00:00
Simon Kelley
1062667618 BSD make support 2015-02-01 00:15:16 +00:00
Simon Kelley
6ef15b34ca Fix broken ECDSA DNSSEC signatures. 2015-01-31 22:44:26 +00:00
Simon Kelley
3d04f46334 inotify documentation updates. 2015-01-31 21:59:13 +00:00
Simon Kelley
aff3396280 Update copyrights for dawn of 2015. 2015-01-31 20:13:40 +00:00
Simon Kelley
70d1873dd9 Expand inotify code to dhcp-hostsdir, dhcp-optsdir and hostsdir. 2015-01-31 19:59:29 +00:00
Simon Kelley
0491805d2f Allow inotify to be disabled at compile time on Linux. 2015-01-26 11:23:43 +00:00
Win King Wan
61b838dd57 Don't reply to DHCPv6 SOLICIT messages when not configured for statefull DHCPv6. 2015-01-21 20:41:48 +00:00
Conrad Kostecki
fbf01f7046 Update German translation. 2015-01-20 21:07:56 +00:00
Simon Kelley
5f4dc5c6ca Add --dhcp-hostsdir config option. 2015-01-20 20:51:02 +00:00
Simon Kelley
2ae195f5a7 Don't treat SERVFAIL as a recoverable error..... 2015-01-18 22:20:48 +00:00
Simon Kelley
393415597c Cope with multiple interfaces with the same LL address. 2015-01-18 22:11:10 +00:00
Simon Kelley
ae4624bf46 Logs for DS records consistent. 2015-01-12 23:22:08 +00:00
Simon Kelley
5e321739db Don't answer from cache RRsets from wildcards, as we don't have NSECs. 2015-01-12 23:16:56 +00:00
Simon Kelley
9f79ee4ae3 Log port of requestor when doing extra logging. 2015-01-12 20:18:18 +00:00
RinSatsuki
28de38768e Add --min-cache-ttl option. 2015-01-10 15:22:21 +00:00
Simon Kelley
25cf5e373e Add --log-queries=extra option for more complete logging. 2015-01-09 15:53:03 +00:00
Simon Kelley
424c4a8a53 Merge branch 'unsigned' 2015-01-07 22:01:14 +00:00
Simon Kelley
97e618a0e3 DNSSEC: do top-down search for limit of secure delegation. 2015-01-07 21:55:43 +00:00
Yousong Zhou
d8dbd903d0 Fix race condition issue in makefile. 2015-01-05 17:03:35 +00:00
Yousong Zhou
81c538efce Implement makefile dependencies on COPTS variable. 2015-01-03 16:36:14 +00:00
Matthias Andree
d310ab7ecb Fix build failure in new inotify code on BSD. 2014-12-27 15:36:38 +00:00
Simon Kelley
0b1008d367 Bad packet protection. 2014-12-27 15:33:32 +00:00
Glen Huang
32fc6dbe03 Add --ignore-address option. 2014-12-27 15:28:12 +00:00
Simon Kelley
83d2ed09fc Initialise return value. 2014-12-23 18:42:38 +00:00
Simon Kelley
fbc5205702 Fix problems validating NSEC3 and wildcards. 2014-12-23 15:46:08 +00:00
Simon Kelley
cbc6524234 Make caching work for CNAMEs pointing to A/AAAA records shadowed in /etc/hosts
If the answer to an upstream query is a CNAME which points to an
A/AAAA record which also exists in /etc/hosts and friends, then
caching is suppressed, to avoid inconsistent answers. This is
now modified to allow caching when the upstream and local A/AAAA
records have the same value.
2014-12-21 21:21:53 +00:00
Simon Kelley
094b5c3d90 Fix crash in DNSSEC code when attempting to verify large RRs. 2014-12-21 16:11:52 +00:00
Simon Kelley
3267804598 Tweak field width in cache dump to avoid truncating IPv6 addresses. 2014-12-17 20:38:20 +00:00
Simon Kelley
476693678e Eliminate IPv6 privacy addresses from --interface-name answers. 2014-12-17 12:41:56 +00:00
Simon Kelley
bd9520b7ad Remove redundant IN6_IS_ADDR_ULA(a) macro defn. 2014-12-16 20:41:29 +00:00
Simon Kelley
3ad3f3bbd4 Fix breakage of --domain=<domain>,<subnet>,local 2014-12-16 18:25:17 +00:00
Simon Kelley
ad946d555d CHANGELOG re. inotify. 2014-12-15 17:52:22 +00:00
Simon Kelley
800c5cc1e7 Remove floor on EDNS0 packet size with DNSSEC. 2014-12-15 17:50:15 +00:00
Simon Kelley
857973e6f7 Teach the new inotify code about symlinks. 2014-12-15 15:58:13 +00:00
Simon Kelley
9c448c8018 Merge branch 'inotify' 2014-12-10 17:40:03 +00:00
Simon Kelley
193de4abf5 Use inotify instead of polling on Linux.
This should solve problems people are seeing when a file changes
twice within a second and thus is missed for polling.
2014-12-10 17:32:16 +00:00
Hans Dedecker
98906275a0 Fix conntrack with --bind-interfaces
Make sure dst_addr is assigned the correct address in receive_query when OPTNOWILD is
enabled so the assigned mark can be correctly retrieved and set in forward_query when
conntrack is enabled.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
2014-12-09 22:22:53 +00:00
Vladislav Grishenko
b9ff5c8f43 Improve RFC-compliance when unable to supply addresses in DHCPv6
While testing https://github.com/sbyx/odhcp6c client I have noticed it
permanently crashes after startup.

The reason was it (odhcp6c) doesn't expect empty IA options in ADVERTISE
message without any suboptions.

Despite this validation bug of odhcp6c, dnsmasq should not generate
ADVERTISE messages with IA if there's nothing to advert per  RFC 3315
17.2.2:

   If the server will not assign any addresses to any IAs in a

   subsequent Request from the client, the server MUST send an Advertise

   message to the client that includes only a Status Code option with

   code NoAddrsAvail and a status message for the user, a Server

   Identifier option with the server's DUID, and a Client Identifier

   option with the client's DUID.

Meanwhile it's need to add status code for every IA in REPLY message per
RFC3315 18.2.1:

   If the server cannot assign any addresses to an IA in the message
   from the client, the server MUST include the IA in the Reply message
   with no addresses in the IA and a Status Code option in the IA
   containing status code NoAddrsAvail.

So, I've changed the logic to skip IA completely from ADVERTISE messages and
to add NoAddrsAvail subcode into IA of REPLY messages.

As for overhead, yes, I believe it's ok to return NoAddrsAvail twice in IA
and in global section for compatibility with all old and new clients.
2014-10-06 14:34:24 +01:00
Tomas Hozza
3d9d2dd001 Fit example conf file typo. 2014-10-06 10:46:48 +01:00
Daniel Collins
17b475912f Fix typo in new Dbus code.
Simon's fault.
2014-10-03 21:58:43 +01:00
Karl Vogel
e9828b6f66 Set conntrack mark before connect() call.
SO_MARK has to be done before issuing the connect() call on the
TCP socket.
2014-10-03 21:45:15 +01:00
Simon Kelley
72eba2bffc Bump Debian version. 2014-10-03 08:50:37 +01:00
Simon Kelley
6ac3bc0452 Debian build fixes for kFreeBSD 2014-10-03 08:48:11 +01:00
Simon Kelley
00cd9d5519 crash at startup when an empty suffix is supplied to --conf-dir 2014-10-02 21:44:21 +01:00
Simon Kelley
f2658275b2 Add newline at the end of example config file. 2014-09-25 21:51:25 +01:00
Jan Psota
25e27235dd Update Polish translation. 2014-09-23 22:16:15 +01:00
Simon Kelley
bf2db4b084 Fix CHANGELOG entry under wrong version. 2014-09-18 22:10:46 +01:00
Simon Kelley
5782649ad9 Fix bug which caused dnsmasq to become unresponsive when an interface goes. 2014-09-18 22:08:58 +01:00
Simon Kelley
288df49c96 Fix bug when resulted in NXDOMAIN answers instead of NODATA.
check_for_local_domain() was broken due to new code matching F_*
bits in cache entries for DNSSEC. Because F_DNSKEY | F_DS is
used to match RRSIG entries, cache_find_by_name() insists on an exact match
of those bits. So adding F_DS to the bits that check_for_local_domain()
sends to cache_find_by_name() won't result in DS records as well
as the others, it results in only DS records. Add a new bit, F_NSIGMATCH
which suitably changes the behaviour of cache_find_by_name().
2014-09-18 21:55:27 +01:00
Richard Genoud
10cfc0ddb3 Fix length->netmask conversions to avoid undefined behaviour. 2014-09-17 21:17:39 +01:00
Richard Genoud
15b1b7e9c3 Fix endian bug in --local-service code. 2014-09-17 21:12:00 +01:00
Simon Kelley
00c0f69aa5 Debian bug closure. 2014-09-16 11:22:33 +01:00
Ilya Ponetaev
51943369e3 Supply "Success" status code in reply to DHCPDECLINE. 2014-09-13 21:19:01 +01:00
Ilya Ponetaev
2d75f2e4a5 Don't reply to DHCPCONFIRM messages with no addresses in them. 2014-09-13 21:11:16 +01:00
Ilya Ponetaev
976afc93e4 Set DHCPv6 message type when returning "use multicast". 2014-09-13 20:56:14 +01:00
Ilya Ponetaev
7f68f82146 DHCPv6 REBIND messages don't need a server-id. 2014-09-13 20:52:27 +01:00
Simon Kelley
85900a246c Revert route-information option in RA. There are problems with some clients.
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2014q3/008796.html
2014-09-13 20:42:54 +01:00
Simon Kelley
b4f971a081 Update *.po files for new release. 2014-09-13 20:28:30 +01:00
Simon Kelley
3e1551a1de Extend --conf-dir to allow filtering on file suffixes. 2014-09-09 21:46:07 +01:00
Simon Kelley
af292dae6d Bump Debian standards version. 2014-09-09 16:01:49 +01:00
Simon Kelley
933878f2c8 Remove paypal links and icond refs from Debian package. 2014-09-09 15:59:32 +01:00
Simon Kelley
d54409dcd3 Fix debian changelog date snafu. 2014-09-09 14:06:13 +01:00
Ilya Ponetaev
5bf50af2d0 RFC4191 route information option. 2014-09-09 12:46:21 +01:00
Simon Kelley
c43b8a6326 Debian package: use dns-root-data. 2014-09-07 19:34:39 +01:00
Simon Danner
b06900d1a3 Mention name in systemd. 2014-08-18 22:19:50 +01:00
Simon Kelley
f2f02fc3fb Merge branch 'loop' 2014-08-12 18:41:24 +01:00
Simon Kelley
aaeea9f6ed GetLoopServers Dbus method. 2014-08-12 18:30:44 +01:00
Simon Kelley
2bb6f7735f Missed update of DHCP lease datastructure. 2014-08-06 10:16:32 +01:00
Simon Kelley
40766e55e8 Check all servers loopiness, when any subset is changed. 2014-07-29 16:52:00 +01:00
Simon Kelley
b5ea1cc255 Add --dns-loop-detect feature. 2014-07-29 16:34:14 +01:00
Simon Kelley
6d8e8ac0fa Tidy up previous commit. 2014-07-13 22:18:57 +01:00
Simon Kelley
24b167ada8 Fix logic for associating leases with interfaces.
This handles the case that more than one interface contains
the network the lease address is on, but the interfaces have different
prefix lengths. Use the longest prefix length.
2014-07-12 16:39:00 +01:00
Chen Yufei
993f8cbb1b Don't do IPSET on Apple. Needed header files are missing. 2014-07-08 22:40:03 +01:00
Simon Kelley
47a9516980 Use event system to re-send query on new route. Tidies module boundaries. 2014-07-08 22:22:02 +01:00
Lung-Pin Chang
dc8a1b1bcf Set interface with longest prefix in DHCP & DHCPv6 lease
- With nested prefixes reside on different interfaces of single host

  (e.g., in 6to4, 2002::/16 on WAN and 2002:<IPv4>:<subnet>::/64 on LAN),

  current matching mechanism might return the interface with shorter prefix

  length instead of the longer one, if it appears later in the netlink message.

Signed-off-by: Lung-Pin Chang <changlp@cs.nctu.edu.tw>
2014-07-06 21:08:47 +08:00
Simon Kelley
cdb755c5f1 Fix FTBFS with Nettle-3.0. 2014-06-18 20:52:53 +01:00
Simon Kelley
063efb330a Build config: add -DNO_GMP for use with nettle/mini-gmp 2014-06-17 19:49:31 +01:00
Neil Jerram
70772c9091 Allow wildcard aliases in --bridge-interface option
This is useful when using dnsmasq as DHCP server for a set of VMs
whose data is routed by the host instead of being bridged.  In this
scenario:

- There is an unbounded set of TAP interfaces that have no IP address
  at the host end.

- DHCP allocation is done from an IPv4 address range associated with a
  dummy interface.

- We run dnsmasq with --interface dummy --interface tap*
  --bind-dynamic, so that it listens on all the TAP interfaces, and
  --bridge-interface=dummy,tap*, so that it will allocate IP addresses
  via the TAP interfaces from the range associated with the dummy
  interface.
2014-06-11 21:22:40 +01:00
Simon Kelley
10d8540f62 Makefile typo. 2014-06-11 20:51:27 +01:00
Simon Kelley
006c162382 Fix bug when >1 IPv6 address supplied to Dbus SetServers method. 2014-06-08 21:51:29 +01:00
Simon Kelley
6799a46605 Attribution update. 2014-06-07 21:23:34 +01:00
Daniel Collins
c4638f9e66 New DBus methods. 2014-06-07 21:21:44 +01:00
Simon Kelley
4b34f5d22f Copyright update. 2014-06-07 20:05:08 +01:00
Simon Kelley
a0358e5ddb Handle async notification of address changes using the event system. 2014-06-07 13:38:48 +01:00
Simon Kelley
a03f8d4c37 Suppress re-entrant calls to dhcp_construct_contexts() 2014-06-05 22:38:53 +01:00
Simon Kelley
c4a0937683 ipsets equivalent in *BSD, using pf tables. 2014-06-02 20:30:07 +01:00
Simon Kelley
2f4c4b6076 LOG error of ARP-injection fails. 2014-05-23 20:44:59 +01:00
Simon Kelley
a008a843cf Bump Debian version. 2014-05-20 21:01:34 +01:00
Simon Kelley
d92c53e700 Debian: Dynamically create /var/run/dnsmasq when systemd in use too. 2014-05-20 21:00:02 +01:00
Simon Kelley
a754e1d7b2 Debian: Write pid-file in the correct place when using systemd. 2014-05-20 20:56:55 +01:00
Simon Kelley
8e9ffba66e Merge branch 'mobile-ra'
Conflicts:
	CHANGELOG
2014-05-20 20:38:25 +01:00
Simon Kelley
15a97ad6fb Use ECC crypto in Nettle now. 2014-05-20 20:34:41 +01:00
Simon Ruderich
91f4a5e4b5 Debian/rules fixes to enable hardening. 2014-05-20 20:34:00 +01:00
Simon Kelley
0fa7e62947 Bump Debian version. 2014-05-20 19:54:25 +01:00
Andreas Metzler
62f992f06c Debian fix: Enable dnsmasq systemd unit on install. 2014-05-11 17:53:54 +01:00
Simon Kelley
a23949d44d Debian change: write pid-file even using systemd. 2014-05-11 17:43:29 +01:00
Simon Kelley
b692f23466 Fix DNS failure of cachesize set to zero. 2014-05-09 10:29:43 +01:00
Simon Kelley
8aa999ef69 Debian packaging fixes. 2014-05-04 21:45:26 +01:00
Conrad Kostecki
20b215f293 Update German translation. 2014-05-04 20:43:49 +01:00
Simon Kelley
e6096e643a Another filter_rrsigs fix. 2014-05-01 18:19:12 +01:00
Simon Kelley
8938ae05ac Get packet size right when removing pseudoheader. 2014-05-01 17:46:25 +01:00
Simon Kelley
9d1b22aac2 Fix DNSSEC validation of ANY queries. 2014-04-29 13:02:41 +01:00
Simon Kelley
1fc02680af Do SERVFAIL, therefore continue when searching for DS in TCP path too. 2014-04-29 12:30:18 +01:00
Simon Kelley
4872aa747b Handle SERVFAIL replies when looking for proven-nonexistence of DS. 2014-04-26 22:13:31 +01:00
Simon Kelley
7ea3d3fdca ra-advrouter mode for RFC-3775 mobile IPv6 support. 2014-04-25 22:04:05 +01:00
Simon Kelley
50f86ce8e4 Need to fixup records in the additional section when removing DNSSEC stuff. 2014-04-24 17:59:58 +01:00
Simon Kelley
7e22cf28f8 Update doc.html - was positively antediluvian. 2014-04-24 12:05:33 +01:00
Simon Kelley
3b1b3e9d50 CHANGELOG update for 2.70 release. 2014-04-23 15:46:05 +01:00
Simon Kelley
ab72091de2 Bump Debian version. 2014-04-23 15:14:48 +01:00
Matt Comben
66f57867d8 Typo. 2014-04-23 12:28:04 +01:00
Simon Kelley
6375838445 Fix crash on TCP DNS request when DNSSEC not enabled. 2014-04-16 22:20:55 +01:00
Simon Kelley
82a14af5e7 Ensure request name in buffer for ipset lookup. 2014-04-13 20:48:57 +01:00
Simon Kelley
97dce08ed7 Add donate button to doc.html. 2014-04-11 19:05:54 +01:00
Simon Kelley
198d940af6 Update CHANGELOG/release-notes. 2014-04-09 20:36:53 +01:00
Lutz Preßler
1d7e0a36e3 ipv6.arpa -> ip6.arpa 2014-04-07 22:06:23 +01:00
Simon Kelley
10068600f8 Fix NXDOMAIN RCODE in auth PTR replies. 2014-04-03 21:16:40 +01:00
Simon Kelley
b7639d5815 Fix ipsets logging patch. 2014-03-29 09:20:07 +00:00
Wang Jian
49752b90d5 Log IPSET actions. 2014-03-28 20:52:47 +00:00
Simon Kelley
e98bd52e25 Add --dnssec-no-timecheck 2014-03-28 20:41:23 +00:00
Simon Kelley
8a8bbad0cf Ensure ->sentto is valid for DNSSEC forwards. Otherwise retries SEGV. 2014-03-27 22:02:17 +00:00
Simon Kelley
fec216df32 Cache stats availble in CHAOS .bind domain. 2014-03-27 20:54:34 +00:00
Simon Kelley
4e1fe44428 Terminate DS-search when reaching the root via cache entries. 2014-03-26 12:24:19 +00:00
Simon Kelley
51967f9807 SERVFAIL is an expected error return, don't try all servers. 2014-03-25 21:07:00 +00:00
Tomas Hozza
b37f8b99ae Handle failure of hash_questions() 2014-03-25 20:52:28 +00:00
Tomas Hozza
fc2833f172 Memory leak in error path. 2014-03-25 20:43:21 +00:00
Simon Kelley
490f90758d Reorder sanity checks on UDP packet reception, to cope with failed recvfrom() 2014-03-24 22:04:42 +00:00
Simon Kelley
56618c31f6 Add dnssec-check-unsigned to example config file. 2014-03-24 21:13:49 +00:00
Simon Kelley
604f7598c2 CHANGELOG update. 2014-03-22 19:33:43 +00:00
Simon Kelley
2a7a2b84ec Ignore DNS queries from port 0: http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html 2014-03-22 19:18:06 +00:00
Andy
3e21a1a6fa Tidy uid defines. 2014-03-22 19:10:07 +00:00
Simon Kelley
2b29191e7c Fix DNSSEC crash retrying to IPv6 server. 2014-03-21 11:13:55 +00:00
Simon Kelley
03431d6373 Initialise uid when creating CNAME cache record. 2014-03-20 16:25:43 +00:00
Simon Kelley
cc1a29e250 Make --quiet-dhcp apply to DHCPDISCOVER when client ignored. 2014-03-20 15:47:18 +00:00
Moritz Warning
e62e9b6187 Manpage typos. 2014-03-20 15:32:22 +00:00
Simon Kelley
19c51cfa49 Tidy and fix cache->uid handling.
Some CNAMES left the value of ->uid undefined.

Since there are now special values if this, for CNAMES
to interface names, that could cause a crash
if the undefined value hit the special value.

Also ensure that the special value can't arise
when the uid is encoding the source of an F_CONFIG
record, in case there's a CNAME to it.
2014-03-18 22:38:30 +00:00
Andy
d5082158ee Ensure next_uid() can never return 0. 2014-03-17 19:50:29 +00:00
Simon Kelley
3f7483e816 Handle integer overflow in uid counter. Fixes rare crashes in cache code. 2014-03-16 22:56:58 +00:00
Simon Kelley
0c8584eabc Warn about non-local queries once only for UDP. 2014-03-12 20:12:56 +00:00
Simon Kelley
f00690f93e Typo 2014-03-12 20:07:12 +00:00
Simon Kelley
89b12ed35b OPT_LOCAL_SERVICE needs up-to-date interface list too. 2014-03-06 13:27:57 +00:00
Simon Kelley
1a9a3489ec Set --local-service in Debian package startup. 2014-03-05 15:01:08 +00:00
Simon Kelley
c8a80487cd --local-service. Default protection from DNS amplification attacks. 2014-03-05 14:29:54 +00:00
Simon Kelley
4ea8e80dd9 Add --static to pkg-config command when appropriate. 2014-03-05 11:01:23 +00:00
Simon Kelley
c07d30dcb1 Compiler warning. 2014-03-03 14:19:19 +00:00
Simon Kelley
d588ab54d4 Man page updates for DNSSEC. 2014-03-02 14:30:05 +00:00
Simon Kelley
f8b422a7b6 KEYBLOCK LEN better as a multiple of 8. 2014-03-02 12:46:51 +00:00
Simon Kelley
29fe922b14 Can have local DS records (trust anchors). 2014-03-01 22:53:57 +00:00
Simon Kelley
8707019237 Mass edit of INSECURE->BOGUS returns for server failure/bad input. 2014-03-01 20:48:24 +00:00
Simon Kelley
d1fbb77e0f Don't cache secure replies which we've messsed with. 2014-03-01 20:08:58 +00:00
Simon Kelley
1fbe4d2f5f Tweak tuning params. 2014-03-01 20:03:47 +00:00
Simon Kelley
0575610fa1 Handle replies with no answers and no NS in validate_reply. 2014-03-01 18:07:57 +00:00
Simon Kelley
e3f1455850 Don't free blockdata for negative DS cache entries. 2014-03-01 17:58:28 +00:00
Simon Kelley
bd9b3cf55b Fix off-by-one overwrite. 2014-03-01 16:12:28 +00:00
Simon Kelley
14db4212ab Tidy. 2014-03-01 15:35:50 +00:00
Simon Kelley
00a5b5d477 Check that unsigned replies come from unsigned zones if --dnssec-check-unsigned set. 2014-02-28 18:10:55 +00:00
Simon Kelley
b8eac19177 Negative caching for DS records. 2014-02-27 14:30:03 +00:00
Simon Kelley
b47b04c846 Return INSECURE when validation fails with proved non-existent DS. 2014-02-25 23:13:28 +00:00
Simon Kelley
613ad15d02 Strip DNSSEC RRs when query doesn't have DO bit set. 2014-02-25 23:02:28 +00:00
Simon Kelley
24187530fb Speeling. 2014-02-24 21:46:44 +00:00
Simon Kelley
a857daa351 Code cleanup. 2014-02-24 21:01:09 +00:00
Simon Kelley
f01d7be6c6 An NSEC record cannot attest to its own non-existance! 2014-02-24 20:20:00 +00:00
Simon Kelley
d387380a25 Check signer name in RRSIGs. 2014-02-23 16:20:46 +00:00
Simon Kelley
f2e4c277c4 Bugfix for last commit. 2014-02-23 15:24:26 +00:00
Simon Kelley
5107ace14a NSEC3 validation. First pass. 2014-02-23 10:48:32 +00:00
Simon Kelley
7b1eae4f50 Add --servers-file option. 2014-02-20 13:43:28 +00:00
Simon Kelley
c152dc8492 Omit ECC from DNSSEC if nettle library is old. 2014-02-19 18:14:33 +00:00
Simon Kelley
7bcca0060f More server cleanup. 2014-02-19 17:45:17 +00:00
Simon Kelley
d68c2ca2b7 Cleanup of server reading code, preparation, for dynamic reading from files. 2014-02-18 22:30:30 +00:00
Simon Kelley
de73a497ca --rev-server option. Syntactic sugar for PTR queries. 2014-02-17 21:43:27 +00:00
Simon Kelley
e3ec15af10 Log BOGUS validation result when upstream sends SERVFAIL. 2014-02-13 16:56:30 +00:00
Simon Kelley
dac74312da TYpo. 2014-02-13 16:43:49 +00:00
Simon Kelley
2ecd9bd5c0 No CD in forwarded queries unless dnssec-debug for TCP too. 2014-02-13 16:42:02 +00:00
Simon Kelley
a0ab18f6eb Don't mess with the TTL of DNSSEC RRs. 2014-02-13 16:38:23 +00:00
Simon Kelley
ebe95a831f Add RFC-6605 ECDSA DNSSEC verification. 2014-02-13 14:56:10 +00:00
Simon Kelley
ee4158678a Use DS records as trust anchors, not DNSKEYs.
This allows us to query for the root zone DNSKEY RRset and validate
it, thus automatically handling KSK rollover.
2014-02-11 11:07:22 +00:00
Simon Kelley
83349b8aa4 Further tidying of AD and DO bit handling. 2014-02-10 21:02:01 +00:00
Simon Kelley
7fa836e105 Handle validation when more one key is needed. 2014-02-10 20:11:24 +00:00
Simon Kelley
1633e30834 Fix Byte-order botch: broke DNSSEC on big-endian platforms. 2014-02-10 16:42:46 +00:00
Simon Kelley
c8ca33f810 Fix DNSSEC caching problems: incomplete RRSIG RRsets. 2014-02-10 10:35:42 +00:00
Simon Kelley
e243c072b5 AD bit in queries handled as RFC6840 p5.7 2014-02-06 18:14:09 +00:00
Simon Kelley
da4f372271 Add trust-anchors file to Debian package. 2014-02-06 15:21:37 +00:00
Simon Kelley
610e782a29 Fix stack-smashing crash in DNSSEC. Thanks to Henk Jan Agteresch. 2014-02-06 14:45:17 +00:00
Simon Kelley
854cf26907 DNSSEC config in example file. 2014-02-06 12:07:10 +00:00
Simon Kelley
bb201c211a Protect against malicious DNS replies with very large RRsets. 2014-02-06 12:01:05 +00:00
Simon Kelley
12fae49fff Make RR work when returning A/AAAA records and an RRSIG. 2014-02-04 22:03:06 +00:00
Jesse Glick
fd372273bd Updated version of contrib/try-all-ns 2014-02-04 20:20:35 +00:00
Simon Kelley
b98d22c191 Linking stuff. Latest Debian/Ubuntu don't automatically link gmp. 2014-02-04 18:09:30 +00:00
Simon Kelley
160f6507c3 Make DNSEC default, add build-depends for same, bump version. 2014-02-04 16:49:41 +00:00
Simon Kelley
613d6c5249 CHANGLEOG for DNSSEC. 2014-02-04 11:50:11 +00:00
Simon Kelley
81a883fda3 Format tweak. 2014-02-03 21:17:04 +00:00
Simon Kelley
40b695c1f1 Log NXDOMAIN correctly. 2014-02-03 17:07:51 +00:00
Simon Kelley
5f938534a9 Return configured DNSKEYs even though we don't have RRSIGS for them. 2014-02-03 16:44:32 +00:00
Simon Kelley
8d718cbb3e Nasty cache failure and memory leak with DNSSEC. 2014-02-03 16:27:37 +00:00
Simon Kelley
f6a2b79310 Validate Ooops. 2014-02-01 14:54:26 +00:00
Simon Kelley
82e3f45a9f Blockdata fixes and tuning. 2014-01-31 21:05:48 +00:00
Simon Kelley
072e81b3c5 Blockdata leak. 2014-01-31 12:42:54 +00:00
Simon Kelley
1d97ac4fd2 copy-n-paste error. 2014-01-31 11:12:27 +00:00
Simon Kelley
db73746620 Anounce DNSSEC at startup. 2014-01-31 10:32:45 +00:00
Simon Kelley
97bc798b05 Init ->dependent field in frec allocation. 2014-01-31 10:19:52 +00:00
Simon Kelley
edc231bc58 Compiler warning. 2014-01-31 09:52:50 +00:00
Simon Kelley
b85e092e23 Add a file containing current root trust anchors, for convenience. 2014-01-30 09:49:28 +00:00
Simon Kelley
583043f527 Crash in cache code when compiled with HAVE_DNSSEC. 2014-01-28 14:54:46 +00:00
Simon Kelley
8f6213cce9 Allow use of COPTS in Debian rules invokation for nefarious purposes. 2014-01-28 11:16:49 +00:00
Simon Kelley
00ec693db8 Debian package with DNSSEC now possible.
DNSSEC will eventually become opt-out and when that happens
I'll add libnettle build-depends. For now, build with

fakeroot debian/rules DEB_BUILD_OPTIONS=usednssec

to get DNSSEC support.
2014-01-28 11:08:57 +00:00
Simon Kelley
70b4a818ef Man page entries for DNSSEC flags. 2014-01-27 22:38:48 +00:00
Simon Kelley
7c28612a59 Trivial format fix. 2014-01-27 21:38:11 +00:00
Simon Kelley
6f4681034e Code tidy. 2014-01-26 23:39:17 +00:00
Simon Kelley
6938f3476e Don't mark answers as DNSEC validated if DNS-doctored. 2014-01-26 22:47:39 +00:00
Simon Kelley
17fb9ea763 Exclude CRC code in DNSSEC build - replaced with SHA1. 2014-01-26 09:36:54 +00:00
Simon Kelley
7d23a66ff0 Remove --dnssec-permissive, pointless if we don't set CD upstream. 2014-01-26 09:33:21 +00:00
Simon Kelley
703c7ff429 Fix to last commit. 2014-01-25 23:46:23 +00:00
Simon Kelley
8a9be9e493 Replace CRC32 with SHA1 for spoof detection in DNSSEC builds. 2014-01-25 23:17:21 +00:00
Simon Kelley
c92f0083a2 Get AA flag right in DNSSEC answers from cache. 2014-01-25 18:43:59 +00:00
Simon Kelley
b5dbfd142a RRSIG answer logging. 2014-01-25 18:19:51 +00:00
Simon Kelley
cbf13a2a6d Class specifier in --dnskey, instead of hardwiring C_IN. 2014-01-25 17:59:14 +00:00
Simon Kelley
5b3bf92101 --dnssec-debug 2014-01-25 17:03:07 +00:00
Simon Kelley
0744ca66ad More DNSSEC caching logic, and avoid repeated validation of DS/DNSKEY 2014-01-25 16:40:15 +00:00
Simon Kelley
2d33bda2e6 RRSIGS for PTR records from cache. 2014-01-24 22:37:25 +00:00
Simon Kelley
32f90c0fad Tweak. 2014-01-24 10:37:36 +00:00
Simon Kelley
bce6e1bc6d RRSIGs in DS and DNSKEY cached answers. 2014-01-23 22:02:19 +00:00
Simon Kelley
824202ef54 More DNSSEC cache readout. 2014-01-23 20:59:46 +00:00
Simon Kelley
9ebfca1e84 Compiler warning. 2014-01-23 12:11:43 +00:00
Simon Kelley
6429e421b3 Compiler warning. 2014-01-23 12:09:36 +00:00
Simon Kelley
c9bfa948c3 remove redundant headerage 2014-01-22 22:32:33 +00:00
Simon Kelley
e7829aefd8 Cache RRSIGS. 2014-01-22 22:21:51 +00:00
Simon Kelley
51ea3ca254 Caching of DNSSEC records. 2014-01-22 19:31:38 +00:00
Jonas Gorski
57ab36e77d Tweak definition of a permanent IPv6 address on Linux.
The linux kernel treats all addresses with a limited lifetime as being
non permanent, but when taking over the prefix livetimes from
upstream assigned prefixes through DHCP, addresses will always have a limited
lifetime.

Still reject temporary addresses, as they indicate autoconfigured
interfaces.

Contributed by T-Labs, Deutsche Telekom Innovation Laboratories

Signed-off-by: Jonas Gorski<jogo@openwrt.org>
2014-01-22 11:34:16 +00:00
Simon Kelley
dd0e0a3995 Handle time_t wraparound more sanely. 2014-01-22 11:16:59 +00:00
Simon Kelley
6fd6dacb39 Fix loop in RR sort. 2014-01-21 20:17:40 +00:00
Simon Kelley
39048ad10b bug fix, avoids infinite loop in forwarding code. 2014-01-21 17:33:58 +00:00
Simon Kelley
979cdf9b64 Fix to hostname_cmp, and update to canonicalisation table. RFC 4034 LIES. 2014-01-21 16:26:41 +00:00
Simon Kelley
dbf721235b Rationalise hostname_cmp() 2014-01-21 14:28:02 +00:00
Simon Kelley
c979fa04a4 Provide for static library linking. 2014-01-21 13:45:17 +00:00
Simon Kelley
c5f4ec7d23 NSEC proof-of-non-existence. 2014-01-20 22:37:55 +00:00
Simon Kelley
5d3b87a484 Better handling of truncated DNSSEC replies. 2014-01-20 11:57:23 +00:00
Simon Kelley
72ae2f3d56 Don't validate error returns. 2014-01-19 09:54:16 +00:00
Simon Kelley
6c0cb858c1 Trivial format fix 2014-01-17 14:40:46 +00:00
Simon Kelley
e0c0ad3b5e UDP retries for DNSSEC 2014-01-16 22:42:07 +00:00
Simon Kelley
4619d94622 Fix SEGV and failure to validate on x86_64. 2014-01-16 19:53:06 +00:00
Simon Kelley
0975a58e9b Merge branch 'master' of ssh://central/var/cache/git/dnsmasq 2014-01-15 17:12:08 +00:00
Simon Kelley
a25720a34a protocol handling for DNSSEC 2014-01-14 23:13:55 +00:00
Simon Kelley
cc111e0bab Add ip6addr.h to Makefile list. 2014-01-13 21:38:19 +00:00
Simon Kelley
86bec2d399 Swap crypto library from openSSL to nettle. 2014-01-13 21:31:20 +00:00
Simon Kelley
a59ff5f3df Merge branch 'master' of ssh://central/var/cache/git/dnsmasq 2014-01-12 22:36:12 +00:00
Simon Kelley
c3a04081ff [fd00::} and [fe80::] special addresses in DHCPv6 options. 2014-01-11 22:18:19 +00:00
Simon Kelley
ae76242fdf Fix missing RA RDNS option with --dhcp-option=option6:23,[::] 2014-01-10 18:15:16 +00:00
Simon Kelley
4f04476e3b Set AD bit for address replies from /etc/hosts &c 2014-01-10 12:20:38 +00:00
Simon Kelley
1486a9c7f2 Furthet tweak to RRset sort. 2014-01-10 11:44:26 +00:00
Simon Kelley
5ada888507 RFC 4035 5.3.2 wildcard label rules. 2014-01-09 22:25:03 +00:00
Simon Kelley
5f8e58f49b DNSSEC consolidation. 2014-01-09 17:31:19 +00:00
Simon Kelley
b8071a849a Tweak blockdata accounting. 2014-01-09 09:41:33 +00:00
Simon Kelley
b6e9e7c32d Handle digest lengths greater than 1 block. 2014-01-08 21:21:20 +00:00
Simon Kelley
0435d041ea AD into cache fixes. 2014-01-08 18:22:37 +00:00
Simon Kelley
795501bc86 AD bit handling when doing validation. 2014-01-08 18:11:55 +00:00
Simon Kelley
c2207688c0 Memory stats for DNSSEC. 2014-01-08 18:04:20 +00:00
Simon Kelley
98c098bfc7 Move blockdata to it's own file. 2014-01-08 17:31:16 +00:00
Simon Kelley
c47e3ba446 Update copyright for 2014. 2014-01-08 17:07:54 +00:00
Simon Kelley
f1668d2786 New source port for DNSSEC-originated queries. 2014-01-08 16:53:27 +00:00
Simon Kelley
7d7b7b31e5 DNSSEC for TCP queries. 2014-01-08 15:57:36 +00:00
Simon Kelley
3ddacb86e9 Ensure cache is big enough to do DNSSEC. 2014-01-08 14:32:03 +00:00
Simon Kelley
60b68069cf Rationalise DNS packet-buffer size calculations. 2014-01-08 12:10:28 +00:00
Simon Kelley
871417d45d Handle truncated replies in DNSSEC validation. 2014-01-08 11:22:32 +00:00
Simon Kelley
65d1e3bb9b Tweak libraries and make DNSSEC compile optional. 2014-01-08 11:00:01 +00:00
Simon Kelley
0fc2f31368 First functional DNSSEC - highly alpha. 2014-01-08 10:26:58 +00:00
Simon Kelley
c3e0b9b6e7 backup 2013-12-31 13:50:39 +00:00
Simon Kelley
6ea1f23b3f Send correct O and M bits when advertising only deprecated prefixes. 2013-12-19 15:45:12 +00:00
Simon Kelley
963c380d13 Merge branch 'master' into dnssec 2013-12-18 17:45:31 +00:00
Simon Kelley
00238fb019 indentation fix. 2013-12-18 13:24:12 +00:00
Simon Kelley
74e6b52011 Typo in contributor name. Sorry. 2013-12-17 21:33:53 +00:00
Simon Kelley
875b8160f6 Remove unused code. 2013-12-17 17:40:32 +00:00
Simon Kelley
76ff440ebe Ignore ",," in dhcp-host, rather than treating it as ",0," 2013-12-17 16:29:14 +00:00
Simon Kelley
8db957dfbf Fix endless loop with some bogu-nxdomain. Another F_CONFIG botch. 2013-12-17 15:47:10 +00:00
Simon Kelley
9d633048fe Saving progress 2013-12-13 15:36:55 +00:00
Simon Kelley
a9b55837dc Merge branch 'master' into dnssec 2013-12-12 14:53:46 +00:00
Simon Kelley
c352dd8f1a Merge branch 'master' into dnssec 2013-12-12 12:16:17 +00:00
Simon Kelley
3a2371527f Commit to allow master merge. 2013-12-12 12:15:50 +00:00
Simon Kelley
1ee9be4c3f Implement dynamic interface discovery on *BSD 2013-12-09 16:50:19 +00:00
Simon Kelley
56ad6c9be1 Bump debian version. 2013-12-08 15:58:29 +00:00
Jan Psota
fa04c83d86 Update Polish translation. 2013-12-08 15:43:03 +00:00
Vladislav Grishenko
4c82efc5ac Relax rules in prefix length in (IPv6) dhcp-range. 2013-12-03 16:05:30 +00:00
Simon Kelley
5f45d6a715 Update Debian changelog. 2013-12-03 13:43:56 +00:00
Simon Kelley
2329bef5ba Check arrival interface of IPv6 requests, even in --bind-interfaces. 2013-12-03 13:41:16 +00:00
Simon Kelley
62ab3ccd3d Only set scope_id in addresses to bind() for linklocal addresses.
FreeBSD complains otherwise.
2013-12-03 11:53:53 +00:00
Matthias Andree
71aaa5a791 Fix previous errno saving fix. 2013-12-03 11:20:45 +00:00
Simon Kelley
08619211f8 Garbage collect listening sockets when their address is deleted.
In --bind-dynamic mode, stop listening on an address when it's
removed from an interface. 6rd and 6to4 tunnels can go through
lots of addresses.
2013-12-02 14:43:48 +00:00
Simon Kelley
3dffbc3ebf Don't overwrite errno before generating message. 2013-12-02 13:22:37 +00:00
Simon Kelley
0d6eb134f5 Do immediate RA when a prefix goes from old->current. 2013-11-26 13:30:12 +00:00
Vladislav Grishenko
50db3492e2 Fix compiler warning. 2013-11-26 11:09:31 +00:00
Vladislav Grishenko
3b19596122 Fix compiler warnings. 2013-11-26 11:08:21 +00:00
Vladislav Grishenko
d082faf3e4 Fix compiler warning. 2013-11-26 11:04:24 +00:00
Vladislav Grishenko
99e8891f85 Fix compiler warning. 2013-11-26 11:02:29 +00:00
Simon Kelley
532066ee2d Add missing malloc() return-code check. 2013-11-26 10:14:47 +00:00
Simon Kelley
254390644a Segfault with some CNAMEs. Also memory leak on reload of /etc/hosts. 2013-11-25 21:14:51 +00:00
Simon Kelley
241fa9c6c8 Remove arc4random, we have a good RNG and it's a portability problem. 2013-11-22 11:17:37 +00:00
Simon Kelley
e142a83296 Merge messages to .po files. 2013-11-22 10:38:55 +00:00
Simon Kelley
f7029f5c08 Extend /4 and /6 syntax to --interface-name 2013-11-21 15:10:02 +00:00
Simon Kelley
c50f25a3ea Allow empty subnet list in --auth-zone 2013-11-21 11:29:27 +00:00
Simon Kelley
65c9b48921 Merge branch 'master' into dnssec 2013-11-17 12:34:04 +00:00
Simon Kelley
f25e6c6d33 Support /4 and /6 suffixes in interface names in --auth-server 2013-11-17 12:23:42 +00:00
Simon Kelley
587ad4f271 Fix crash introduced in 376d48c7f1 2013-11-15 15:47:51 +00:00
Simon Kelley
4452292064 When advertising ONLY deleted IPv6 prefixes, set router lifetime to zero. 2013-11-15 14:45:04 +00:00
Simon Kelley
e597dba7ec Merge branch 'master' into dnssec 2013-11-15 11:29:21 +00:00
Simon Kelley
dd9d9ce54c Fix problems when advertising deleted IPv6 prefixes. 2013-11-15 11:24:00 +00:00
Simon Kelley
06e54b823e Merge branch 'master' into dnssec 2013-11-14 10:39:40 +00:00
Simon Kelley
32b4e4cb7c Auth-DNS manpage update. 2013-11-14 10:36:55 +00:00
Simon Kelley
376d48c7f1 Allow interface name to specify subnets in --auth-zone. 2013-11-13 13:04:30 +00:00
Simon Kelley
6586e8352a Use random address allocation for DHCPv6 temporary addresses. 2013-11-07 14:20:13 +00:00
Simon Kelley
3511a92869 Fix start-up order for making DHCPv6 DUID
Previously, if the DUID wasn't read from the lease-file or
script, a new one was created _after_ the helper process fork,
so for that first run, the script calls got an empty DUID.

Also, use a DUID_LL format DUID when there's no stable lease
storage, as well as when the RTC is broken. That has a chance of
evaluating to the same value on each startup.
2013-11-07 10:28:11 +00:00
Simon Kelley
44de649e5c Make private functions "static" 2013-11-06 11:36:57 +00:00
Brad Smith
29c122af83 Fix FTBFS on openBSD-current. 2013-11-04 14:11:18 +00:00
Simon Kelley
6dbdc972c4 Fix FTBFS on OS X >=10.7 Need to select a IPv6 sockopt API. 2013-10-28 14:22:57 +00:00
Simon Kelley
7b174c250d Fix check for local domains in CNAME case. Fixes d56a604a96 2013-10-28 13:14:03 +00:00
Jeremy Lavergne
50d7f721ee Fix FTBFS on MacOS 2013-10-28 11:26:30 +00:00
Simon Kelley
5a4120dbfb Merge branch 'master' into dnssec
Conflicts:
	src/dnsmasq.h
	src/forward.c
	src/option.c
2013-10-25 13:16:27 +01:00
Simon Kelley
eec5c1e21c Fix parsing of synth-domain=domain,addr,addr,prefix 2013-10-25 10:37:30 +01:00
Gildas
1f776a4aa2 Update French translation. 2013-10-25 10:05:22 +01:00
Kevin Darbyshire-Bryant
227ddad9b5 Fix logic botch in quiet-dhcp option. 2013-10-24 17:47:00 +01:00
Gildas
a9bf81ad91 Message typo. 2013-10-24 13:31:40 +01:00
Simon Kelley
6008bdbbc1 Fix botch in determining if auth query is local. 2013-10-21 21:47:03 +01:00
Simon Kelley
93bafe619d Fix CNAME botch in auth code, also set RA flag for local queries. 2013-10-21 21:19:34 +01:00
Simon Kelley
8ab91e9f7f Get NXDOMAIN right on non-A/AAAA query for name known via interface-name. 2013-10-21 20:50:04 +01:00
Simon Kelley
5731050062 Get NXDOMAIN right for local queries to auth zones. 2013-10-21 18:26:20 +01:00
Simon Kelley
fb63dd1345 Handle two interface-names, different interface, same name. 2013-10-21 18:19:35 +01:00
Simon Kelley
5f8002fcd7 Restore NS and SOA records to local auth queries. 2013-10-21 17:40:18 +01:00
Simon Kelley
19b1689161 Don't filter by subnet when handling local queries for auth-zones. 2013-10-20 10:19:39 +01:00
Simon Kelley
b485ed97aa Always answer queries for authoritative zones locally, never forward. 2013-10-18 22:00:39 +01:00
René van Dorst
53c4c5c859 Fix crash at startup when dhcp-host with client-ids is present. 2013-10-18 14:05:32 +01:00
Simon Kelley
dc27e148a1 Warning when using --bind-interfaces and routeable addresses. 2013-10-16 14:33:23 +01:00
Simon Kelley
45cca58592 Fix caching of dangling CNAMEs. 2013-10-15 10:20:13 +01:00
Simon Kelley
e136725c5b Remove RA_INTERVAL from config.h - it's configurable now. 2013-10-14 17:23:54 +01:00
Simon Kelley
486479e943 Check prefix length when contructing DHCP ranges. 2013-10-14 17:18:03 +01:00
Simon Kelley
3bb51da835 Fix d56a604a96 re ANY queries. 2013-10-14 14:20:34 +01:00
Simon Kelley
806cf78797 Better defaults for address and lifetime of RDNS option in RA. 2013-10-14 14:08:44 +01:00
Simon Kelley
3b3f441189 Log SO_BINDTODEVICE use at startup. 2013-10-11 16:33:28 +01:00
Simon Kelley
24b5a5d50b dhcp-host selection fix for v4/v6 2013-10-11 15:19:28 +01:00
Simon Kelley
d56a604a96 CNAMEs can now point to interface names. 2013-10-11 14:39:03 +01:00
Kevin Darbyshire-Bryant
8c0b73d3a8 Add --quiet-* options. 2013-10-11 11:56:33 +01:00
Simon Kelley
6bd3a09fb8 Merge branch 'edns0'
Conflicts:
	CHANGELOG
	src/dnsmasq.h
	src/option.c
2013-10-11 10:25:56 +01:00
Simon Kelley
f65b0e546b Add sponsorship details. 2013-10-11 10:19:01 +01:00
Simon Kelley
8584c502d3 Don't do bindtodevice if --interface option not given. 2013-10-10 21:15:23 +01:00
Simon Kelley
c3edf383ff Correct client subnet EDNS0 option number. 2013-10-10 21:09:15 +01:00
Simon Kelley
c4cd95df68 Add --ra-param and remove --force-fast-ra 2013-10-10 20:58:11 +01:00
Simon Kelley
ed4c0767b1 --add-subnet option. 2013-10-08 20:46:34 +01:00
Vic
043c271f8a Update Spanish translation. 2013-10-04 15:09:13 +01:00
Simon Kelley
d4da20f064 Unset environment variables to script when we have no value for them. 2013-10-04 10:12:49 +01:00
Simon Kelley
903650af67 Further fixes to DHCP logging. 2013-10-03 11:43:09 +01:00
Tanguy Bouzeloc
ef1d7425e3 Fix problem in DHCPv6 vendorclass/userclass matching code. 2013-10-03 11:06:31 +01:00
Simon Kelley
1d1c795601 Tweak tag->debian package version code so rc tags are later than test ones. 2013-10-02 14:52:23 +01:00
Simon Kelley
889d8a156f Update Polish translation. 2013-10-02 13:12:09 +01:00
Simon Kelley
b7f666ff09 Add *.po target to cannonicalise .po files received from translators. 2013-10-02 11:48:43 +01:00
Simon Kelley
e4e9b342a7 Cosmetic change to start-up logging of DHCPv6 configuration. 2013-10-02 11:03:39 +01:00
Simon Kelley
d5c35a59b0 Merge new messages into .po files. 2013-10-01 20:28:22 +01:00
Simon Kelley
2f9fd1dcc5 Fix FTBFS when NO_IPV6 defined. 2013-10-01 09:54:41 +01:00
Simon Kelley
8f3194f7ac Do multicast interface selection portably for router advertisements. 2013-09-30 15:04:58 +01:00
Simon Kelley
10bd29265b macscript: create file if it doesn't exist. 2013-09-27 21:07:30 +01:00
Simon Kelley
42b44a591b Add contrib/mactable 2013-09-27 14:38:45 +01:00
Simon Kelley
a810559b24 daemon->icmp6fd is always valid when doing DHCPv6 now. 2013-09-25 15:36:00 +01:00
Simon Kelley
861c89141a Change rules for constructing DHCPv6 ranges. 2013-09-25 15:30:30 +01:00
Simon Kelley
8939c95fd6 Don't extract MAC address from ND table when DHCPv6 request is from a relay. 2013-09-25 11:49:34 +01:00
Vladislav Grishenko
408c368fa5 Remove unused variable warnings when omitting stuff at compile-time. 2013-09-24 16:18:49 +01:00
Simon Kelley
b5d9a362b4 Fix TFTP script action, broken a few commits ago. 2013-09-24 09:44:33 +01:00
Simon Kelley
f1af2bb485 Big ugly refactor in rfc3315.c should be no behaviour changes. 2013-09-24 09:16:28 +01:00
Simon Kelley
1b55190d3f Fix FTBFS on OpenBSD. 2013-09-23 15:28:38 +01:00
Simon Kelley
f373a15b62 Ommit option-parsing code with NO_AUTH. 2013-09-23 12:47:47 +01:00
Simon Kelley
91543f4831 Fix FTBFS when various facilities omitted at compile time. 2013-09-23 12:41:20 +01:00
Simon Kelley
d81b42d067 Prod neighbour discovery with ARP instead of PING. 2013-09-23 12:26:34 +01:00
Simon Kelley
724789de13 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2013-09-21 14:07:58 +01:00
Simon Kelley
8f51a29137 Fix compiler warnings. 2013-09-21 14:07:12 +01:00
Simon Kelley
c845f6eda5 Fix compiler warnings. 2013-09-21 14:02:10 +01:00
Simon Kelley
89500e31f1 Support MAC addresses in dhcp-host and dhcp-mac for DHCPv6. 2013-09-20 16:29:20 +01:00
Simon Kelley
c8f2dd8b53 Cope with DHCPv6 REQUESTs without address options. 2013-09-13 11:22:55 +01:00
Simon Kelley
ceae52df15 Add "baseline" and "bloatcheck" makefile targets 2013-09-12 15:05:47 +01:00
Simon Kelley
c2d8d3ffc4 Debian packing. remove unwanted '-' in version number using gitversion. 2013-09-11 15:52:22 +01:00
Simon Kelley
aa985beeef Fix a couple of warnings in debian package build. 2013-09-11 10:28:39 +01:00
Simon Kelley
65e7912d31 Debian: depend on binary not source verions for dnsmasq-dnsmasq_base dependency. 2013-09-11 10:01:31 +01:00
Simon Kelley
02ed24d351 Add gitversion Debian build option. 2013-09-09 18:06:45 +01:00
Simon Kelley
6acef73052 Sponsorhip details in CHANGELOG. 2013-09-09 15:21:39 +01:00
Simon Kelley
10ae7b50f2 Don't use BINDTODEVICE on DHCP socket when relaying. 2013-09-05 20:08:01 +01:00
Simon Kelley
831b5ba12b Debian resolvconf script update. 2013-09-05 15:36:25 +01:00
Simon Kelley
0932f9c08b CHANGELOG update. 2013-09-05 11:30:30 +01:00
Simon Kelley
397542b213 Fix bug resulting in tight-loop when new interfaces arrive. 2013-09-05 11:27:34 +01:00
Simon Kelley
0c38719fe0 Don't crash with empty tag: in dhcp-range. 2013-09-05 10:21:12 +01:00
Simon Kelley
ff7eea27e7 Add --dhcp-relay config option. 2013-09-04 18:01:38 +01:00
Simon Kelley
687bac22db Tidy rebase 2013-08-20 15:41:26 +01:00
Giovanni Bajo
8d41ebd8a3 Add copyright banners 2013-08-20 15:41:26 +01:00
Giovanni Bajo
4631dbf68c DSA-NSEC3-SHA1 is an alias of DSA for signature verification. 2013-08-20 15:41:26 +01:00
Simon Kelley
4f9aefc753 Don't fight over namespace with re-implementation of strchrnul() 2013-08-20 15:41:26 +01:00
Giovanni Bajo
4b5287005f Again make errors greppable. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
5c32841934 Implement RSA-SHA512. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
ccd1d32c3a Make testsuite errors greppable. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
75ffc9bf15 Implement RSA-MD5. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
3af1ea8cbc Simplify abstraction of verification algorithms (it was too flexible) 2013-08-20 15:41:25 +01:00
Giovanni Bajo
1f0dc5835b Implement DSA-SHA1 verification algorithm. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
ed1fc98595 Untangle digestalg from verifyalg; better separation, less code duplication. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
b58fb39f24 Since extract_name() does not convert to lowercase, do it temporarly within convert_domain_to_wire(). 2013-08-20 15:41:25 +01:00
Giovanni Bajo
0304d28f7e Parse and match DS records. 2013-08-20 15:41:25 +01:00
Giovanni Bajo
f5adbb90a1 Implement digest algorithm support. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
32b826e2a0 Genericize verifyalg_add_data_domain() (rename to convert_domain_to_wire()). 2013-08-20 15:41:24 +01:00
Giovanni Bajo
0937692dc6 Add rdata description for MX. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
785ee80b93 Describe SOA rdata section. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
f119ed382e Simplify verifyalg_add_rdata() with new canonicalization functions. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
da23c4f960 Simplify rrset_canonical_order() with new canonicalization functions. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
4885d57c58 Add rdata canonicalization functions. 2013-08-20 15:41:24 +01:00
Giovanni Bajo
0db0e0c216 Fix a bug in rdlen update while decompressing a name 2013-08-20 15:41:24 +01:00
Giovanni Bajo
ec2962eacb Fix the macro names. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
0ca895f585 Fix rrset_canonical_order() to correct handle canonicalization of domain names in RDATA. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
6299ffbe60 Start refactoring for correct handling of domain wire-format.
Introduce utility functions and RDATA meta-description.
2013-08-20 15:41:23 +01:00
Giovanni Bajo
7f0485cf53 verifyalg_add_data_domain: fix for root domain (""). 2013-08-20 15:41:23 +01:00
Giovanni Bajo
02bff4f109 Implement RSASHA256. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
d1ca25ca7e Canonicalize NS records. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
23c2176681 Process RRSIGs also in authority and additional sections. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
e83297d0f6 RSASHA1-NSEC3-SHA1 is equivalent to RSASHA1 for the purpose of RRSIG validation. 2013-08-20 15:41:23 +01:00
Giovanni Bajo
41de7442d2 Reformat some code (no semantic difference). 2013-08-20 15:41:23 +01:00
Giovanni Bajo
0852d76b58 Start implementing canonicalization of RDATA wire formats. 2013-08-20 15:41:22 +01:00
Giovanni Bajo
a55ce08cc0 Silence a few warnings. 2013-08-20 15:41:22 +01:00
Giovanni Bajo
dd090561bf Convert to C-style comments. 2013-08-20 15:41:22 +01:00
Giovanni Bajo
28f04fd647 Remove unused variable. 2013-08-20 15:41:22 +01:00
Giovanni Bajo
50a96b62f1 Fix a validation bug when owner != signer.
Since owner and signer are both domain names and share the same
buffer in memory (daemon->namebuff), we need to go through a little
hoop to make sure one doesn't step on the other's toes. We don't
really need to extract the signer name until we have finished
calculating the hash of the RRset, so we postpone its extraction.
2013-08-20 15:41:22 +01:00
Giovanni Bajo
00b963ab72 Improve logging message. 2013-08-20 15:41:22 +01:00
Giovanni Bajo
79333a2498 Fix a bug in extract_name_no_compression.
When the maxlen was exactly equal to the length of the string,
the function was returning 0 because the end-of-buffer check was
misplaced.
2013-08-20 15:41:22 +01:00
Giovanni Bajo
32f82c62c8 Export skip_name function. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
4e076d746f Debug function. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
13e435ebca Bugfix: domain names must go through hash function in DNS format (but uncompressed!) 2013-08-20 15:41:21 +01:00
Giovanni Bajo
4b0eecbb44 Bugfix: rdata flags must go through hash function in network byte order. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
0360a524df Implement RSA verification. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
262ac85107 verify() function must take a keydata chained buffer for input key. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
4c70046d93 Move helper functions to common header file. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
458824dcb4 Helper function to walk through keydata chained blocks. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
a7338645d7 Add a FIXME for missing logic. 2013-08-20 15:41:21 +01:00
Giovanni Bajo
776fd04754 Add cast to silence warning. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
20bccd499f Rework the loop a little (no functionality changes) 2013-08-20 15:41:20 +01:00
Giovanni Bajo
708bcd2dd3 Call valg verify functions (unimplemented for now) 2013-08-20 15:41:20 +01:00
Giovanni Bajo
d0edff7d6e Insert all DNSKEY/DS records into cache in one transaction. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
ccca70cb33 Change some logging messages. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
0d829ebc69 Skip non-signing keys 2013-08-20 15:41:20 +01:00
Giovanni Bajo
4137b84e4e Postpone RRSIG processing after all DNSKEY/DS have been parsed. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
e6c2a670fe Before using a key for validation, also verify that algorithm matches. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
47f99dd2b3 Fix argument in dnssec_parsekey() call. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
6759b99e28 Add function to extract algorithm number from context. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
3471f18130 Start parsing DNSKEY records and insert them into cache. 2013-08-20 15:41:20 +01:00
Giovanni Bajo
2ef843dd16 extract_name_no_compression: strip trailing dot. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
ce2a0f5a6a Macros to simplify tentative parsing. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
adca3e9c4b Refactor to use new VerifyAlg context, and start implementing logic for querying DNSKEYs. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
366dfcb907 Explicitize the context of verification algorithm. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
28c625572b Move general macros in dnsmasq.h 2013-08-20 15:41:19 +01:00
Giovanni Bajo
02f9b76418 Rename key cache field. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
ba8badd6df Fix bug in keydata_alloc() 2013-08-20 15:41:19 +01:00
Giovanni Bajo
0decc869ae Fix rrset qsort comparison function. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
b573aebc09 Add skeleton for RSASHA256. 2013-08-20 15:41:19 +01:00
Giovanni Bajo
d31d057aa3 Remove useless endian-conversion after GETLONG(). 2013-08-20 15:41:18 +01:00
Giovanni Bajo
6445c8ed73 Fix off-by-one in iteration. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
382e38f494 Specify the correct place where to canonicalize RR within RRset. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
9940aba9f6 Initial openssl RSASHA1 implementation (only SHA1 for now). 2013-08-20 15:41:18 +01:00
Giovanni Bajo
7e846b9858 Add openssl support to build machinery. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
d322de0613 Further abstract API of verify crypto. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
b98f771519 Filter out invalid characters in domain names. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
c7a93f6e4e Skip trailing \0 in domain name. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
970ce22b68 Augment verify algorithm table. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
e292e93d35 Initial dnssec structure. 2013-08-20 15:41:18 +01:00
Giovanni Bajo
fa164d459f DNSSEC validation require EDNS0, force larger packet size. 2013-08-20 15:41:17 +01:00
Giovanni Bajo
f53c79c01b Externalize dns parsing functions. 2013-08-20 15:41:17 +01:00
Giovanni Bajo
7dbe193bee Add run-time options to activate dnssec validation. 2013-08-20 15:41:17 +01:00
Giovanni Bajo
a669f012dd Add dnssec RR types 2013-08-20 15:39:44 +01:00
Giovanni Bajo
237724c0c7 Rename existing DNSSEC macros into DNSSEC_PROXY. 2013-08-20 15:39:44 +01:00
Giovanni Bajo
53f84c7f62 Add compile-time macro for DNSSEC support. 2013-08-20 15:39:43 +01:00
Simon Kelley
6692a1a53f Fix dhcp-range sanity checking. 2013-08-20 14:41:31 +01:00
Simon Kelley
a37cd7aaf5 Use tags from pxe-proxy dhcp-range statements. 2013-08-20 10:33:32 +01:00
Vladislav Grishenko
e4cdbbf521 Allow prefix :: in constructed dhcp-range. 2013-08-19 16:20:31 +01:00
Vladislav Grishenko
4568a6f842 IFACE_PERMANENT interface flag in enumeration. 2013-08-19 16:07:07 +01:00
Simon Kelley
5c72bb9e33 Silence compiler warning. 2013-08-19 14:12:59 +01:00
Vladislav Grishenko
8c3bdb4ffc Add code to get IPv6 address lifetimes and flags for *BSD. 2013-08-19 14:04:38 +01:00
Simon Kelley
ffbad34b31 Set SOREUSEADDR as well as SOREUSEPORT on DHCP sockets when both available. 2013-08-14 15:53:57 +01:00
Simon Kelley
f086d39641 Debian package change: update resolvconf script. 2013-08-14 14:54:23 +01:00
Simon Kelley
cc4baaab0d Fix DHCPv6 lease time calculation when client sends VL==0 or PL==0 2013-08-05 15:03:44 +01:00
Simon Kelley
66409193dc Sanity check for dhcp-range template. 2013-08-01 20:19:32 +01:00
Simon Kelley
2937f8a040 Provide independent control over which interfaces get TFTP. 2013-07-29 19:49:07 +01:00
Simon Kelley
edf0bde0c6 Make --listen-address higher priority than --except-interface. 2013-07-29 17:21:48 +01:00
Simon Kelley
8d03046269 Add --force-fast-ra option. 2013-07-29 15:41:26 +01:00
Simon Kelley
9f48ffa1e8 Apply ceiling of configured dhcp-range leasetime to deprecated prefix adverts. 2013-07-28 15:47:04 +01:00
Simon Kelley
871d4562f1 Support RFC-4242 information-refresh-time. 2013-07-28 09:37:38 +01:00
Simon Kelley
0f371f9e1a Remove dead code. 2013-07-27 15:15:38 +01:00
Simon Kelley
6bd109aa2f Better job with domain for DHCPv6 information-request. 2013-07-27 15:11:44 +01:00
Simon Kelley
f7a40ec650 Tweak when old prefix returns. 2013-07-27 13:36:08 +01:00
Simon Kelley
ff1b41dc57 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq
Conflicts:
	CHANGELOG
2013-07-27 12:32:29 +01:00
Simon Kelley
fc4c4fda05 Fix MAC address enumeration on *BSD. 2013-07-26 15:38:59 +01:00
Simon Kelley
ef1a94abaa Advertise lost prefixes with pref_time == 0 for 2 hours. 2013-07-26 13:59:03 +01:00
Simon Kelley
d9fb0be8c7 Make --clear-on-reload apply to DBus API too. 2013-07-25 21:47:17 +01:00
Roy Marples
3f3adae6bc DHCP FQDN option tweaks. 2013-07-25 16:22:46 +01:00
Simon Kelley
1ecbaaa382 Tweak parameter lifetimes in Router advertisements. 2013-07-25 14:19:27 +01:00
Kyle Mestery
d859ca2f9b Allow hostnames to start with a number. 2013-07-24 13:17:54 +01:00
Simon Kelley
3953dcc7f2 Typo in name in CHANGELOG. 2013-07-03 20:40:45 +01:00
Simon Kelley
625ac28c61 Fix crash with empty DHCP string options. 2013-07-02 21:19:32 +01:00
Simon Kelley
b4b9308079 Increase timeout/number of retries in TFTP. 2013-06-19 10:31:23 +01:00
Simon Kelley
e2ba0df2d4 Don't BIND DHCP socket if more interfaces may come along later. 2013-05-31 17:04:25 +01:00
Simon Kelley
921360ce62 Add constructor-noauth: keyword 2013-05-31 14:07:22 +01:00
Simon Kelley
429805dbbc Allow constructed ranges from interface address at end of range.
Also make man page on this clearer, as it's been confusing many.
2013-05-31 13:47:26 +01:00
Marcelo Salhab Brogliato
0da5e8979b Log forwarding table overflows. 2013-05-31 11:49:06 +01:00
Simon Kelley
baa80ae512 Remove limit in prefix length in --auth-zone. 2013-05-29 16:32:07 +01:00
Simon Kelley
3e8ed78bf1 Fix option parsing for --dhcp-host. 2013-05-29 14:31:33 +01:00
Simon Kelley
48493329d6 Update Debian resolvconf script for dnscrypt-proxy integration. 2013-05-28 14:49:54 +01:00
Simon Kelley
76dd75de77 Fix hang from new interface-name code, when using TCP. 2013-05-23 10:04:25 +01:00
Simon Kelley
63fd27e35f Debian changelog update. 2013-05-20 11:50:33 +01:00
Simon Kelley
115ac3e4d7 Generalise --interface-name to cope with IPv6 addresses. 2013-05-20 11:28:32 +01:00
Simon Kelley
cfcad42ff1 Fix failure to start with ENOTSOCK 2013-05-17 11:32:03 +01:00
80 changed files with 22054 additions and 8329 deletions

3
.gitignore vendored
View File

@@ -2,7 +2,8 @@ src/*.o
src/*.mo
src/dnsmasq.pot
src/dnsmasq
src/.configured
src/dnsmasq_baseline
src/.copts_*
contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release
debian/base/

515
CHANGELOG
View File

@@ -1,3 +1,397 @@
version 2.74
Fix reversion in 2.73 where --conf-file would attempt to
read the default file, rather than no file.
Fix inotify code to handle dangling symlinks better and
not SEGV in some circumstances.
DNSSEC fix. In the case of a signed CNAME generated by a
wildcard which pointed to an unsigned domain, the wrong
status would be logged, and some necessary checks omitted.
version 2.73
Fix crash at startup when an empty suffix is supplied to
--conf-dir, also trivial memory leak. Thanks to
Tomas Hozza for spotting this.
Remove floor of 4096 on advertised EDNS0 packet size when
DNSSEC in use, the original rationale for this has long gone.
Thanks to Anders Kaseorg for spotting this.
Use inotify for checking on updates to /etc/resolv.conf and
friends under Linux. This fixes race conditions when the files are
updated rapidly and saves CPU by noy polling. To build
a binary that runs on old Linux kernels without inotify,
use make COPTS=-DNO_INOTIFY
Fix breakage of --domain=<domain>,<subnet>,local - only reverse
queries were intercepted. THis appears to have been broken
since 2.69. Thanks to Josh Stone for finding the bug.
Eliminate IPv6 privacy addresses and deprecated addresses from
the answers given by --interface-name. Note that reverse queries
(ie looking for names, given addresses) are not affected.
Thanks to Michael Gorbach for the suggestion.
Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
for the bug report.
Add --ignore-address option. Ignore replies to A-record
queries which include the specified address. No error is
generated, dnsmasq simply continues to listen for another
reply. This is useful to defeat blocking strategies which
rely on quickly supplying a forged answer to a DNS
request for certain domains, before the correct answer can
arrive. Thanks to Glen Huang for the patch.
Revisit the part of DNSSEC validation which determines if an
unsigned answer is legit, or is in some part of the DNS
tree which should be signed. Dnsmasq now works from the
DNS root downward looking for the limit of signed
delegations, rather than working bottom up. This is
both more correct, and less likely to trip over broken
nameservers in the unsigned parts of the DNS tree
which don't respond well to DNSSEC queries.
Add --log-queries=extra option, which makes logs easier
to search automatically.
Add --min-cache-ttl option. I've resisted this for a long
time, on the grounds that disbelieving TTLs is never a
good idea, but I've been persuaded that there are
sometimes reasons to do it. (Step forward, GFW).
To avoid misuse, there's a hard limit on the TTL
floor of one hour. Thansk to RinSatsuki for the patch.
Cope with multiple interfaces with the same link-local
address. (IPv6 addresses are scoped, so this is allowed.)
Thanks to Cory Benfield for help with this.
Add --dhcp-hostsdir. This allows addition of new host
configurations to a running dnsmasq instance much more
cheaply than having dnsmasq re-read all its existing
configuration each time.
Don't reply to DHCPv6 SOLICIT messages if we're not
configured to do stateful DHCPv6. Thanks to Win King Wan
for the patch.
Fix broken DNSSEC validation of ECDSA signatures.
Add --dnssec-timestamp option, which provides an automatic
way to detect when the system time becomes valid after
boot on systems without an RTC, whilst allowing DNS
queries before the clock is valid so that NTP can run.
Thanks to Kevin Darbyshire-Bryant for developing this idea.
Add --tftp-no-fail option. Thanks to Stefan Tomanek for
the patch.
Fix crash caused by looking up servers.bind, CHAOS text
record, when more than about five --servers= lines are
in the dnsmasq config. This causes memory corruption
which causes a crash later. Thanks to Matt Coddington for
sterling work chasing this down.
Fix crash on receipt of certain malformed DNS requests.
Thanks to Nick Sampanis for spotting the problem.
Note that this is could allow the dnsmasq process's
memory to be read by an attacker under certain
circumstances, so it has a CVE, CVE-2015-3294
Fix crash in authoritative DNS code, if a .arpa zone
is declared as authoritative, and then a PTR query which
is not to be treated as authoritative arrived. Normally,
directly declaring .arpa zone as authoritative is not
done, so this crash wouldn't be seen. Instead the
relevant .arpa zone should be specified as a subnet
in the auth-zone declaration. Thanks to Johnny S. Lee
for the bugreport and initial patch.
Fix authoritative DNS code to correctly reply to NS
and SOA queries for .arpa zones for which we are
declared authoritative by means of a subnet in auth-zone.
Previously we provided correct answers to PTR queries
in such zones (including NS and SOA) but not direct
NS and SOA queries. Thanks to Johnny S. Lee for
pointing out the problem.
Fix logging of DHCPREPLY which should be suppressed
by quiet-dhcp6. Thanks to J. Pablo Abonia for
spotting the problem.
Try and handle net connections with broken fragmentation
that lose large UDP packets. If a server times out,
reduce the maximum UDP packet size field in the EDNS0
header to 1280 bytes. If it then answers, make that
change permanent.
Check IPv4-mapped IPv6 addresses when --stop-rebind
is active. Thanks to Jordan Milne for spotting this.
Allow DHCPv4 options T1 and T2 to be set using --dhcp-option.
Thanks to Kevin Benton for patches and work on this.
Fix code for DHCPCONFIRM DHCPv6 messages to confirm addresses
in the correct subnet, even of not in dynamic address
allocation range. Thanks to Steve Hirsch for spotting
the problem.
Add AddDhcpLease and DeleteDhcpLease DBus methods. Thanks
to Nicolas Cavallari for the patch.
Allow configuration of router advertisements without the
"on-link" bit set. Thanks to Neil Jerram for the patch.
Extend --bridge-interface to DHCPv6 and router
advertisements. Thanks to Neil Jerram for the patch.
version 2.72
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
Add support for "ipsets" in *BSD, using pf. Thanks to
Sven Falempim for the patch.
Fix race condition which could lock up dnsmasq when an
interface goes down and up rapidly. Thanks to Conrad
Kostecki for helping to chase this down.
Add DBus methods SetFilterWin2KOption and SetBogusPrivOption
Thanks to the Smoothwall project for the patch.
Fix failure to build against Nettle-3.0. Thanks to Steven
Barth for spotting this and finding the fix.
When assigning existing DHCP leases to intefaces by comparing
networks, handle the case that two or more interfaces have the
same network part, but different prefix lengths (favour the
longer prefix length.) Thanks to Lung-Pin Chang for the
patch.
Add a mode which detects and removes DNS forwarding loops, ie
a query sent to an upstream server returns as a new query to
dnsmasq, and would therefore be forwarded again, resulting in
a query which loops many times before being dropped. Upstream
servers which loop back are disabled and this event is logged.
Thanks to Smoothwall for their sponsorship of this feature.
Extend --conf-dir to allow filtering of files. So
--conf-dir=/etc/dnsmasq.d,\*.conf
will load all the files in /etc/dnsmasq.d which end in .conf
Fix bug when resulted in NXDOMAIN answers instead of NODATA in
some circumstances.
Fix bug which caused dnsmasq to become unresponsive if it
failed to send packets due to a network interface disappearing.
Thanks to Niels Peen for spotting this.
Fix problem with --local-service option on big-endian platforms
Thanks to Richard Genoud for the patch.
version 2.71
Subtle change to error handling to help DNSSEC validation
when servers fail to provide NODATA answers for
non-existent DS records.
Tweak code which removes DNSSEC records from answers when
not required. Fixes broken answers when additional section
has real records in it. Thanks to Marco Davids for the bug
report.
Fix DNSSEC validation of ANY queries. Thanks to Marco Davids
for spotting that too.
Fix total DNS failure and 100% CPU use if cachesize set to zero,
regression introduced in 2.69. Thanks to James Hunt and
the Ubuntu crowd for assistance in fixing this.
version 2.70
Fix crash, introduced in 2.69, on TCP request when dnsmasq
compiled with DNSSEC support, but running without DNSSEC
enabled. Thanks to Manish Sing for spotting that one.
Fix regression which broke ipset functionality. Thanks to
Wang Jian for the bug report.
version 2.69
Implement dynamic interface discovery on *BSD. This allows
the contructor: syntax to be used in dhcp-range for DHCPv6
on the BSD platform. Thanks to Matthias Andree for
valuable research on how to implement this.
Fix infinite loop associated with some --bogus-nxdomain
configs. Thanks fogobogo for the bug report.
Fix missing RA RDNS option with configuration like
--dhcp-option=option6:23,[::] Thanks to Tsachi Kimeldorfer
for spotting the problem.
Add [fd00::] and [fe80::] as special addresses in DHCPv6
options, analogous to [::]. [fd00::] is replaced with the
actual ULA of the interface on the machine running
dnsmasq, [fe80::] with the link-local address.
Thanks to Tsachi Kimeldorfer for championing this.
DNSSEC validation and caching. Dnsmasq needs to be
compiled with this enabled, with
make dnsmasq COPTS=-DHAVE_DNSSEC
this add dependencies on the nettle crypto library and the
gmp maths library. It's possible to have these linked
statically with
make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
which bloats the dnsmasq binary, but saves the size of
the shared libraries which are much bigger.
To enable, DNSSEC, you will need a set of
trust-anchors. Now that the TLDs are signed, this can be
the keys for the root zone, and for convenience they are
included in trust-anchors.conf in the dnsmasq
distribution. You should of course check that these are
legitimate and up-to-date. So, adding
conf-file=/path/to/trust-anchors.conf
dnssec
to your config is all thats needed to get things
working. The upstream nameservers have to be DNSSEC-capable
too, of course. Many ISP nameservers aren't, but the
Google public nameservers (8.8.8.8 and 8.8.4.4) are.
When DNSSEC is configured, dnsmasq validates any queries
for domains which are signed. Query results which are
bogus are replaced with SERVFAIL replies, and results
which are correctly signed have the AD bit set. In
addition, and just as importantly, dnsmasq supplies
correct DNSSEC information to clients which are doing
their own validation, and caches DNSKEY, DS and RRSIG
records, which significantly improve the performance of
downstream validators. Setting --log-queries will show
DNSSEC in action.
If a domain is returned from an upstream nameserver without
DNSSEC signature, dnsmasq by default trusts this. This
means that for unsigned zone (still the majority) there
is effectively no cost for having DNSSEC enabled. Of course
this allows an attacker to replace a signed record with a
false unsigned record. This is addressed by the
--dnssec-check-unsigned flag, which instructs dnsmasq
to prove that an unsigned record is legitimate, by finding
a secure proof that the zone containing the record is not
signed. Doing this has costs (typically one or two extra
upstream queries). It also has a nasty failure mode if
dnsmasq's upstream nameservers are not DNSSEC capable.
Without --dnssec-check-unsigned using such an upstream
server will simply result in not queries being validated;
with --dnssec-check-unsigned enabled and a
DNSSEC-ignorant upstream server, _all_ queries will fail.
Note that DNSSEC requires that the local time is valid and
accurate, if not then DNSSEC validation will fail. NTP
should be running. This presents a problem for routers
without a battery-backed clock. To set the time needs NTP
to do DNS lookups, but lookups will fail until NTP has run.
To address this, there's a flag, --dnssec-no-timecheck
which disables the time checks (only) in DNSSEC. When dnsmasq
is started and the clock is not synced, this flag should
be used. As soon as the clock is synced, SIGHUP dnsmasq.
The SIGHUP clears the cache of partially-validated data and
resets the no-timecheck flag, so that all DNSSEC checks
henceforward will be complete.
The development of DNSSEC in dnsmasq was started by
Giovanni Bajo, to whom huge thanks are owed. It has been
supported by Comcast, whose techfund grant has allowed for
an invaluable period of full-time work to get it to
a workable state.
Add --rev-server. Thanks to Dave Taht for suggesting this.
Add --servers-file. Allows dynamic update of upstream servers
full access to configuration.
Add --local-service. Accept DNS queries only from hosts
whose address is on a local subnet, ie a subnet for which
an interface exists on the server. This option
only has effect if there are no --interface --except-interface,
--listen-address or --auth-server options. It is intended
to be set as a default on installation, to allow
unconfigured installations to be useful but also safe from
being used for DNS amplification attacks.
Fix crashes in cache_get_cname_target() when dangling CNAMEs
encountered. Thanks to Andy and the rt-n56u project for
find this and helping to chase it down.
Fix wrong RCODE in authoritative DNS replies to PTR queries. The
correct answer was included, but the RCODE was set to NXDOMAIN.
Thanks to Craig McQueen for spotting this.
Make statistics available as DNS queries in the .bind TLD as
well as logging them.
version 2.68
Use random addresses for DHCPv6 temporary address
allocations, instead of algorithmically determined stable
addresses.
Fix bug which meant that the DHCPv6 DUID was not available
in DHCP script runs during the lifetime of the dnsmasq
process which created the DUID de-novo. Once the DUID was
created and stored in the lease file and dnsmasq
restarted, this bug disappeared.
Fix bug introduced in 2.67 which could result in erroneous
NXDOMAIN returns to CNAME queries.
Fix build failures on MacOS X and openBSD.
Allow subnet specifications in --auth-zone to be interface
names as well as address literals. This makes it possible
to configure authoritative DNS when local address ranges
are dynamic and works much better than the previous
work-around which exempted contructed DHCP ranges from the
IP address filtering. As a consequence, that work-around
is removed. Under certain circumstances, this change wil
break existing configuration: if you're relying on the
contructed-range exception, you need to change --auth-zone
to specify the same interface as is used to construct your
DHCP ranges, probably with a trailing "/6" like this:
--auth-zone=example.com,eth0/6 to limit the addresses to
IPv6 addresses of eth0.
Fix problems when advertising deleted IPv6 prefixes. If
the prefix is deleted (rather than replaced), it doesn't
get advertised with zero preferred time. Thanks to Tsachi
for the bug report.
Fix segfault with some locally configured CNAMEs. Thanks
to Andrew Childs for spotting the problem.
Fix memory leak on re-reading /etc/hosts and friends,
introduced in 2.67.
Check the arrival interface of incoming DNS and TFTP
requests via IPv6, even in --bind-interfaces mode. This
isn't possible for IPv4 and can generate scary warnings,
but as it's always possible for IPv6 (the API always
exists) then we should do it always.
Tweak the rules on prefix-lengths in --dhcp-range for
IPv6. The new rule is that the specified prefix length
must be larger than or equal to the prefix length of the
corresponding address on the local interface.
version 2.67
Fix crash if upstream server returns SERVFAIL when
--conntrack in use. Thanks to Giacomo Tazzari for finding
@@ -31,7 +425,128 @@ version 2.67
want to continue to bind the aliases too, you need to add
eg. --interface=eth0:0 to the config.
Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket
operation on non-socket" error on startup with
configurations which have exactly one --interface option
and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
bug report.
Generalise --interface-name to cope with IPv6 addresses
and multiple addresses per interface per address family.
Fix option parsing for --dhcp-host, which was generating a
spurious error when all seven possible items were
included. Thanks to Zhiqiang Wang for the bug report.
Remove restriction on prefix-length in --auth-zone. Thanks
to Toke Hoiland-Jorgensen for suggesting this.
Log when the maximum number of concurrent DNS queries is
reached. Thanks to Marcelo Salhab Brogliato for the patch.
If wildcards are used in --interface, don't assume that
there will only ever be one available interface for DHCP
just because there is one at start-up. More may appear, so
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
report.
Increase timeout/number of retries in TFTP to accomodate
AudioCodes Voice Gateways doing streaming writes to flash.
Thanks to Damian Kaczkowski for spotting the problem.
Fix crash with empty DHCP string options when adding zero
terminator. Thanks to Patrick McLean for the bug report.
Allow hostnames to start with a number, as allowed in
RFC-1123. Thanks to Kyle Mestery for the patch.
Fixes to DHCP FQDN option handling: don't terminate FQDN
if domain not known and allow a FQDN option with blank
name to request that a FQDN option is returned in the
reply. Thanks to Roy Marples for the patch.
Make --clear-on-reload apply to setting upstream servers
via DBus too.
When the address which triggered the construction of an
advertised IPv6 prefix disappears, continue to advertise
the prefix for up to 2 hours, with the preferred lifetime
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
things work better if a prefix disappears without being
deprecated first. Thanks to Uwe Schindler for persuasively
arguing for this.
Fix MAC address enumeration on *BSD. Thanks to Brad Smith
for the bug report.
Support RFC-4242 information-refresh-time options in the
reply to DHCPv6 information-request. The lease time of the
smallest valid dhcp-range is sent. Thanks to Uwe Schindler
for suggesting this.
Make --listen-address higher priority than --except-interface
in all circumstances. Thanks to Thomas Hood for the bugreport.
Provide independent control over which interfaces get TFTP
service. If enable-tftp is given a list of interfaces, then TFTP
is provided on those. Without the list, the previous behaviour
(provide TFTP to the same interfaces we provide DHCP to)
is retained. Thanks to Lonnie Abelbeck for the suggestion.
Add --dhcp-relay config option. Many thanks to vtsl.net
for sponsoring this development.
Fix crash with empty tag: in --dhcp-range. Thanks to
Kaspar Schleiser for the bug report.
Add "baseline" and "bloatcheck" makefile targets, for
revealing size changes during development. Thanks to
Vladislav Grishenko for the patch.
Cope with DHCPv6 clients which send REQUESTs without
address options - treat them as SOLICIT with rapid commit.
Support identification of clients by MAC address in
DHCPv6. When using a relay, the relay must support RFC
6939 for this to work. It always works for directly
connected clients. Thanks to Vladislav Grishenko
for prompting this feature.
Remove the rule for constructed DHCP ranges that the local
address must be either the first or last address in the
range. This was originally to avoid SLAAC addresses, but
we now explicitly autoconfig and privacy addresses instead.
Update Polish translation. Thanks to Jan Psota.
Fix problem in DHCPv6 vendorclass/userclass matching
code. Thanks to Tanguy Bouzeloc for the patch.
Update Spanish transalation. Thanks to Vicente Soriano.
Add --ra-param option. Thanks to Vladislav Grishenko for
inspiration on this.
Add --add-subnet configuration, to tell upstream DNS
servers where the original client is. Thanks to DNSthingy
for sponsoring this feature.
Add --quiet-dhcp, --quiet-dhcp6 and --quiet-ra. Thanks to
Kevin Darbyshire-Bryant for the initial patch.
Allow A/AAAA records created by --interface-name to be the
target of --cname. Thanks to Hadmut Danisch for the
suggestion.
Avoid treating a --dhcp-host which has an IPv6 address
as eligable for use with DHCPv4 on the grounds that it has
no address, and vice-versa. Thanks to Yury Konovalov for
spotting the problem.
Do a better job caching dangling CNAMEs. Thanks to Yves
Dorfsman for spotting the problem.
version 2.66
Add the ability to act as an authoritative DNS
server. Dnsmasq can now answer queries from the wider 'net

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2013 Simon Kelley
# dnsmasq is Copyright (c) 2000-2015 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
@@ -51,36 +51,48 @@ top!=pwd
# GNU make way.
top?=$(CURDIR)
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`
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`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
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`
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`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
copts_conf = .copts_$(sum)
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o domain.o
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o poll.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h
dns-protocol.h radv-protocol.h ip6addr.h
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
-f $(top)/Makefile dnsmasq
clean :
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
rm -rf core */core
mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
clean : mostly_clean
rm -f $(BUILDDIR)/dnsmasq_baseline
rm -f core */core
rm -f *~ contrib/*/*~ */*~
install : all install-common
@@ -93,8 +105,8 @@ all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`" \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) `$(PKG_CONFIG) --libs libidn`" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
@@ -105,28 +117,45 @@ install-i18n : all-i18n install-common
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
merge :
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
@cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile dnsmasq.pot
for f in `cd $(PO); echo *.po`; do \
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
done
# Cannonicalise .po file.
%.po :
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
mv $(PO)/$*.po $(PO)/$*.po.orig && $(MSGMERGE) --no-wrap $(PO)/$*.po.orig $(BUILDDIR)/dnsmasq.pot >$(PO)/$*.po;
$(BUILDDIR):
mkdir -p $(BUILDDIR)
# rules below are helpers for size tracking
baseline : mostly_clean all
@cd $(BUILDDIR) && \
mv dnsmasq dnsmasq_baseline
bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
@cd $(BUILDDIR) && \
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
size dnsmasq_baseline dnsmasq
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
.configured: $(hdrs)
@rm -f *.o
$(copts_conf): $(hdrs)
@rm -f *.o .copts_*
@touch $@
$(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ .
$(objs): $(copts_conf) $(hdrs)
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : .configured $(hdrs) $(objs)
dnsmasq : $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
@@ -135,5 +164,4 @@ dnsmasq.pot : $(objs:.o=.c) $(hdrs)
%.mo : $(top)/$(PO)/%.po dnsmasq.pot
$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
.PHONY : all clean install install-common all-i18n install-i18n merge
.PHONY : all clean mostly_clean install install-common all-i18n install-i18n merge baseline bloatcheck

View File

@@ -8,7 +8,9 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.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 \
loop.c inotify.c poll.c
LOCAL_MODULE := dnsmasq

130
bld/bloat-o-meter Executable file
View File

@@ -0,0 +1,130 @@
#!/usr/bin/env python
#
# Copyright 2004 Matt Mackall <mpm@selenic.com>
#
# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
import sys, os#, re
def usage():
sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0])
sys.exit(-1)
f1, f2 = (None, None)
flag_timing, dashes = (False, False)
for f in sys.argv[1:]:
if f.startswith("-"):
if f == "--": # sym_args
dashes = True
break
if f == "-t": # timings
flag_timing = True
else:
if not os.path.exists(f):
sys.stderr.write("Error: file '%s' does not exist\n" % f)
usage()
if f1 is None:
f1 = f
elif f2 is None:
f2 = f
if flag_timing:
import time
if f1 is None or f2 is None:
usage()
sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
def getsizes(file):
sym, alias, lut = {}, {}, {}
for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines():
l = l.strip()
if not (len(l) and l[0].isdigit() and len(l.split()) == 8):
continue
num, value, size, typ, bind, vis, ndx, name = l.split()
if ndx == "UND": continue # skip undefined
if typ in ["SECTION", "FILES"]: continue # skip sections and files
if "." in name: name = "static." + name.split(".")[0]
value = int(value, 16)
size = int(size, 16) if size.startswith('0x') else int(size)
if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias
alias[(value, size)] = {"name" : name}
else:
sym[name] = {"addr" : value, "size": size}
lut[(value, size)] = 0
for addr, sz in iter(alias.keys()):
# If the non-GLOBAL sym has an implementation elsewhere then
# it's an alias, disregard it.
if not (addr, sz) in lut:
# If this non-GLOBAL sym does not have an implementation at
# another address, then treat it as a normal symbol.
sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
for l in os.popen("readelf -W -S " + file).readlines():
x = l.split()
if len(x)<6: continue
# Should take these into account too!
#if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
if x[1] not in [".rodata"]: continue
sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)}
return sym
if flag_timing:
start_t1 = int(time.time() * 1e9)
old = getsizes(f1)
if flag_timing:
end_t1 = int(time.time() * 1e9)
start_t2 = int(time.time() * 1e9)
new = getsizes(f2)
if flag_timing:
end_t2 = int(time.time() * 1e9)
start_t3 = int(time.time() * 1e9)
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
delta, common = [], {}
for name in iter(old.keys()):
if name in new:
common[name] = 1
for name in old:
if name not in common:
remove += 1
sz = old[name]["size"]
down += sz
delta.append((-sz, name))
for name in new:
if name not in common:
add += 1
sz = new[name]["size"]
up += sz
delta.append((sz, name))
for name in common:
d = new[name].get("size", 0) - old[name].get("size", 0)
if d>0: grow, up = grow+1, up+d
elif d<0: shrink, down = shrink+1, down-d
else:
continue
delta.append((d, name))
delta.sort()
delta.reverse()
if flag_timing:
end_t3 = int(time.time() * 1e9)
print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
for d, n in delta:
if d:
old_sz = old.get(n, {}).get("size", "-")
new_sz = new.get(n, {}).get("size", "-")
print("%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d))
print("-"*78)
total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
% (add, remove, grow, shrink, up, -down, up-down)
print(total % (" "*(80-len(total))))
if flag_timing:
print("\n%d/%d; %d Parse origin/new; processing nsecs" %
(end_t1-start_t1, end_t2-start_t2, end_t3-start_t3))
print("total nsecs: %d" % (end_t3-start_t1))

View File

@@ -11,8 +11,9 @@
# If there is more than one v[0-9].* tag, sort them and use the
# first. This favours, eg v2.63 over 2.63rc6.
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
cd $1; git describe
if which git >/dev/null 2>&1 && \
([ -d $1/.git ] || grep '^gitdir:' $1/.git >/dev/null 2>&1); then
cd $1; git describe | sed 's/^v//'
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
@@ -20,7 +21,7 @@ else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
else
cat $1/VERSION
fi

View File

@@ -2,10 +2,39 @@
search=$1
shift
pkg=$1
shift
op=$1
shift
in=`cat`
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
grep $search >/dev/null 2>&1; then
exec $*
echo $in | grep $search >/dev/null 2>&1; then
# Nasty, nasty, in --copy, arg 2 is another config to search for, use with NO_GMP
if [ $op = "--copy" ]; then
if grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
echo $in | grep $pkg >/dev/null 2>&1; then
pkg=""
else
pkg="$*"
fi
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
pkg=`$pkg --static $op $*`
else
pkg=`$pkg $op $*`
fi
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
else
echo "$pkg"
fi
else
echo "$pkg"
fi
fi

36
contrib/mactable/macscript Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/bash
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
# Script for dnsmasq lease-change hook.
# Maintains the above file with a IP address/MAC address pairs,
# one lease per line. Works with IPv4 and IPv6 leases, file is
# atomically updated, so no races for users of the data.
action="$1"
mac="$2" # IPv4
ip="$3"
# ensure it always exists.
if [ ! -f "$STATUS_FILE" ]; then
touch "$STATUS_FILE"
fi
if [ -n "$DNSMASQ_IAID" ]; then
mac="$DNSMASQ_MAC" # IPv6
fi
# worry about an add or old action when the MAC address is not known:
# leave any old one in place in that case.
if [ "$action" = "add" -o "$action" = "old" -o "$action" = "del" ]; then
if [ -n "$mac" -o "$action" = "del" ]; then
sed "/^${ip//./\.} / d" "$STATUS_FILE" > "$STATUS_FILE".new
if [ "$action" = "add" -o "$action" = "old" ]; then
echo "$ip $mac" >> "$STATUS_FILE".new
fi
mv "$STATUS_FILE".new "$STATUS_FILE" # atomic update.
fi
fi

View File

@@ -0,0 +1,18 @@
The script reads stdin and replaces all IP addresses with names before
outputting it again. IPs from private networks are reverse looked up
via dns. Other IP adresses are searched for in the dnsmasq query log.
This gives names (CNAMEs if I understand DNS correctly) that are closer
to the name the client originally asked for then the names obtained by
reverse lookup. Just run
netstat -n -4 | ./reverse_replace.sh
to see what it does. It needs
log-queries
log-facility=/var/log/dnsmasq.log
in the dnsmasq configuration.
The script runs on debian (with ash installed) and on busybox.

View File

@@ -0,0 +1,125 @@
#!/bin/ash
# $Id: reverse_replace.sh 18 2015-03-01 16:12:35Z jo $
#
# Usage e.g.: netstat -n -4 | reverse_replace.sh
# Parses stdin for IP4 addresses and replaces them
# with names retrieved by parsing the dnsmasq log.
# This currently only gives CNAMEs. But these
# usually tell ou more than the mones from reverse
# lookups.
#
# This has been tested on debian and asuswrt. Plese
# report successful tests on other platforms.
#
# Author: Joachim Zobel <jz-2014@heute-morgen.de>
# License: Consider this MIT style licensed. You can
# do as you ike, but you must not remove my name.
#
LOG=/var/log/dnsmasq.log
MAX_LINES=15000
# sed regex do match IPs
IP_regex='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
# private IP ranges
IP_private='\(^127\.\)\|\(^192\.168\.\)\|\(^10\.\)\|\(^172\.1[6-9]\.\)\|\(^172\.2[0-9]\.\)\|\(^172\.3[0-1]\.\)'
#######################################################################
# Find Commands
HOST=nslookup
if type host > /dev/null 2>&1; then
# echo "No need for nslookup, host is there"
HOST=host
fi
#######################################################################
# Functions
# Use shell variables for an (IP) lookup table
create_lookup_table()
{
# Parse log into lookup table
local CMDS="$( tail -"$MAX_LINES" "$LOG" | \
grep " is $IP_regex" | \
sed "s#.* \([^ ]*\) is \($IP_regex\).*#set_val \2 \1;#" )"
local IFS='
'
for CMD in $CMDS
do
eval $CMD
done
}
set_val()
{
local _IP=$(echo $1 | tr . _)
local KEY="__IP__$_IP"
eval "$KEY"=$2
}
get_val()
{
local _IP=$(echo $1 | tr . _)
local KEY="__IP__$_IP"
eval echo -n '${'"$KEY"'}'
}
dns_lookup()
{
local IP=$1
local RTN="$($HOST $IP | \
sed 's#\s\+#\n#g' | \
grep -v '^$' | \
tail -1 | tr -d '\n' | \
sed 's#\.$##')"
if echo $RTN | grep -q NXDOMAIN; then
echo -n $IP
else
echo -n "$RTN"
fi
}
reverse_dns()
{
local IP=$1
# Skip if it is not an IP
if ! echo $IP | grep -q "^$IP_regex$"; then
echo -n $IP
return
fi
# Do a dns lookup, if it is a local IP
if echo $IP | grep -q $IP_private; then
dns_lookup $IP
return
fi
local NAME="$(get_val $IP)"
if [ -z "$NAME" ]; then
echo -n $IP
else
echo -n $NAME
fi
}
#######################################################################
# Main
create_lookup_table
while read LINE; do
for IP in $(echo "$LINE" | \
sed "s#\b\($IP_regex\)\b#\n\1\n#g" | \
grep $IP_regex)
do
NAME=`reverse_dns $IP `
# echo "$NAME $IP"
LINE=`echo "$LINE" | sed "s#$IP#$NAME#" `
done
echo $LINE
done

View File

@@ -1,5 +1,5 @@
[Unit]
Description=A lightweight DHCP and caching DNS server
Description=dnsmasq - A lightweight DHCP and caching DNS server
[Service]
Type=dbus

View File

@@ -0,0 +1,29 @@
From: Jesse Glick <jglick@cloudbees.com>
To: dnsmasq-discuss@lists.thekelleys.org.uk
Subject: Re: [Dnsmasq-discuss] Ability to delegate to one server but fall
back to another after NXDOMAIN?
On Wed, Jan 15, 2014 at 12:30 PM, Simon Kelley <simon@thekelleys.org.uk> wrote:
> > There's a (very old) patch in contrib/try-all-ns that would make a starting point
This does not apply against trunk, so I tried to rework it. The
following appears to do what I expect:
diff --git a/src/forward.c b/src/forward.c
index 8167229..76070b5 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -610,7 +610,11 @@ void reply_query(int fd, int family, time_t now)
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
!option_bool(OPT_ORDER) &&
- forward->forwardall == 0)
+ forward->forwardall == 0 ||
+ /* try each in turn */
+ RCODE(header) == NXDOMAIN &&
+ option_bool(OPT_ORDER) &&
+ server->next != NULL)
/* for broken servers, attempt to send to another one. */
{
unsigned char *pheader;

View File

@@ -277,6 +277,11 @@ int main(int argc, char **argv)
exit(1);
}
if (inet_addr(argv[2]) == INADDR_NONE)
{
perror("invalid ip address");
exit(1);
}
lease.s_addr = inet_addr(argv[2]);
server = find_interface(lease, nl, if_nametoindex(argv[1]));

View File

@@ -40,6 +40,14 @@ ClearCache
Returns nothing. Clears the domain name cache and re-reads
/etc/hosts. The same as sending dnsmasq a HUP signal.
SetFilterWin2KOption
--------------------
Takes boolean, sets or resets the --filterwin2k option.
SetBogusPrivOption
------------------
Takes boolean, sets or resets the --bogus-priv option.
SetServers
----------
Returns nothing. Takes a set of arguments representing the new
@@ -152,6 +160,89 @@ for SetServersEx is represented as
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
]
GetLoopServers
--------------
(Only available if dnsmasq compiled with HAVE_LOOP)
Return an array of strings, each string is the IP address of an upstream
server which has been found to loop queries back to this dnsmasq instance, and
it therefore not being used.
AddDhcpLease
------------
Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
database, as if a client requested and obtained a lease.
If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
D-Bus signal and will run the configured DHCP lease script accordingly.
This function takes many arguments which are the lease parameters:
- A string with the textual representation of the IPv4 or IPv6 address of the
client.
Examples:
"192.168.1.115"
"1003:1234:abcd::1%eth0"
"2001:db8:abcd::1"
- A string representing the hardware address of the client, using the same
format as the one used in the lease database.
Examples:
"00:23:45:67:89:ab"
"06-00:20:e0:3b:13:af" (token ring)
- The hostname of the client, as an array of bytes (so there is no problem
with non-ASCII character encoding). May be empty.
Example (for "hostname.or.fqdn"):
[104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
empty.
Examples:
DHCPv6 DUID:
[0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
DHCPv4 client identifier:
[255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
- The duration of the lease, in seconds. If the lease is updated, then
the duration replaces the previous duration.
Example:
7200
- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
Example (for IPv6):
203569230
- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
(IA_NA). For DHCPv4 leases, this must be set to false.
RemoveDhcpLease
---------------
Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
database, as if a client sent a release message to abandon a lease.
This function takes only one parameter: the text representation of the
IPv4 or IPv6 address of the lease to remove.
Note that this function will trigger the DhcpLeaseRemoved signal and the
configured DHCP lease script will be run with the "del" action.
2. SIGNALS

127
debian/changelog vendored
View File

@@ -1,8 +1,131 @@
dnsmasq (2.67-1) unstable; urgency=low
dnsmasq (2.74-1) unstable; urgency=low
* New upstream. (LP: #1468611)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 15 Jul 2015 21:54:11 +0000
dnsmasq (2.73-2) unstable; urgency=low
* Fix behaviour of empty --conf-file (closes: #790341)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 7 Jul 2015 21:46:42 +0000
dnsmasq (2.73-1) unstable; urgency=low
* New upstream. (closes: #786996)
* Tweak field width in cache dump to avoid truncating IPv6
addresses. (closes: #771557)
* Add newline at the end of example config file. (LP: #1416895)
* Make Debian package build reproducible. (closes: #777323)
* Add Requires=network.target to systemd unit.
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 4 Jun 2015 22:31:42 +0000
dnsmasq (2.72-3) unstable; urgency=medium
* debian/systemd.service: switch from Type=dbus to Type=forking.
dnsmasq does not depend on dbus, but Type=dbus systemd services cannot
work without it. (Closes: #769486, #776530)
- debian/init: when called with systemd-exec argument, let dnsmasq
go into the background, so Type=forking can detect when it is ready
* Remove line containing only whitespace in debian/contol.
(closes: #777571)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:56:12 +0000
dnsmasq (2.72-2) unstable; urgency=low
* Fix build in Debian-kFreeBSD. (closes: #763693)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 02 Oct 2014 22:34:12 +0000
dnsmasq (2.72-1) unstable; urgency=low
* New upstream.
* If dns-root-data package is installed, use it to set the DNSSEC
trust anchor(s). Recommend dns-root-data. (closes: #760460)
* Handle AD bit correctly in replies from cache. (closes: #761654)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 20 May 2014 21:01:11 +0000
dnsmasq (2.71-1) unstable; urgency=low
* New upstream.
* Fix 100% CPU-usage bug when dnsmasq started with cachesize
set to zero. (LP: #1314697)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 May 2014 20:17:10 +0000
dnsmasq (2.70-3) unstable; urgency=medium
* Write a pid-file, even when being started using systemd, since
other components may wish to signal dnsmasq.
* Enable dnsmasq systemd unit on install. Otherwise dnsmasq does not run on
fresh installations (without administrator handholding) and even worse it
is disabled on systems switching from sysv to systemd. Modify
postinst/postrm exactly as dh_systemd would, add dependency on
init-system-helpers. Closes: #724602
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 11 May 2014 17:45:21 +0000
dnsmasq (2.70-2) unstable; urgency=low
* Ensure daemon not stared if dnsmasq package has been removed,
even if dnsmasq-base is still installed. (closes: #746941)
* Tidy cruft in initscript. (closes: #746940)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 04 May 2014 21:34:11 +0000
dnsmasq (2.70-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 19 Apr 2013 10:23:31 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 23 Apr 2014 15:14:42 +0000
dnsmasq (2.69-1) unstable; urgency=low
* New upstream.
* Set --local-service. (closes: #732610)
This tells dnsmasq to ignore DNS requests that don't come
from a local network. It's automatically ignored if
--interface --except-interface, --listen-address or
--auth-server exist in the configuration, so for most
installations, it will have no effect, but for
otherwise-unconfigured installations, it stops dnsmasq
from being vulnerable to DNS-reflection attacks.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
dnsmasq (2.68-1) unstable; urgency=low
* New upstream. (closes: #730553)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 8 Dec 2013 15:57:32 +0000
dnsmasq (2.67-1) unstable; urgency=low
* New upstream.
* Update resolvconf script. (closes: #720732)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:53:22 +0000
dnsmasq (2.66-4) unstable; urgency=low
* Update resolvconf script. (closes: #716908)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:48:21 +0000
dnsmasq (2.66-3) unstable; urgency=low
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
dnsmasq (2.66-2) unstable; urgency=low
* Fix error on startup with some configs. (closes: #709010)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
dnsmasq (2.66-1) unstable; urgency=low

12
debian/control vendored
View File

@@ -1,13 +1,16 @@
Source: dnsmasq
Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.3
Standards-Version: 3.9.5
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base(>= ${source:Version})
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
init-system-helpers (>= 1.18~)
Suggests: resolvconf
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server
@@ -25,6 +28,7 @@ Architecture: any
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~)
Recommends: dns-root-data
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
@@ -38,5 +42,3 @@ Description: Utilities for manipulating DHCP leases
Small utilities to query a DHCP server's lease database and
remove leases from it. These programs are distributed with dnsmasq
and may not work correctly with other DHCP servers.

2
debian/copyright vendored
View File

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

2
debian/default vendored
View File

@@ -27,7 +27,7 @@ CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
# If the resolvconf package is installed, dnsmasq will use its output
# rather than the contents of /etc/resolv.conf to find upstream
# nameservers. Uncommenting this line inhibits this behaviour.
# Not that including a "resolv-file=<filename>" line in
# Note that including a "resolv-file=<filename>" line in
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
# installed: the line below must be uncommented.
#IGNORE_RESOLVCONF=yes

37
debian/init vendored
View File

@@ -29,6 +29,12 @@ if [ -r /etc/default/locale ]; then
export LANG
fi
# /etc/dnsmasq.d/README is a non-conffile installed by the dnsmasq package.
# Should the dnsmasq package be removed, the following test ensures that
# the daemon is no longer started, even if the dnsmasq-base package is
# still in place.
test -e /etc/dnsmasq.d/README || exit 0
test -x $DAEMON || exit 0
# Provide skeleton LSB log functions for backports which don't have LSB functions.
@@ -90,6 +96,24 @@ if [ ! "$DNSMASQ_USER" ]; then
DNSMASQ_USER="dnsmasq"
fi
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
# It's automatically ignored if --interface --except-interface, --listen-address
# or --auth-server exist in the configuration, so for most installations, it will
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
# from being vulnerable to DNS-reflection attacks.
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
# If the dns-root-data package is installed, then the trust anchors will be
# available in $ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
# --trust-anchor options.
ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -e s/". IN DS "/--trust-anchor=.,/ -e s/" "/,/g $ROOT_DS | tr '\n' ' '`"
fi
start()
{
# Return
@@ -144,9 +168,6 @@ stop()
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
return "$RETVAL"
}
stop_resolvconf()
@@ -266,9 +287,13 @@ case "$1" in
stop_resolvconf
;;
systemd-exec)
# --pid-file without argument disables writing a PIDfile, we don't need one with sytemd.
# Enable DBus by default because we use DBus activation with systemd.
exec $DAEMON --keep-in-foreground --pid-file --enable-dbus \
# /var/run may be volatile, so we need to ensure that
# /var/run/dnsmasq exists here as well as in postinst
if [ ! -d /var/run/dnsmasq ]; then
mkdir /var/run/dnsmasq || return 2
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
fi
exec $DAEMON -x /var/run/dnsmasq/$NAME.pid \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \

16
debian/postinst vendored
View File

@@ -1,6 +1,22 @@
#!/bin/sh
set -e
# Code copied from dh_systemd_enable ----------------------
# This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled dnsmasq.service; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable dnsmasq.service >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state dnsmasq.service >/dev/null || true
fi
# End code copied from dh_systemd_enable ------------------
if [ -x /etc/init.d/dnsmasq ]; then
update-rc.d dnsmasq defaults 15 85 >/dev/null

16
debian/postrm vendored
View File

@@ -4,3 +4,19 @@ set -e
if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null
fi
# Code copied from dh_systemd_enable ----------------------
if [ "$1" = "remove" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper mask dnsmasq.service >/dev/null
fi
fi
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge dnsmasq.service >/dev/null
deb-systemd-helper unmask dnsmasq.service >/dev/null
fi
fi
# End code copied from dh_systemd_enable ------------------

4
debian/readme vendored
View File

@@ -64,7 +64,9 @@ Notes on configuring dnsmasq as packaged for Debian.
noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be
combined with noi18n to be effective.
gitversion : set the version of the produced packages from the
git-derived versioning information on the source,
rather the the debian changelog.
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and

38
debian/resolvconf vendored
View File

@@ -1,16 +1,14 @@
#!/bin/bash
#!/bin/sh
#
# Script to update the resolver list for dnsmasq
#
# N.B. Resolvconf may run us even if dnsmasq is not running.
# If dnsmasq is installed then we go ahead and update
# the resolver list in case dnsmasq is started later.
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
# If dnsmasq is installed then we go ahead and update the resolver list
# in case dnsmasq is started later.
#
# Assumption: On entry, PWD contains the resolv.conf-type files
# Assumption: On entry, PWD contains the resolv.conf-type files.
#
# Requires bash because it uses a non-POSIX printf extension.
#
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
# This file is part of the dnsmasq package.
#
set -e
@@ -18,6 +16,7 @@ set -e
RUN_DIR="/var/run/dnsmasq"
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
MY_NAME_FOR_RESOLVCONF="dnsmasq"
[ -x /usr/sbin/dnsmasq ] || exit 0
[ -x /lib/resolvconf/list-records ] || exit 1
@@ -27,7 +26,7 @@ PATH=/bin:/sbin
report_err() { echo "$0: Error: $*" >&2 ; }
# Stores arguments (minus duplicates) in RSLT, separated by spaces
# Doesn't work properly if an argument itself contain whitespace
# Doesn't work properly if an argument itself contains whitespace
uniquify()
{
RSLT=""
@@ -45,7 +44,22 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
exit 1
fi
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
RSLVCNFFILES=""
for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
case "$F" in
"lo.$MY_NAME_FOR_RESOLVCONF")
# Omit own record
;;
lo.*)
# Include no more records after one for a local nameserver
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
break
;;
*)
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
;;
esac
done
NMSRVRS=""
if [ "$RSLVCNFFILES" ] ; then
@@ -56,8 +70,8 @@ fi
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
# to detect changes in the file. This means that if a resolvconf update occurs
# within one second of the previous one then dnsmasq may fail to notice the
# more recent change. To work around this problem we sleep here to ensure
# that the new mtime is different.
# more recent change. To work around this problem we sleep one second here
# if necessary in order to ensure that the new mtime is different.
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
sleep 1
fi

100
debian/rules vendored
View File

@@ -11,65 +11,82 @@
package=dnsmasq-base
CFLAGS = $(shell export DEB_BUILD_OPTIONS=$(DEB_BUILD_OPTIONS); dpkg-buildflags --get CFLAGS)
CFLAGS += $(shell dpkg-buildflags --get CPPFLAGS)
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all" dpkg-buildflags
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
CFLAGS += -Wall -W
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
LDFLAGS = $(shell $(dpkg_buildflags) --get LDFLAGS)
COPTS =
DEB_COPTS = $(COPTS)
TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
endif
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_DBUS
DEB_COPTS += -DHAVE_DBUS
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_BUILD_ARCH_OS),linux)
COPTS += -DHAVE_CONNTRACK
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
endif
endif
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_IPSET
DEB_COPTS += -DNO_IPSET
endif
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP6
DEB_COPTS += -DNO_DHCP6
endif
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_IPV6
DEB_COPTS += -DNO_IPV6
endif
ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_TFTP
DEB_COPTS += -DNO_TFTP
endif
ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP
DEB_COPTS += -DNO_DHCP
endif
ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_SCRIPT
DEB_COPTS += -DNO_SCRIPT
endif
ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_BROKEN_RTC
DEB_COPTS += -DHAVE_BROKEN_RTC
endif
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_IDN
DEB_COPTS += -DHAVE_IDN
endif
endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_LUASCRIPT
DEB_COPTS += -DHAVE_LUASCRIPT
endif
ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DNSSEC
endif
ifneq ($(DEB_HOST_ARCH_OS),linux)
# For strlcpy in FreeBSD
LDFLAGS += -lbsd
endif
clean:
@@ -102,8 +119,9 @@ binary-indep: checkroot
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' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
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 ..
@@ -117,68 +135,74 @@ binary-arch: checkroot
-d debian/base/usr/share/doc/$(package) \
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/var/run \
-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="$(COPTS)" CC=gcc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
# Need to remove paypal links in Debian Package for policy reasons.
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
gzip -9n debian/base/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
gzip -9 debian/base/usr/share/doc/$(package)/changelog
gzip -9n debian/base/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
endif
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
gzip -9 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 -9 debian/base/usr/share/man/man8/dnsmasq.8
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 \
gzip -9 $$f/man8/dnsmasq.8 ; \
gzip -9n $$f/man8/dnsmasq.8 ; \
fi \
done
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
ifeq ($(DEB_BUILD_ARCH_OS),linux)
ifeq ($(DEB_HOST_ARCH_OS),linux)
rm -rf debian/utils
install -m 755 -d debian/utils/DEBIAN \
-d debian/utils/usr/share/man/man1 \
-d debian/utils/usr/bin \
-d debian/utils/usr/share/doc/dnsmasq-utils
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(COPTS)" CC=gcc
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..

View File

@@ -1,9 +1,10 @@
[Unit]
Description=A lightweight DHCP and caching DNS server
Description=dnsmasq - A lightweight DHCP and caching DNS server
Requires=network.target
[Service]
Type=dbus
BusName=uk.org.thekelleys.dnsmasq
Type=forking
PIDFile=/var/run/dnsmasq/dnsmasq.pid
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/usr/sbin/dnsmasq --test
@@ -11,12 +12,6 @@ ExecStartPre=/usr/sbin/dnsmasq --test
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
# wrapper picking up extra configuration files and then execs dnsmasq
# itself, when called with the "systemd-exec" function.
#
# It also adds the command-line flags
# --keep-in-foreground --pid-file --enable-dbus
# to disable writing a pid-file (not needed with systemd) and
# enable DBus by default because we use DBus activation.
#
ExecStart=/etc/init.d/dnsmasq systemd-exec
# The systemd-*-resolvconf functions configure (and deconfigure)

View File

@@ -20,6 +20,18 @@
# Never forward addresses in the non-routed address spaces.
#bogus-priv
# Uncomment these to enable DNSSEC validation and caching:
# (Requires dnsmasq to be built with DNSSEC option.)
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
#dnssec
# Replies which are not DNSSEC signed may be legitimate, because the domain
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
# check that an unsigned reply is OK, by finding a secure proof that a DS
# record somewhere between the root and the domain does not exist.
# The cost of setting this is that even queries in unsigned domains will need
# one or more extra DNS queries to verify.
#dnssec-check-unsigned
# Uncomment this to filter useless windows-originated DNS requests
# which can trigger dial-on-demand links needlessly.
@@ -239,6 +251,13 @@
# the IP address 192.168.0.60
#dhcp-host=id:01:02:02:04,192.168.0.60
# Always give the Infiniband interface with hardware address
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
# ip address 192.168.0.61. The client id is derived from the prefix
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
# hex digits of the hardware address.
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
# Always give the host with client identifier "marjorie"
# the IP address 192.168.0.60
#dhcp-host=id:marjorie,192.168.0.60
@@ -333,6 +352,14 @@
# Ask client to poll for option changes every six hours. (RFC4242)
#dhcp-option=option6:information-refresh-time,6h
# Set option 58 client renewal time (T1). Defaults to half of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T1:1m
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T2:2m
# Set the NTP time server address to be the same machine as
# is running dnsmasq
#dhcp-option=42,0.0.0.0
@@ -474,6 +501,9 @@
# Set the root directory for files available via FTP.
#tftp-root=/var/ftpd
# Do not abort if the tftp-root is unavailable
#tftp-no-fail
# Make the TFTP server more secure: with this set, only files owned by
# the user dnsmasq is running as will be send over the net.
#tftp-secure
@@ -628,3 +658,9 @@
# Include another lot of configuration options.
#conf-file=/etc/dnsmasq.more.conf
#conf-dir=/etc/dnsmasq.d
# Include all the files in a directory except those ending in .bak
#conf-dir=/etc/dnsmasq.d,.bak
# Include all files in a directory which end in .conf
#conf-dir=/etc/dnsmasq.d/,*.conf

137
doc.html
View File

@@ -1,8 +1,7 @@
<HTML>
<HEAD>
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
<link rel="icon"
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
<TITLE> Dnsmasq - network services for small networks.</TITLE>
<link rel="icon" href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
</HEAD>
<BODY BGCOLOR="WHITE">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
@@ -11,82 +10,48 @@
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
</table>
Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be
lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used
for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
server. It is designed to provide DNS and, optionally, DHCP, to a
small network. It can serve the names of local machines which are
not in the global DNS. The DHCP server integrates with the DNS
server and allows machines with DHCP-allocated addresses
to appear in the DNS with names configured either in each host or
in a central configuration file. Dnsmasq supports static and dynamic
DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
<P>
Dnsmasq is targeted at home networks using NAT and
connected to the internet via a modem, cable-modem or ADSL
connection but would be a good choice for any smallish network (up to
1000 clients is known to work) where low
resource use and ease of configuration are important.
<P>
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
Solaris and Mac OS X.
Dnsmasq is included in at least the following Linux distributions:
Gentoo, Debian, Slackware, Suse, Fedora,
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
CoyoteLinux, Endian Firewall and
Clarkconnect. It is also available as FreeBSD, OpenBSD and NetBSD ports and is used in
Linksys wireless routers (dd-wrt, openwrt and the stock firmware) and the m0n0wall project.
<P>
Dnsmasq provides the following features:
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
cacheing of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
<DIR>
<LI>
The DNS configuration of machines behind the firewall is simple and
doesn't depend on the details of the ISP's dns servers
<LI>
Clients which try to do DNS lookups while a modem link to the
internet is down will time out immediately.
</LI>
<LI>
Dnsmasq will serve names from the /etc/hosts file on the firewall
machine: If the names of local machines are there, then they can all
be addressed without having to maintain /etc/hosts on each machine.
</LI>
<LI>
The integrated DHCP server supports static and dynamic DHCP leases and
multiple networks and IP ranges. It works across BOOTP relays and
supports DHCP options including RFC3397 DNS search lists.
Machines which are configured by DHCP have their names automatically
included in the DNS and the names can specified by each machine or
centrally by associating a name with a MAC address in the dnsmasq
config file.
</LI>
<LI>
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
mappings (PTR records), reducing the load on upstream servers and
improving performance (especially on modem connections).
</LI>
<LI>
Dnsmasq can be configured to automatically pick up the addresses of
its upstream nameservers from ppp or dhcp configuration. It will
automatically reload this information if it changes. This facility
will be of particular interest to maintainers of Linux firewall
distributions since it allows dns configuration to be made automatic.
</LI>
<LI>
On IPv6-enabled boxes, dnsmasq can both talk to upstream servers via IPv6
and offer DNS service via IPv6. On dual-stack (IPv4 and IPv6) boxes it talks
both protocols and can even act as IPv6-to-IPv4 or IPv4-to-IPv6 forwarder.
</LI>
<LI>
Dnsmasq can be configured to send queries for certain domains to
upstream servers handling only those domains. This makes integration
with private DNS systems easy.
</LI>
<LI>
Dnsmasq supports MX and SRV records and can be configured to return MX records
for any or all local machines.
</LI>
<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
<LI>Upstream servers can be configured in a variety of convenient ways, including dynamic configuration as these change on moving upstream network.
<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides
zone transfer to secondaries for the zone, if required.</LI>
<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
<LI>Internationalised domain names are supported.
</DIR>
<P>
The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
<DIR>
<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
<LI> There is a built in read-only TFTP server to support netboot.</LI>
<LI> Machines which are configured by DHCP have their names automatically
included in the DNS and the names can specified by each machine or
centrally by associating a name with a MAC address or UID in the dnsmasq
configuration file.</LI>
</DIR>
<P>
The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
<DIR>
<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
<LI> Router advertisements can include the RDNSS option.</LI>
<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
</DIR>
<P>
For extra compactness, unused features may be omitted at compile time.
<H2>Get code.</H2>
@@ -102,15 +67,31 @@ the repo, or get a copy using git protocol with the command
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
<H2>License.</H2>
Dnsmasq is distributed under the GPL. See the file COPYING 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.
<H2>Contact.</H2>
There is a dnsmasq mailing list at <A
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
first location for queries, bugreports, suggestions etc.
Dnsmasq was written by Simon Kelley. You can contact me at <A
first location for queries, bugreports, suggestions etc. The list is mirrored, with a
search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</A>.
You can contact me at <A
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
<H2>Donations.</H2>
Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project.
These days I'm working on it as my main activity.
I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make
a contribution towards my expenses, please use the donation button below.
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
</BODY>

View File

@@ -13,7 +13,10 @@ Dnsmasq accepts DNS queries and either answers them from a small, local,
cache or forwards them to a real, recursive, DNS server. It loads the
contents of /etc/hosts so that local hostnames
which do not appear in the global DNS can be resolved and also answers
DNS queries for DHCP configured hosts. It can also act as the authoritative DNS server for one or more domains, allowing local names to appear in the global DNS.
DNS queries for DHCP configured hosts. It can also act as the
authoritative DNS server for one or more domains, allowing local names
to appear in the global DNS. It can be configured to do DNSSEC
validation.
.PP
The dnsmasq DHCP server supports static address assignments and multiple
networks. It automatically
@@ -47,6 +50,10 @@ Additional hosts file. Read the specified file as well as /etc/hosts. If -h is g
only the specified file. This option may be repeated for more than one
additional hosts file. If a directory is given, then read all the files contained in that directory.
.TP
.B --hostsdir=<path>
Read all the hosts files contained in the directory. New or changed files
are read automatically. See --dhcp-hostsdir for details.
.TP
.B \-E, --expand-hosts
Add the domain to simple names (without a period) in /etc/hosts
in the same way as for DHCP-derived names. Note that this does not
@@ -78,6 +85,12 @@ the upstream DNS servers.
.B --max-cache-ttl=<time>
Set a maximum TTL value for entries in the cache.
.TP
.B --min-cache-ttl=<time>
Extend short TTL values to the time given when caching them. Note that
artificially extending TTL values is in general a bad idea, do not do it
unless you have a good reason, and understand what you are doing.
Dnsmasq limits the value of this option to one hour, unless recompiled.
.TP
.B --auth-ttl=<time>
Set the TTL value returned in answers from the authoritative server.
.TP
@@ -95,7 +108,10 @@ only, to stop dnsmasq daemonising in production, use
.B -k.
.TP
.B \-q, --log-queries
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1.
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
.B --log-queries=extra
then the log has extra information at the start of each line.
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor.
.TP
.B \-8, --log-facility=<facility>
Set the facility to which dnsmasq will send syslog entries, this
@@ -199,7 +215,20 @@ or
.B --listen-address
configuration, indeed
.B --auth-server
will overide these and provide a different DNS service on the specified interface. The <domain> is the "glue record". It should resolve in the global DNS to a A and/or AAAA record which points to the address dnsmasq is listening on.
will overide these and provide a different DNS service on the
specified interface. The <domain> is the "glue record". It should
resolve in the global DNS to a A and/or AAAA record which points to
the address dnsmasq is listening on. When an interface is specified,
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
addresses associated with the interface.
.TP
.B --local-service
Accept DNS queries only from hosts whose address is on a local subnet,
ie a subnet for which an interface exists on the server. This option
only has effect is there are no --interface --except-interface,
--listen-address or --auth-server options. It is intended to be set as
a default on installation, to allow unconfigured installations to be
useful but also safe from being used for DNS amplification attacks.
.TP
.B \-2, --no-dhcp-interface=<interface name>
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
@@ -277,6 +306,12 @@ an advertising web page in response to queries for unregistered names,
instead of the correct NXDOMAIN response. This option tells dnsmasq to
fake the correct response when it sees this behaviour. As at Sept 2003
the IP address being returned by Verisign is 64.94.110.11
.TP
.B \-B, --ignore-address=<ipaddr>
Ignore replies to A-record queries which include the specified address.
No error is generated, dnsmasq simply continues to listen for another reply.
This is useful to defeat blocking strategies which rely on quickly supplying a
forged answer to a DNS request for certain domain, before the correct answer can arrive.
.TP
.B \-f, --filterwin2k
Later versions of windows make periodic DNS requests which don't get sensible answers from
@@ -318,6 +353,16 @@ it will send queries to just one server. Setting this flag forces
dnsmasq to send all queries to all available servers. The reply from
the server which answers first will be returned to the original requester.
.TP
.B --dns-loop-detect
Enable code to detect DNS forwarding loops; ie the situation where a query sent to one
of the upstream server eventually returns as a new query to the dnsmasq instance. The
process works by generating TXT queries of the form <hex>.test and sending them to
each upstream server. The hex is a UID which encodes the instance of dnsmasq sending the query
and the upstream server to which it was sent. If the query returns to the server which sent it, then
the upstream server through which it was sent is disabled and this event is logged. Each time the
set of upstream servers changes, the test is re-run on all of them, including ones which
were previously disabled.
.TP
.B --stop-dns-rebind
Reject (and log) addresses from upstream nameservers which are in the
private IP ranges. This blocks an attack where a browser behind a
@@ -338,7 +383,8 @@ by '/', like the --server syntax, eg.
Don't poll /etc/resolv.conf for changes.
.TP
.B --clear-on-reload
Whenever /etc/resolv.conf is re-read, clear the DNS cache.
Whenever /etc/resolv.conf is re-read or the upstream servers are set
via DBus, clear the DNS cache.
This is useful when new nameservers may have different
data than that held in cache.
.TP
@@ -406,7 +452,15 @@ source address specified but the port may be specified directly as
part of the source address. Forcing queries to an interface is not
implemented on all platforms supported by dnsmasq.
.TP
.B \-A, --address=/<domain>/[domain/]<ipaddr>
.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
This is functionally the same as
.B --server,
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
.B --rev-server=1.2.3.0/24,192.168.0.1
is exactly equivalent to
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
.TP
.B \-A, --address=/<domain>/[domain/][<ipaddr>]
Specify an IP address to return for any host in the given domains.
Queries in the domains are never forwarded and always replied to
with the specified IP address which may be IPv4 or IPv6. To give
@@ -418,7 +472,10 @@ domain specification works in the same was as for --server, with the
additional facility that /#/ matches any domain. Thus
--address=/#/1.2.3.4 will always return 1.2.3.4 for any query not
answered from /etc/hosts or DHCP and not sent to an upstream
nameserver by a more specific --server directive.
nameserver by a more specific --server directive. As for --server,
one or more domains with no address returns a no-such-domain answer, so
--address=/example.com/ is equivalent to --server=/example.com/ and returns
NXDOMAIN for example.com and all its subdomains.
.TP
.B --ipset=/<domain>/[domain/]<ipset>[,<ipset>]
Places the resolved IP addresses of queries for the specified domains
@@ -462,7 +519,7 @@ zone files: the port, weight and priority numbers are in a different
order. More than one SRV record for a given service/domain is allowed,
all that match are returned.
.TP
.B --host-record=<name>[,<name>....][<IPv4-address>],[<IPv6-address>]
.B --host-record=<name>[,<name>....],[<IPv4-address>],[<IPv6-address>]
Add A, AAAA and PTR records to the DNS. This adds one or more names to
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
appear in more than one
@@ -496,7 +553,7 @@ Return an NAPTR DNS record, as specified in RFC3403.
Return a CNAME record which indicates that <cname> is really
<target>. There are significant limitations on the target; it must be a
DNS name which is known to dnsmasq from /etc/hosts (or additional
hosts files), from DHCP or from another
hosts files), from DHCP, from --interface-name or from another
.B --cname.
If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it
@@ -508,11 +565,13 @@ record (which is always in the C_IN class). The value of the record is
given by the hex data, which may be of the form 01:23:45 or 01 23 45 or
012345 or any mixture of these.
.TP
.B --interface-name=<name>,<interface>
.B --interface-name=<name>,<interface>[/4|/6]
Return a DNS record associating the name with the primary address on
the given interface. This flag specifies an A record for the given
the given interface. This flag specifies an A or AAAA record for the given
name in the same way as an /etc/hosts line, except that the address is
not constant, but taken from the given interface. If the interface is
not constant, but taken from the given interface. The interface may be
followed by "/4" or "/6" to specify that only IPv4 or IPv6 addresses
of the interface should be used. If the interface is
down, not configured or non-existent, an empty record is returned. The
matching PTR record is also created, mapping the interface address to
the name. More than one name may be associated with an interface
@@ -542,7 +601,20 @@ server. The MAC address can only be added if the requestor is on the same
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
is not yet standardised, so this should be considered
experimental. Also note that exposing MAC addresses in this way may
have security and privacy implications.
have security and privacy implications. The warning about caching
given for --add-subnet applies to --add-mac too.
.TP
.B --add-subnet[[=<IPv4 prefix length>],<IPv6 prefix length>]
Add the subnet address of the requestor to the DNS queries which are
forwarded upstream. The amount of the address forwarded depends on the
prefix length parameter: 32 (128 for IPv6) forwards the whole address,
zero forwards none of it but still marks the request so that no
upstream nameserver will add client address information either. The
default is zero for both IPv4 and IPv6. Note that upstream nameservers
may be configured to return different results based on this
information, but the dnsmasq cache does not take account. If a dnsmasq
instance is configured such that different results may be encountered,
caching should be disabled.
.TP
.B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
@@ -558,27 +630,96 @@ Set the maximum number of concurrent DNS queries. The default value is
where this needs to be increased is when using web-server log file
resolvers, which can generate large numbers of concurrent queries.
.TP
.B --proxy-dnssec
A resolver on a client machine can do DNSSEC validation in two ways: it
can perform the cryptograhic operations on the reply it receives, or
it can rely on the upstream recursive nameserver to do the validation
and set a bit in the reply if it succeeds. Dnsmasq is not a DNSSEC
validator, so it cannot perform the validation role of the recursive nameserver,
but it can pass through the validation results from its own upstream
nameservers. This option enables this behaviour. You should only do
this if you trust all the configured upstream nameservers
.I and the network between you and them.
If you use the first DNSSEC mode, validating resolvers in clients,
this option is not required. Dnsmasq always returns all the data
needed for a client to do validation itself.
.B --dnssec
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
DNSSEC records needed to validate the replies. The replies are validated and the result returned as
the Authenticated Data bit in the DNS packet. In addition the DNSSEC records are stored in the cache, making
validation by clients more efficient. Note that validation by clients is the most secure DNSSEC mode, but for
clients unable to do validation, use of the AD bit set by dnsmasq is useful, provided that the network between
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
trust anchors provided, see
.B --trust-anchor.
Because the DNSSEC validation process uses the cache, it is not
permitted to reduce the cache size below the default when DNSSEC is
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
ie capable of returning DNSSEC records with data. If they are not,
then dnsmasq will not be able to determine the trusted status of
answers. In the default mode, this menas that all replies will be
marked as untrusted. If
.B --dnssec-check-unsigned
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
.TP
.B --auth-zone=<domain>[,<subnet>[,<subnet>.....]]
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
Provide DS records to act a trust anchors for DNSSEC
validation. Typically these will be the DS record(s) for Zone Signing
key(s) of the root zone,
but trust anchors for limited domains are also possible. The current
root-zone trust anchors may be downloaded from https://data.iana.org/root-anchors/root-anchors.xml
.TP
.B --dnssec-check-unsigned
As a default, dnsmasq does not check that unsigned DNS replies are
legitimate: they are assumed to be valid and passed on (without the
"authentic data" bit set, of course). This does not protect against an
attacker forging unsigned replies for signed DNS zones, but it is
fast. If this flag is set, dnsmasq will check the zones of unsigned
replies, to ensure that unsigned replies are allowed in those
zones. The cost of this is more upstream queries and slower
performance. See also the warning about upstream servers in the
section on
.B --dnssec
.TP
.B --dnssec-no-timecheck
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
which have not been throughly checked.
.TP
.B --dnssec-timestamp=<path>
Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the
system time is considered to be valid once it becomes later than the timestamp on the specified file. The file is created and
its timestamp set automatically by dnsmasq. The file must be stored on a persistent filesystem, so that it and its mtime are carried
over system restarts. The timestamp file is created after dnsmasq has dropped root, so it must be in a location writable by the
unprivileged user that dnsmasq runs as.
.TP
.B --proxy-dnssec
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
alternative to having dnsmasq validate DNSSEC, but it depends on the security of the network between
dnsmasq and the upstream servers, and the trustworthiness of the upstream servers.
.TP
.B --dnssec-debug
Set debugging mode for the DNSSEC validation, set the Checking Disabled bit on upstream queries,
and don't convert replies which do not validate to responses with
a return code of SERVFAIL. Note that
setting this may affect DNS behaviour in bad ways, it is not an
extra-logging flag and should not be set in production.
.TP
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
will be served, except that A and AAAA records must be in one of the
specified subnets, or in a subnet corresponding to a constructed DHCP
range. The subnet(s) are also used to define in-addr.arpa and
ipv6.arpa domains which are served for reverse-DNS queries. For IPv4
subnets, the prefix length is limited to the values 8, 16 or 24.
will be served. If subnet(s) are given, A and AAAA records must be in one of the
specified subnets.
As alternative to directly specifying the subnets, it's possible to
give the name of an interface, in which case the subnets implied by
that interface's configured addresses and netmask/prefix-length are
used; this is useful when using constructed DHCP ranges as the actual
address is dynamic and not known when configuring dnsmasq. The
interface addresses may be confined to only IPv6 addresses using
<interface>/6 or to only IPv4 using <interface>/4. This is useful when
an interface has dynamically determined global IPv6 addresses which should
appear in the zone, but RFC1918 IPv4 addresses which should not.
Interface-name and address-literal subnet specifications may be used
freely in the same --auth-zone declaration.
The subnet(s) are also used to define in-addr.arpa and
ip6.arpa domains which are served for reverse-DNS queries. If not
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
unless you are familiar with RFC 2317 and have arranged the
in-addr.arpa delegation accordingly. Note that if no subnets are
specified, then no reverse queries are answered.
.TP
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
Specify fields in the SOA record associated with authoritative
@@ -635,7 +776,8 @@ always optional. It is always
allowed to have more than one dhcp-range in a single subnet.
For IPv6, the parameters are slightly different: instead of netmask
and broadcast address, there is an optional prefix length. If not
and broadcast address, there is an optional prefix length which must
be equal to or larger then the prefix length on the local interface. If not
given, this defaults to 64. Unlike the IPv4 case, the prefix length is not
automatically derived from the interface configuration. The mimimum
size of the prefix length is 64.
@@ -646,7 +788,20 @@ This forms a template which describes how to create ranges, based on the address
.B --dhcp-range=::1,::400,constructor:eth0
will look for addresses of the form <network>::1 on eth0 and then create a range from <network>::1 to <network>::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard.
will look for addresses on
eth0 and then create a range from <network>::1 to <network>::400. If
the interface is assigned more than one network, then the
corresponding ranges will be automatically created, and then
deprecated and finally removed again as the address is deprecated and
then deleted. The interface name may have a final "*" wildcard. Note
that just any address on eth0 will not do: it must not be an
autoconfigured or privacy address, or be deprecated.
If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
then the address can be simply ::
.B --dhcp-range=::,constructor:eth0
The optional
.B set:<tag>
@@ -666,7 +821,7 @@ or from /etc/ethers will be served. A static-only subnet with address
all zeros may be used as a "catch-all" address to enable replies to all
Information-request packets on a subnet which is provided with
stateless DHCPv6, ie
.B --dhcp=range=::,static
.B --dhcp-range=::,static
For IPv4, the <mode> may be
.B proxy
@@ -678,7 +833,7 @@ and
for details.)
For IPv6, the mode may be some combination of
.B ra-only, slaac, ra-names, ra-stateless.
.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter, off-link.
.B ra-only
tells dnsmasq to offer Router Advertisement only on this subnet,
@@ -713,6 +868,14 @@ can be combined with
and
.B slaac.
.B ra-advrouter
enables a mode where router address(es) rather than prefix(es) are included in the advertisements.
This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option
is also included, as described in RFC-3775 section 7.3.
.B off-link
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
.TP
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine
@@ -737,7 +900,8 @@ the same subnet as some valid dhcp-range. For
subnets which don't need a pool of dynamically allocated addresses,
use the "static" keyword in the dhcp-range declaration.
It is allowed to use client identifiers rather than
It is allowed to use client identifiers (called client
DUID in IPv6-land rather than
hardware addresses to identify hosts by prefixing with 'id:'. Thus:
.B --dhcp-host=id:01:02:03:04,.....
refers to the host with client identifier 01:02:03:04. It is also
@@ -752,11 +916,12 @@ IPv6 addresses may contain only the host-identifier part:
.B --dhcp-host=laptop,[::56]
in which case they act as wildcards in constructed dhcp ranges, with
the appropriate network part inserted.
Note that in IPv6 DHCP, the hardware address is not normally
available, so a client must be identified by client-id (called client
DUID in IPv6-land) or hostname.
Note that in IPv6 DHCP, the hardware address may not be
available, though it normally is for direct-connected clients, or
clients using DHCP relays which support RFC 6939.
The special option id:* means "ignore any client-id
For DHCPv4, the special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others.
@@ -829,6 +994,18 @@ is given, then read all the files contained in that directory. The advantage of
using this option is the same as for --dhcp-hostsfile: the
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a
.TP
.B --dhcp-hostsdir=<path>
This is equivalent to dhcp-hostsfile, except for the following. The path MUST be a
directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP.
If a file is deleted for changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq recieves a SIGHUP, or
is restarted; ie host records are only added dynamically.
.TP
.B --dhcp-optsdir=<path>
This is equivalent to dhcp-optsfile, with the differences noted for --dhcp-hostsdir.
.TP
.B --dhcp-boot
flag as DHCP options, using the options names bootfile-name,
server-ip-address and tftp-server. This allows these to be included
@@ -863,9 +1040,11 @@ and to set the time-server address to 192.168.0.4, do
.B --dhcp-option = 42,192.168.0.4
or
.B --dhcp-option = option:ntp-server, 192.168.0.4
The special address 0.0.0.0 (or [::] for DHCPv6) is taken to mean "the address of the
machine running dnsmasq". Data types allowed are comma separated
dotted-quad IP addresses, a decimal number, colon-separated hex digits
The special address 0.0.0.0 is taken to mean "the address of the
machine running dnsmasq".
Data types allowed are comma separated
dotted-quad IPv4 addresses, []-wrapped IPv6 addresses, a decimal number, colon-separated hex digits
and a text string. If the optional tags are given then
this option is only sent when all the tags are matched.
@@ -881,7 +1060,9 @@ keyword, followed by the option number or option name. The IPv6 option
name space is disjoint from the IPv4 option name space. IPv6 addresses
in options must be bracketed with square brackets, eg.
.B --dhcp-option=option6:ntp-server,[1234::56]
For IPv6, [::] means "the global address of
the machine running dnsmasq", whilst [fd00::] is replaced with the
ULA, if it exists, and [fe80::] with the link-local address.
Be careful: no checking is done that the correct type of data for the
option number is sent, it is quite possible to
@@ -944,6 +1125,38 @@ DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case.
.TP
.B --dhcp-relay=<local address>,<server address>[,<interface]
Configure dnsmasq to do DHCP relay. The local address is an address
allocated to an interface on the host running dnsmasq. All DHCP
requests arriving on that interface will we relayed to a remote DHCP
server at the server address. It is possible to relay from a single local
address to multiple remote servers by using multiple dhcp-relay
configs with the same local address and different server
addresses. A server address must be an IP literal address, not a
domain name. In the case of DHCPv6, the server address may be the
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
must be given, not be wildcard, and is used to direct the multicast to the
correct interface to reach the DHCP server.
Access control for DHCP clients has the same rules as for the DHCP
server, see --interface, --except-interface, etc. The optional
interface name in the dhcp-relay config has a different function: it
controls on which interface DHCP replies from the server will be
accepted. This is intended for configurations which have three
interfaces: one being relayed from, a second connecting the DHCP
server, and a third untrusted network, typically the wider
internet. It avoids the possibility of spoof replies arriving via this
third interface.
It is allowed to have dnsmasq act as a DHCP server on one set of
interfaces and relay from a disjoint set of interfaces. Note that
whilst it is quite possible to write configurations which appear to
act as a server and a relay on the same interface, this is not
supported: the relay function will take precedence.
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
DHCPv4 to a DHCPv6 server or vice-versa.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
Map from a vendor-class string to a tag. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This option
@@ -972,7 +1185,7 @@ this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering".
.TP
.B \-4, --dhcp-mac=set:<tag>,<MAC address>
(IPv4 only) Map from a MAC address to a tag. The MAC address may include
Map from a MAC address to a tag. The MAC address may include
wildcards. For example
.B --dhcp-mac=set:3com,01:34:23:*:*:*
will set the tag "3com" for any host whose MAC address matches the pattern.
@@ -1178,7 +1391,7 @@ enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP
.B \-5, --no-ping
(IPv4 only) By default, the DHCP server will attempt to ensure that an address in
(IPv4 only) By default, the DHCP server will attempt to ensure that an address is
not in use before allocating it to a host. It does this by sending an
ICMP echo request (aka "ping") to the address in question. If it gets
a reply, then the address must already be in use, and another is
@@ -1188,6 +1401,11 @@ tried. This flag disables this check. Use with caution.
Extra logging for DHCP: log all the options sent to DHCP clients and
the tags used to determine them.
.TP
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
Suppress logging of the routine operation of these protocols. Errors and
problems will still be logged. --quiet-dhcp and quiet-dhcp6 are
over-ridden by --log-dhcp.
.TP
.B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information.
.TP
@@ -1278,7 +1496,7 @@ every call to the script.
DNSMASQ_IAID containing the IAID for the lease. If the lease is a
temporary allocation, this is prefixed to 'T'.
DNSMASQ_MAC containing the MAC address of the client, if known.
Note that the supplied hostname, vendorclass and userclass data is
only supplied for
@@ -1382,10 +1600,13 @@ option also forces the leasechange script to be called on changes
to the client-id and lease length and expiry time.
.TP
.B --bridge-interface=<interface>,<alias>[,<alias>]
Treat DHCP request packets arriving at any of the <alias> interfaces
as if they had arrived at <interface>. This option is necessary when
using "old style" bridging on BSD platforms, since
packets arrive at tap interfaces which don't have an IP address.
Treat DHCP (v4 and v6) request and IPv6 Router Solicit packets
arriving at any of the <alias> interfaces as if they had arrived at
<interface>. This option allows dnsmasq to provide DHCP and RA
service over unaddressed and unbridged Ethernet interfaces, e.g. on an
OpenStack compute host where each such interface is a TAP interface to
a VM, or as in "old style bridging" on BSD platforms. A trailing '*'
wildcard can be used in each <alias>.
.TP
.B \-s, --domain=<domain>[,<address range>[,local]]
Specifies DNS domains for the DHCP server. Domains may be be given
@@ -1466,11 +1687,26 @@ the relevant link-local address of the machine running dnsmasq is sent
as recursive DNS server. If provided, the DHCPv6 options dns-server and
domain-search are used for RDNSS and DNSSL.
.TP
.B --enable-tftp
.B --ra-param=<interface>,[high|low],[[<ra-interval>],<router lifetime>]
Set non-default values for router advertisements sent via an
interface. The priority field for the router may be altered from the
default of medium with eg
.B --ra-param=eth0,high.
The interval between router advertisements may be set (in seconds) with
.B --ra-param=eth0,60.
The lifetime of the route may be changed or set to zero, which allows
a router to advertise prefixes but not a route via itself.
.B --ra-parm=eth0,0,0
(A value of zero for the interval means the default value.) All three parameters may be set at once.
.B --ra-param=low,60,1200
The interface field may include a wildcard.
.TP
.B --enable-tftp[=<interface>[,<interface>]]
Enable the TFTP server function. This is deliberately limited to that
needed to net-boot a client. Only reading is allowed; the tsize and
blksize extensions are supported (tsize is only supported in octet
mode).
mode). Without an argument, the TFTP service is provided to the same set of interfaces as DHCP service.
If the list of interfaces is provided, that defines which interfaces recieve TFTP service.
.TP
.B --tftp-root=<directory>[,<interface>]
Look for files to transfer using TFTP relative to the given
@@ -1480,6 +1716,9 @@ Absolute paths (starting with /) are allowed, but they must be within
the tftp-root. If the optional interface argument is given, the
directory is only used for TFTP requests via that interface.
.TP
.B --tftp-no-fail
Do not abort startup if specified tftp root directories are inaccessible.
.TP
.B --tftp-unique-root
Add the IP address of the TFTP client as a path component on the end
of the TFTP-root (in standard dotted-quad format). Only valid if a
@@ -1535,12 +1774,23 @@ Specify a different configuration file. The conf-file option is also allowed in
configuration files, to include multiple configuration files. A
filename of "-" causes dnsmasq to read configuration from stdin.
.TP
.B \-7, --conf-dir=<directory>[,<file-extension>......]
.B \-7, --conf-dir=<directory>[,<file-extension>......],
Read all the files in the given directory as configuration
files. If extension(s) are given, any files which end in those
extensions are skipped. Any files whose names end in ~ or start with . or start and end
with # are always skipped. This flag may be given on the command
line or in a configuration file.
with # are always skipped. If the extension starts with * then only files
which have that extension are loaded. So
.B --conf-dir=/path/to/dir,*.conf
loads all files with the suffix .conf in /path/to/dir. This flag may be given on the command
line or in a configuration file. If giving it on the command line, be sure to
escape * characters.
.TP
.B --servers-file=<file>
A special case of
.B --conf-file
which differs in two respects. Firstly, only --server and --rev-server are allowed
in the configuration file included. Secondly, the file is re-read and the configuration
therein is updated when dnsmasq recieves SIGHUP.
.SH CONFIG FILE
At startup, dnsmasq reads
.I /etc/dnsmasq.conf,
@@ -1566,7 +1816,8 @@ clears its cache and then re-loads
.I /etc/hosts
and
.I /etc/ethers
and any file given by --dhcp-hostsfile, --dhcp-optsfile or --addn-hosts.
and any file given by --dhcp-hostsfile, --dhcp-hostsdir, --dhcp-optsfile,
--dhcp-optsdir, --addn-hosts or --hostsdir.
The dhcp lease change script is called for all
existing DHCP leases. If
.B
@@ -1581,12 +1832,22 @@ When it receives a SIGUSR1,
writes statistics to the system log. It writes the cache size,
the number of names which have had to removed from the cache before
they expired in order to make room for new names and the total number
of names that have been inserted into the cache. For each upstream
of names that have been inserted into the cache. The number of cache hits and
misses and the number of authoritative queries answered are also given. For each upstream
server it gives the number of queries sent, and the number which
resulted in an error. In
.B --no-daemon
mode or when full logging is enabled (-q), a complete dump of the
contents of the cache is made.
contents of the cache is made.
The cache statistics are also available in the DNS as answers to
queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
.B dig
utility would be
dig +short chaos txt cachesize.bind
.PP
When it receives SIGUSR2 and it is logging direct to a file (see
.B --log-facility
@@ -1690,7 +1951,7 @@ which has tags will be used in preference to an untagged
.B dhcp-option,
provided that _all_ the tags match somewhere in the
set collected as described above. The prefix '!' on a tag means 'not'
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
tag purple is not in the set of valid tags. (If using this in a
command line rather than a configuration file, be sure to escape !,
which is a shell metacharacter)
@@ -1807,9 +2068,13 @@ Something like:
.nf
.B auth-server=our.zone.com,eth0
.B interface-name=our.zone.com,eth0
.B auth-zone=our.zone.com,1.2.3.0/24
.B auth-zone=our.zone.com,1.2.3.0/24,eth0
.fi
(The "eth0" argument in auth-zone adds the subnet containing eth0's
dynamic address to the zone, so that the interface-name returns the
address in outside queries.)
Our final configuration builds on that above, but also adds a
secondary DNS server. This is another DNS server which learns the DNS data
for the zone by doing zones transfer, and acts as a backup should
@@ -1838,7 +2103,7 @@ to particular hosts then
will do so.
Dnsmasq acts as an authoritative server for in-addr.arpa and
ipv6.arpa domains associated with the subnets given in auth-zone
ip6.arpa domains associated with the subnets given in auth-zone
declarations, so reverse (address to name) lookups can be simply
configured with a suitable NS record, for instance in this example,
where we allow 1.2.3.0/24 addresses.
@@ -1867,18 +2132,20 @@ IPv4 and IPv6 addresses from /etc/hosts (and
.B --addn-hosts
) and
.B --host-record
and
.B --interface-name
provided the address falls into one of the subnets specified in the
.B --auth-zone.
.PP
Addresses specified by
.B --interface-name.
In this case, the address is not contrained to a subnet from
.B --auth-zone.
.PP
Addresses of DHCP leases, provided the address falls into one of the subnets specified in the
.B --auth-zone.
(If contructed DHCP ranges are is use, which depend on the address dynamically
assigned to an interface, then the form of
.B --auth-zone
OR a constructed DHCP range. In the default mode, where a DHCP lease
which defines subnets by the dynamic address of an interface should
be used to ensure this condition is met.)
.PP
In the default mode, where a DHCP lease
has an unqualified name, and possibly a qualified name constructed
using
.B --domain

View File

@@ -1062,10 +1062,14 @@ esta opci
cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
.TP
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
como si hubieran llegado a la interface <nombre de interface>. Esta opción
es necesaria al usar bridging estilo viejo en plataformas BSD, dado a que
los paquetes llegan a interfaces tap que no tienen una dirección IP.
Tratar paquetes de pedidos DHCP (v4 y v6) y de IPv6 Router Solicit que
llegan a cualquiera de las interfaces <alias> como si hubieran llegado
a la interface <nombre de interface>. Esta opción permite que dnsmasq
puede proporcionar los servicios DHCP y RA a través de interfaces
ethernet sin dirección y sin puente; por ejemplo en un nodo de cálculo
de OpenStack, donde cada una de esas interfaces es una interfaz TAP
para una máquina virtual, o al usar bridging estilo viejo en
plataformas BSD.
.TP
.B \-s, --domain=<dominio>[,<rango de IPs>]
Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser

View File

@@ -403,7 +403,8 @@ noms de domains entourés par des '/', selon une syntaxe similaire à l'option
Ne pas vérifier régulièrement si le fichier /etc/resolv.conf a été modifié.
.TP
.B --clear-on-reload
Lorsque le fichier /etc/resolv.conf est relu, vider le cache DNS.
Lorsque le fichier /etc/resolv.conf est relu, ou si les serveurs amonts sont
configurés via DBus, vider le cache DNS.
Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
différentes de celles stockées dans le cache.
.TP
@@ -596,9 +597,9 @@ Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
.TP
.B --cname=<cname>,<cible>
Retourne un enregistrement de type CNAME qui indique que <cname> est en
réalité <cible>. Il existe des contraintes significatives sur la valeur
de cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
(ou un fichier hôtes additionnel), ou via DHCP, ou par un autre
réalité <cible>. Il existe des contraintes importantes sur la valeur
cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
(ou un fichier hôtes additionnel), via DHCP, via interface--name ou par un autre
.B --cname.
Si une cible ne satisfait pas ces critères, le CNAME est ignoré. Le CNAME
doit être unique, mais il est autorisé d'avoir plus d'un CNAME pointant
@@ -622,6 +623,24 @@ Plus d'un nom peut être associé à une interface donnée en répétant cette o
plusieurs fois; dans ce cas, l'enregistrement inverse pointe vers le nom fourni
dans la première instance de cette option.
.TP
.B --synth-domain=<domaine>,<plage d'adresses>[,<préfixe>]
Créé des enregistrements A/AAAA ou PTR pour une plage d'adresses. Les
enregistrements utilisent l'adresse ainsi que les points (ou les deux points
dans le cas d'IPv6) remplacés par des tirets.
Un exemple devrait rendre cela plus clair :
La configuration
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
permet de retourner internal-192-168-0-56.thekelleys.org.uk lors d'une requête
sur l'adresse 192.168.0.56 et vice-versa pour la requête inverse. La même
logique s'applique pour IPv6, avec la particularité suivante : les adresses
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.
Ainsi, ::1 devient 0--1.
La plage d'adresses peut-être de la forme
<adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau>
.TP
.B --add-mac
Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises aux serveurs
amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
@@ -630,7 +649,20 @@ 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,
aussi cette fonctionalité doit être considérée comme expérimentale. Notez
également qu'exposer les adresses MAC de la sorte peut avoir des implications
en termes de sécurité et de vie privée.
en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet
s'applique également ici.
.TP
.B --add-subnet[[=<longueur de préfixe IPv4>],<longueur de préfixe IPv6>]
Rajoute l'adresse de sous-réseau du requêteur aux requêtes DNS transmises
aux serveurs amonts. La quantité d'adresses transmises dépend du paramètre
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
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
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.
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é.
.TP
.B \-c, --cache-size=<taille>
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
@@ -665,15 +697,20 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
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.
.TP
.B --auth-zone=<domaine>[,<sous-réseau>[,<sous-réseau>.....]]
.B --auth-zone=<domaine>[,<sous-réseau>[/<longueur de préfixe>][,<sous-réseau>[/<longueur de préfixe>].....]]
Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
autorité. Les enregistrements DNS définis localement et correspondant à ce
domaine seront fournis, à ceci près que les enregistrements A et AAAA doivent
se situer dans l'un des sous-réseaux précisés si ceux-ci sont définis, ou dans
un réseau correspondant à une plage DHCP. Le ou les sous-réseaux sont également
utilisé pour définir les domaines in-addr.arpa et ipv6.arpa servant à
l'interrogation DNS inverse. Dans le cas d'IPv4, la longueur du masque de
réseau doit être de 8, 16 ou 24.
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
(ce comportement peut-être désactivé par
.B constructor-noauth:
). 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
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
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.
.TP
.B --auth-soa=<numéro de série>[,<mainteneur de zone (hostmaster)>[,<rafraichissement>[,<nombre de réessais>[,<expiration>]]]]
Spécifie les champs de l'enregistrement de type SOA (Start Of Authority)
@@ -762,6 +799,27 @@ rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
final.
provoque la recherche d'adresses sur eth0 et crée une plage allant de
<réseau>::1 à <réseau>:400. Si l'interface est assignée à
plus d'un réseau, les plages correspondantes seront respectivement
automatiquement créées, rendues obsolètes et supprimées lorsque l'adresse
est rendue obsolète et supprimée. Le nom de l'interface peut être spécifié avec
un caractère joker '*' final. Les adresses autoconfigurées, privées ou
obsolètes ne conviennent pas.
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
peut-être indiquée sous la forme '::'
.B --dhcp-range=::,constructor:eth0
Il existe une variante de la syntaxe constructor: qui consiste en l'utilisation
du mot-clef
.B constructor-noauth.
Voir
.B --auth-zone
pour des explications à ce sujet.
L'identifiant de label optionnel
.B set:<label>
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
@@ -794,7 +852,7 @@ et
pour plus de détails).
Pour IPv6, le mode peut-être une combinaison des valeurs
.B ra-only, slaac, ra-names, ra-stateless.
.B ra-only, slaac, ra-names, ra-stateless, off-link.
.B ra-only
indique à dnsmasq de n'effectuer que des annonces de routeur (Router
@@ -830,6 +888,9 @@ peut-être combiné avec
et
.B slaac.
.B off-link
indique à dnsmasq d'annoncer le préfixe sans le bit L (sur lien).
.TP
.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,set:<label>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
@@ -853,9 +914,9 @@ 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
déclaration de plage d'adresses dhcp-range.
Il est possible
d'utiliser des identifiants clients plutôt que des adresses matérielles pour
identifier les hôtes, en préfixant par ceux-ci par 'id:'. Ainsi,
Il est possible d'utiliser des identifiants clients (appellé "DUID client" dans
le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes,
en préfixant ceux-ci par 'id:'. Ainsi,
.B --dhcp-host=id:01:02:03:04,.....
réfère à l'hôte d'identifiant 01:02:03:04. Il est également possible de
spécifier l'identifiant client sous la forme d'une chaîne de caractères, comme
@@ -871,11 +932,13 @@ Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
.B --dhcp-host=laptop,[::56]
Dans ce cas, lorsque des plages dhcp sont définies automatiquement par le biais
de constructeurs, la partie réseau correspondante est rajoutée à l'adresse.
A noter que pour le DHCP IPv6, l'adresse matérielle n'est en principe pas
disponible, aussi un client doit-être identifié par un identifiant de client
(appellé "DUID client") ou un nom d'hôte.
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
A noter que pour le DHCP IPv6, l'adresse matérielle n'est pas toujours
disponible, bien que ce soit toujours le cas pour des clients directement
connectés (sur le même domaine de broadcast) ou pour des clients utilisant
des relais DHCP qui supportent la RFC 6939.
En DHCPv4, l'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
que l'adresse matérielle". Cela est utile lorsqu'un client présente un
identifiant client mais pas les autres.
@@ -1079,6 +1142,40 @@ quelques rares cas, perturber des clients vieux ou défectueux. Cette
option force le comportement à l'utilisation des valeurs "simples et sûres"
afin d'éviter des problèmes dans de tels cas.
.TP
.B --dhcp-relay=<adresse locale>,<adresse de serveur>[,<interface]
Configure dnsmasq en temps que relais DHCP. L'adresse locale est une
adresse allouée à l'une interface de la machine sur laquelle tourne dnsmasq.
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
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
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
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
joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le
multicast pourra atteindre le serveur DHCP.
Le contrôle d'accès pour les clients DHCP suivent les mêmes règles que pour
les serveurs DHCP : voir --interface, --except-interface, etc. Le nom
d'interface optionel dans l'option dhcp-relay comporte une autre fonction :
il contrôle l'interface sur laquelle la réponse du serveur sera acceptée. Cela
sert par exemple dans des configurations à 3 interfaces : une à partir de
laquelle les requêtes sont relayées, une seconde permettant de se connecter à
un serveur DHCP, et une troisième reliée à un réseau non-sécurisé tel
qu'internet. Cela permet d'éviter l'arrivée de requêtes usurpées via cette
troisième interface.
Il est permis de configurer dnsmasq pour fonctionner comme serveur DHCP sur
certaines interfaces et en temps que relais sur d'autres. Cependant, même s'il
est possible de configurer dnsmasq de telle manière qu'il soit à la fois
serveur et relais pour une même interface, cela n'est pas supporté et la
fonction de relais prendra le dessus.
Le relais DHCPv4 et le relais DHCPv6 sont tous les deux supportés, mais il
n'est pas possible de relayer des requêtes DHCPv4 à un serveur DHCPv6 et
vice-versa.
.TP
.B \-U, --dhcp-vendorclass=set:<label>,[enterprise:<numéro IANA d'enterprise>,]<classe de vendeur>
Associe une chaîne de classe de vendeur à un label. La plupart
@@ -1113,7 +1210,7 @@ d'impression différent pour les hôtes de la classe "comptes" et ceux de la
classe "ingénierie".
.TP
.B \-4, --dhcp-mac=set:<label>,<adresse MAC>
(IPv4 uniquement) Associe une adresse matérielle (MAC) à un label. L'adresse
Associe une adresse matérielle (MAC) à un label. L'adresse
matérielle peut inclure des jokers. Par exemple
.B --dhcp-mac=set:3com,01:34:23:*:*:*
permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
@@ -1354,6 +1451,11 @@ Traces additionnelles pour le service DHCP : enregistre toutes les options
envoyées aux clients DHCP et les labels utilisés pour la
détermination de celles-ci.
.TP
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
Supprime les logs des opérations de routine des protocoles concernés. Les
erreurs et les problèmes seront toujours enregistrés. L'option --log-dhcp
prends le pas sur --quiet-dhcp et quiet-dhcp6.
.TP
.B \-l, --dhcp-leasefile=<chemin de fichier>
Utilise le fichier dont le chemin est fourni pour stocker les informations de
baux DHCP.
@@ -1447,6 +1549,8 @@ pour chaque appel au script.
DNSMASQ_IAID contenant l'IAID pour le bail. Si le bail est une allocation
temporaire, cela est préfixé par le caractère 'T'.
DNSMASQ_MAC contient l'adresse MAC du client, si celle-ci est connue.
A noter que le nom d'hôte fourni, la classe de vendeur ou les données de classe
d'utilisateur sont uniquement fournies pour les actions "add" ou l'action "old"
lorsqu'un hôte reprend un bail existant, puisque ces informations ne sont pas
@@ -1554,11 +1658,14 @@ changement d'état de bail à chaque changement de l'identifiant de client, de
longueur de bail ou de date d'expiration.
.TP
.B --bridge-interface=<interface>,<alias>[,<alias>]
Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias>
comme si elles arrivaient de l'interface <interface>. Cette option est
nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
pas d'adresse IP.
Traiter les requêtes DHCP (v4 et v6) et IPv6 Router Solicit arrivant
sur n'importe laquelle des interfaces <alias> comme si elles
arrivaient de l'interface <interface>. Cette option permet à dnsmasq
de fournir les service DHCP et RA sur les interfaces ethernet non
adressés et non pontés; par exemple sur un hôte de calcul d'OpenStack
où chaque telle interface est une interface TAP à une machine
virtuelle, ou lors de l'utilisation de pont ethernet "ancien mode" sur
plate-forme BSD. Chaque <alias> peut finir avec un simple '*' joker.
.TP
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
@@ -1649,11 +1756,30 @@ dnsmasq est spécifiée comme DNS récursif. Si elles sont fournies, les
options dns-server et domain-search sont utilisées respectivement pour RDNSS et
DNSSL.
.TP
.B --enable-tftp
.B --ra-param=<interface>,[high|low],[[<intervalle d'annonce routeur>],<durée de vie route>]
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é
pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou
"low" (basse). Par exemple :
.B --ra-param=eth0,high.
Un intervalle (en secondes) entre les annonces routeur peut-être fourni par :
.B --ra-param=eth0,60.
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 :
.B --ra-parm=eth0,0,0
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
Ces trois paramètres peuvent-être configurés en une fois :
.B --ra-param=low,60,1200
La valeur pour l'interface peut inclure un caractère joker.
.TP
.B --enable-tftp[=<interface>[,<interface>]]
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
un accès en lecture est possible; les extensions tsize et blksize sont supportées
(tsize est seulement supporté en mode octet).
(tsize est seulement supporté en mode octet). Sans argument optionel, le service
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
service TFTP sera activé.
.TP
.B --tftp-root=<répertoire>[,<interface>]
Les fichiers à fournir dans les transferts TFTP seront cherchés en prenant le
@@ -2066,7 +2192,7 @@ spécifiques, vous pouvez le faire via :
.fi
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
et ipv6.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
le nom) peuvent-simplement être configurées avec un enregistrement NS
adéquat. Par exemple, comme nous définissons plus haut les adresses

1396
po/de.po

File diff suppressed because it is too large Load Diff

1563
po/es.po

File diff suppressed because it is too large Load Diff

1527
po/fi.po

File diff suppressed because it is too large Load Diff

1263
po/fr.po

File diff suppressed because it is too large Load Diff

1293
po/id.po

File diff suppressed because it is too large Load Diff

1527
po/it.po

File diff suppressed because it is too large Load Diff

1248
po/no.po

File diff suppressed because it is too large Load Diff

1266
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1248
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -18,27 +18,26 @@
#ifdef HAVE_AUTH
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
struct subnet *subnet;
struct addrlist *subnet;
for (subnet = zone->subnet; subnet; subnet = subnet->next)
{
if (subnet->is6 && (flag & F_IPV4))
continue;
if (!subnet->is6)
if (!(subnet->flags & ADDRLIST_IPV6))
{
struct in_addr addr = addr_u->addr.addr4;
struct in_addr mask;
struct in_addr netmask, addr = addr_u->addr.addr4;
if (!(flag & F_IPV4))
continue;
mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
if (is_same_net(addr, subnet->addr4, mask))
if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
return subnet;
}
#ifdef HAVE_IPV6
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen))
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr.addr.addr6, subnet->prefixlen))
return subnet;
#endif
@@ -46,22 +45,16 @@ static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_a
return NULL;
}
static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_addr *addr_u)
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
#ifdef HAVE_DHCP6
struct dhcp_context *context;
if (flag & F_IPV6)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
return 1;
#endif
/* No zones specified, no filter */
if (!zone->subnet)
return 1;
return filter_zone(zone, flag, addr_u) != NULL;
return find_subnet(zone, flag, addr_u) != NULL;
}
static int in_zone(struct auth_zone *zone, char *name, char **cut)
int in_zone(struct auth_zone *zone, char *name, char **cut)
{
size_t namelen = strlen(name);
size_t domainlen = strlen(zone->domain);
@@ -88,7 +81,7 @@ static int in_zone(struct auth_zone *zone, char *name, char **cut)
}
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr)
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
@@ -96,9 +89,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0;
struct crec *crecp;
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
struct auth_zone *zone = NULL;
struct subnet *subnet = NULL;
struct addrlist *subnet = NULL;
char *cut;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
@@ -109,7 +102,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
/* determine end of question section (we put answers there) */
if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */
@@ -138,46 +131,75 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
continue;
}
if (qtype == T_PTR)
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
(flag = in_arpa_name_2_addr(name, &addr)) &&
!local_query)
{
if (!(flag = in_arpa_name_2_addr(name, &addr)))
continue;
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = filter_zone(zone, flag, &addr)))
if ((subnet = find_subnet(zone, flag, &addr)))
break;
if (!zone)
{
auth = 0;
continue;
}
if (flag == F_IPV4)
{
for (intr = daemon->int_names; intr; intr = intr->next)
{
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
else if (qtype == T_SOA)
soa = 1, found = 1;
else if (qtype == T_NS)
ns = 1, found = 1;
}
if (intr)
{
if (in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
anscount++;
}
if (qtype == T_PTR && flag)
{
intr = NULL;
if (flag == F_IPV4)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#ifdef HAVE_IPV6
else if (flag == F_IPV6)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#endif
if (intr)
{
if (local_query || in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
anscount++;
}
}
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
do {
strcpy(name, cache_get_name(crecp));
@@ -189,8 +211,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
*p = 0; /* must be bare name */
/* add external domain */
strcat(name, ".");
strcat(name, zone->domain);
if (zone)
{
strcat(name, ".");
strcat(name, zone->domain);
}
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
@@ -198,7 +223,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
T_PTR, C_IN, "d", name))
anscount++;
}
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
{
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
found = 1;
@@ -212,21 +237,29 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
if (!found)
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
if (found)
nxdomain = 0;
else
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
continue;
}
cname_restart:
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
if (found)
/* NS and SOA .arpa requests have set found above. */
cut = NULL;
else
{
auth = 0;
continue;
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
{
auth = 0;
continue;
}
}
for (rec = daemon->mxnames; rec; rec = rec->next)
@@ -321,21 +354,39 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
anscount++;
}
}
if (qtype == T_A)
flag = F_IPV4;
#ifdef HAVE_IPV6
if (qtype == T_AAAA)
flag = F_IPV6;
#endif
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
{
struct addrlist *addrlist;
nxdomain = 0;
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
{
found = 1;
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))
anscount++;
}
}
if (flag)
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
(local_query || filter_zone(zone, flag, &addrlist->addr)))
{
#ifdef HAVE_IPV6
if (addrlist->flags & ADDRLIST_REVONLY)
continue;
#endif
found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &addrlist->addr))
anscount++;
}
}
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(name, a->alias) )
@@ -349,28 +400,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
daemon->auth_ttl, &nameoffset,
T_CNAME, C_IN, "d", name))
anscount++;
goto cname_restart;
}
if (qtype == T_A)
flag = F_IPV4;
#ifdef HAVE_IPV6
if (qtype == T_AAAA)
flag = F_IPV6;
#endif
if (!cut)
{
nxdomain = 0;
if (qtype == T_SOA)
{
soa = 1; /* inhibits auth section */
auth = soa = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
}
@@ -382,7 +425,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
peer_addr->in.sin_port = 0;
#ifdef HAVE_IPV6
else
peer_addr->in6.sin6_port = 0;
{
peer_addr->in6.sin6_port = 0;
peer_addr->in6.sin6_scope_id = 0;
}
#endif
for (peers = daemon->auth_peers; peers; peers = peers->next)
@@ -403,6 +449,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
return 0;
}
auth = 1;
soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1;
@@ -412,6 +459,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
else if (qtype == T_NS)
{
auth = 1;
ns = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
@@ -429,7 +477,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
{
nxdomain = 0;
if ((crecp->flags & flag) &&
(filter_constructed_dhcp(zone, flag, &(crecp->addr.addr))))
(local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
{
*cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
@@ -452,7 +500,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
do
{
nxdomain = 0;
if ((crecp->flags & flag) && filter_constructed_dhcp(zone, flag, &(crecp->addr.addr)))
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr.addr))))
{
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
found = 1;
@@ -483,15 +531,15 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
authname = name;
if (!subnet->is6)
if (!(subnet->flags & ADDRLIST_IPV6))
{
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
char *p = name;
if (subnet->prefixlen == 24)
if (subnet->prefixlen >= 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen != 8)
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
@@ -505,7 +553,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
{
int dig = ((unsigned char *)&subnet->addr6)[i>>3];
int dig = ((unsigned char *)&subnet->addr.addr.addr6)[i>>3];
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
}
p += sprintf(p, "ip6.arpa");
@@ -634,20 +682,34 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
if (in_zone(zone, intr->name, &cut))
{
struct addrlist *addrlist;
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
anscount++;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (!(addrlist->flags & ADDRLIST_IPV6) &&
(local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
#ifdef HAVE_IPV6
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if ((addrlist->flags & ADDRLIST_IPV6) &&
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
#endif
/* restore config data */
if (cut)
*cut = '.';
}
for (a = daemon->cnames; a; a = a->next)
if (in_zone(zone, a->alias, &cut))
{
@@ -677,7 +739,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
{
char *cache_name = cache_get_name(crecp);
if (!strchr(cache_name, '.') && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
if (!strchr(cache_name, '.') &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
{
qtype = T_A;
#ifdef HAVE_IPV6
@@ -694,7 +757,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
{
strcpy(name, cache_get_name(crecp));
if (in_zone(zone, name, &cut) && filter_constructed_dhcp(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
if (in_zone(zone, name, &cut) &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
{
qtype = T_A;
#ifdef HAVE_IPV6
@@ -729,8 +793,17 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
/* done all questions, set up header and return length of result */
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
/* clear RA flag */
header->hb4 &= ~HB4_RA;
if (local_query)
{
/* set RA flag */
header->hb4 |= HB4_RA;
}
else
{
/* clear RA flag */
header->hb4 &= ~HB4_RA;
}
/* authoritive */
if (auth)
@@ -740,7 +813,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (trunc)
header->hb3 |= HB3_TC;
if (anscount == 0 && auth && nxdomain)
if ((auth || local_query) && nxdomain)
SET_RCODE(header, NXDOMAIN);
else
SET_RCODE(header, NOERROR); /* no error */

151
src/blockdata.c Normal file
View File

@@ -0,0 +1,151 @@
/* dnsmasq is Copyright (c) 2000-2015 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
static struct blockdata *keyblock_free;
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
static void blockdata_expand(int n)
{
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
if (n > 0 && new)
{
int i;
new[n-1].next = keyblock_free;
keyblock_free = new;
for (i = 0; i < n - 1; i++)
new[i].next = &new[i+1];
blockdata_alloced += n;
}
}
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
void blockdata_init(void)
{
keyblock_free = NULL;
blockdata_alloced = 0;
blockdata_count = 0;
blockdata_hwm = 0;
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
if (option_bool(OPT_DNSSEC_VALID))
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
}
void blockdata_report(void)
{
if (option_bool(OPT_DNSSEC_VALID))
my_syslog(LOG_INFO, _("DNSSEC memory in use %u, max %u, allocated %u"),
blockdata_count * sizeof(struct blockdata),
blockdata_hwm * sizeof(struct blockdata),
blockdata_alloced * sizeof(struct blockdata));
}
struct blockdata *blockdata_alloc(char *data, size_t len)
{
struct blockdata *block, *ret = NULL;
struct blockdata **prev = &ret;
size_t blen;
while (len > 0)
{
if (!keyblock_free)
blockdata_expand(50);
if (keyblock_free)
{
block = keyblock_free;
keyblock_free = block->next;
blockdata_count++;
}
else
{
/* failed to alloc, free partial chain */
blockdata_free(ret);
return NULL;
}
if (blockdata_hwm < blockdata_count)
blockdata_hwm = blockdata_count;
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
memcpy(block->key, data, blen);
data += blen;
len -= blen;
*prev = block;
prev = &block->next;
block->next = NULL;
}
return ret;
}
void blockdata_free(struct blockdata *blocks)
{
struct blockdata *tmp;
if (blocks)
{
for (tmp = blocks; tmp->next; tmp = tmp->next)
blockdata_count--;
tmp->next = keyblock_free;
keyblock_free = blocks;
blockdata_count--;
}
}
/* if data == NULL, return pointer to static block of sufficient size */
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
{
size_t blen;
struct blockdata *b;
void *new, *d;
static unsigned int buff_len = 0;
static unsigned char *buff = NULL;
if (!data)
{
if (len > buff_len)
{
if (!(new = whine_malloc(len)))
return NULL;
if (buff)
free(buff);
buff = new;
}
data = buff;
}
for (d = data, b = block; len > 0 && b; b = b->next)
{
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
memcpy(d, b->key, blen);
d += blen;
len -= blen;
}
return data;
}
#endif

179
src/bpf.c
View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,12 +19,19 @@
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
#include <ifaddrs.h>
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/if_ether.h>
#if defined(__FreeBSD__)
# include <net/if_var.h>
#endif
#include <netinet/in_var.h>
#ifdef HAVE_IPV6
# include <netinet6/in6_var.h>
#endif
#ifndef SA_SIZE
#define SA_SIZE(sa) \
@@ -33,6 +40,13 @@
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
#endif
#ifdef HAVE_BSD_NETWORK
static int del_family = 0;
static struct all_addr del_addr;
#endif
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
int arp_enumerate(void *parm, int (*callback)())
{
int mib[6];
@@ -83,13 +97,13 @@ int arp_enumerate(void *parm, int (*callback)())
return 1;
}
#endif
#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
int iface_enumerate(int family, void *parm, int (*callback)())
{
struct ifaddrs *head, *addrs;
int errsav, ret = 0;
int errsav, fd = -1, ret = 0;
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
@@ -105,19 +119,29 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (getifaddrs(&head) == -1)
return 0;
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
if (family == AF_INET6)
fd = socket(PF_INET6, SOCK_DGRAM, 0);
#endif
for (addrs = head; addrs; addrs = addrs->ifa_next)
{
if (addrs->ifa_addr->sa_family == family)
{
int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask)
if (iface_index == 0 || !addrs->ifa_addr ||
(!addrs->ifa_netmask && family != AF_LINK))
continue;
if (family == AF_INET)
{
struct in_addr addr, netmask, broadcast;
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
#ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET && del_addr.addr.addr4.s_addr == addr.s_addr)
continue;
#endif
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
if (addrs->ifa_broadaddr)
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
@@ -133,11 +157,50 @@ int iface_enumerate(int family, void *parm, int (*callback)())
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
int i, j, prefix = 0;
u32 valid = 0xffffffff, preferred = 0xffffffff;
int flags = 0;
#ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr.addr6, addr))
continue;
#endif
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
struct in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
{
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
flags |= IFACE_TENTATIVE;
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED;
#ifdef IN6_IFF_TEMPORARY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
flags |= IFACE_PERMANENT;
#endif
#ifdef IN6_IFF_PRIVACY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
flags |= IFACE_PERMANENT;
#endif
}
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
{
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
}
#endif
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
@@ -148,13 +211,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
/* preferred and valid times == forever until we known how to dtermine them. */
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm)))
goto err;
}
#endif
}
if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
(int) preferred, (int)valid, parm)))
goto err;
}
#endif /* HAVE_IPV6 */
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
@@ -172,12 +236,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
err:
errsav = errno;
freeifaddrs(head);
freeifaddrs(head);
if (fd != -1)
close(fd);
errno = errsav;
return ret;
}
#endif
#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
@@ -293,9 +359,90 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
iov[3].iov_base = mess;
iov[3].iov_len = len;
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
}
#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
#ifdef HAVE_BSD_NETWORK
void route_init(void)
{
/* AF_UNSPEC: all addr families */
daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
}
void route_sock(void)
{
struct if_msghdr *msg;
int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
if (rc < 4)
return;
msg = (struct if_msghdr *)daemon->packet;
if (rc < msg->ifm_msglen)
return;
if (msg->ifm_version != RTM_VERSION)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
warned = 1;
}
}
else if (msg->ifm_type == RTM_NEWADDR)
{
del_family = 0;
queue_event(EVENT_NEWADDR);
}
else if (msg->ifm_type == RTM_DELADDR)
{
/* There's a race in the kernel, such that if we run iface_enumerate() immediately
we get a DELADDR event, the deleted address still appears. Here we store the deleted address
in a static variable, and omit it from the set returned by iface_enumerate() */
int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
int of;
unsigned int i;
for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
if (mask & maskvec[i])
{
struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
if (maskvec[i] == RTA_IFA)
{
del_family = sa->sa_family;
if (del_family == AF_INET)
del_addr.addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
#ifdef HAVE_IPV6
else if (del_family == AF_INET6)
del_addr.addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
#endif
else
del_family = 0;
}
of += diff;
/* round up as needed */
if (diff & (sizeof(long) - 1))
of += sizeof(long) - (diff & (sizeof(long) - 1));
}
queue_event(EVENT_NEWADDR);
}
}
#endif /* HAVE_BSD_NETWORK */

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -17,20 +17,25 @@
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define KEYBLOCK_LEN 140 /* choose to mininise fragmentation when storing DNSSEC keys */
#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 20 /* or 20 seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
#define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
#define SMALLDNAME 40 /* most domain names are smaller than this */
#define SMALLDNAME 50 /* most domain names are smaller than this */
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
#define HOSTSFILE "/etc/hosts"
#define ETHERSFILE "/etc/ethers"
#define DEFLEASE 3600 /* default lease time, 1 hour */
@@ -39,14 +44,14 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
#define AUTH_TTL 600 /* default TTL for auth DNS */
#define SOA_REFRESH 1200 /* SOA refresh default */
#define SOA_RETRY 180 /* SOA retry default */
#define SOA_EXPIRY 1209600 /* SOA expiry default */
#define RA_INTERVAL 600 /* Send unsolicited RA's this often when not provoked. */
#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
#define LOOP_TEST_TYPE T_TXT
/* compile-time options: uncomment below to enable or do eg.
make COPTS=-DHAVE_BROKEN_RTC
@@ -105,6 +110,14 @@ HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
HAVE_DNSSEC
include DNSSEC validator.
HAVE_LOOP
include functionality to probe for and remove DNS forwarding loops.
HAVE_INOTIFY
use the Linux inotify facility to efficiently re-read configuration files.
NO_IPV6
NO_TFTP
@@ -113,11 +126,17 @@ NO_DHCP6
NO_SCRIPT
NO_LARGEFILE
NO_AUTH
NO_INOTIFY
these are avilable to explictly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
NO_NETTLE_ECC
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
NO_GMP
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
LEASEFILE
CONFFILE
RESOLVFILE
@@ -126,6 +145,11 @@ RESOLVFILE
*/
/* Defining this builds a binary which handles time differently and works better on a system without a
stable RTC (it uses uptime, not epoch time) and writes the DHCP leases file less often to avoid flash wear.
*/
/* #define HAVE_BROKEN_RTC */
/* The default set of options to build. Built with these options, dnsmasq
has no library dependencies other than libc */
@@ -136,11 +160,20 @@ RESOLVFILE
#define HAVE_SCRIPT
#define HAVE_AUTH
#define HAVE_IPSET
#define HAVE_LOOP
/* Build options which require external libraries.
Defining HAVE_<opt>_STATIC as _well_ as HAVE_<opt> will link the library statically.
You can use "make COPTS=-DHAVE_<opt>" instead of editing these.
*/
/* #define HAVE_LUASCRIPT */
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_CONNTRACK */
/* #define HAVE_DNSSEC */
/* Default locations for important system files. */
@@ -191,10 +224,6 @@ HAVE_SOLARIS_NETWORK
HAVE_GETOPT_LONG
defined when GNU-style getopt_long available.
HAVE_ARC4RANDOM
defined if arc4random() available to get better security from DNS spoofs
by using really random ids (OpenBSD)
HAVE_SOCKADDR_SA_LEN
defined if struct sockaddr has sa_len field (*BSD)
*/
@@ -203,7 +232,6 @@ HAVE_SOCKADDR_SA_LEN
#if defined(__uClinux__)
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
@@ -217,7 +245,6 @@ HAVE_SOCKADDR_SA_LEN
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
# define HAVE_GETOPT_LONG
#endif
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
# define NO_FORK
@@ -232,7 +259,6 @@ HAVE_SOCKADDR_SA_LEN
#elif defined(__linux__)
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#elif defined(__FreeBSD__) || \
@@ -244,29 +270,27 @@ HAVE_SOCKADDR_SA_LEN
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#endif
#if !defined(__FreeBSD_kernel__)
# define HAVE_ARC4RANDOM
#endif
#define HAVE_SOCKADDR_SA_LEN
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* Select the RFC_3542 version of the IPv6 socket API.
Define before netinet6/in6.h is included. */
#define __APPLE_USE_RFC_3542
#define NO_IPSET
#elif defined(__NetBSD__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define ETHER_ADDR_LEN 6
@@ -327,10 +351,18 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_AUTH
#endif
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
#if defined(NO_IPSET)
#undef HAVE_IPSET
#endif
#ifdef NO_LOOP
#undef HAVE_LOOP
#endif
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
#define HAVE_INOTIFY
#endif
/* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
@@ -396,7 +428,20 @@ static char *compile_opts =
#ifndef HAVE_AUTH
"no-"
#endif
"auth";
"auth "
#ifndef HAVE_DNSSEC
"no-"
#endif
"DNSSEC "
#ifndef HAVE_LOOP
"no-"
#endif
"loop-detect "
#ifndef HAVE_INOTIFY
"no-"
#endif
"inotify";
#endif

View File

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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -35,6 +35,11 @@ const char* introspection_xml_template =
" <method name=\"GetVersion\">\n"
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
#ifdef HAVE_LOOP
" <method name=\"GetLoopServers\">\n"
" <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
" </method>\n"
#endif
" <method name=\"SetServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
" </method>\n"
@@ -44,6 +49,12 @@ const char* introspection_xml_template =
" <method name=\"SetServersEx\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
" </method>\n"
" <method name=\"SetFilterWin2KOption\">\n"
" <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"SetBogusPrivOption\">\n"
" <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
" <signal name=\"DhcpLeaseAdded\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
@@ -59,6 +70,21 @@ const char* introspection_xml_template =
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
#ifdef HAVE_DHCP
" <method name=\"AddDhcpLease\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"ay\"/>\n"
" <arg name=\"clid\" type=\"ay\"/>\n"
" <arg name=\"lease_duration\" type=\"u\"/>\n"
" <arg name=\"ia_id\" type=\"u\"/>\n"
" <arg name=\"is_temporary\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"DeleteDhcpLease\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
" </method>\n"
#endif
" </interface>\n"
"</node>\n";
@@ -108,108 +134,6 @@ static void remove_watch(DBusWatch *watch, void *data)
w = data; /* no warning */
}
static void add_update_server(union mysockaddr *addr,
union mysockaddr *source_addr,
const char *interface,
const char *domain)
{
struct server *serv;
/* See if there is a suitable candidate, and unmark */
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_FROM_DBUS) &&
(serv->flags & SERV_MARK))
{
if (domain)
{
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
continue;
}
else
{
if (serv->flags & SERV_HAS_DOMAIN)
continue;
}
serv->flags &= ~SERV_MARK;
break;
}
if (!serv && (serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
memset(serv, 0, sizeof(struct server));
if (domain && !(serv->domain = whine_malloc(strlen(domain)+1)))
{
free(serv);
serv = NULL;
}
else
{
serv->next = daemon->servers;
daemon->servers = serv;
serv->flags = SERV_FROM_DBUS;
if (domain)
{
strcpy(serv->domain, domain);
serv->flags |= SERV_HAS_DOMAIN;
}
}
}
if (serv)
{
if (interface)
strcpy(serv->interface, interface);
else
serv->interface[0] = 0;
if (source_addr->in.sin_family == AF_INET &&
addr->in.sin_addr.s_addr == 0 &&
serv->domain)
serv->flags |= SERV_NO_ADDR;
else
{
serv->flags &= ~SERV_NO_ADDR;
serv->addr = *addr;
serv->source_addr = *source_addr;
}
}
}
static void mark_dbus(void)
{
struct server *serv;
/* mark everything from DBUS */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_FROM_DBUS)
serv->flags |= SERV_MARK;
}
static void cleanup_dbus()
{
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
server_gone(serv);
*up = serv->next;
if (serv->domain)
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
static void dbus_read_servers(DBusMessage *message)
{
DBusMessageIter iter;
@@ -218,8 +142,8 @@ static void dbus_read_servers(DBusMessage *message)
dbus_message_iter_init(message, &iter);
mark_dbus();
mark_servers(SERV_FROM_DBUS);
while (1)
{
int skip = 0;
@@ -252,13 +176,16 @@ static void dbus_read_servers(DBusMessage *message)
dbus_message_iter_get_basic(&iter, &p[i]);
dbus_message_iter_next (&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
break;
{
i++;
break;
}
}
#ifndef HAVE_IPV6
my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
#else
if (i == sizeof(struct in6_addr)-1)
if (i == sizeof(struct in6_addr))
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -289,15 +216,38 @@ static void dbus_read_servers(DBusMessage *message)
domain = NULL;
if (!skip)
add_update_server(&addr, &source_addr, NULL, domain);
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
}
/* unlink and free anything still marked. */
cleanup_dbus();
cleanup_servers();
}
#ifdef HAVE_LOOP
static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
{
DBusMessageIter args, args_iter;
struct server *serv;
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_iter_init_append (reply, &args);
dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_LOOP)
{
prettyprint_addr(&serv->addr, daemon->addrbuff);
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
}
dbus_message_iter_close_container (&args, &args_iter);
return reply;
}
#endif
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
{
DBusMessageIter iter, array_iter, string_iter;
@@ -305,8 +255,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
const char *addr_err;
char *dup = NULL;
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
if (!dbus_message_iter_init(message, &iter))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
@@ -321,7 +269,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
strings ? "Expected array of string" : "Expected array of string arrays");
}
mark_dbus();
mark_servers(SERV_FROM_DBUS);
/* array_iter points to each "as" element in the outer array */
dbus_message_iter_recurse(&iter, &array_iter);
@@ -329,6 +277,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
{
const char *str = NULL;
union mysockaddr addr, source_addr;
int flags = 0;
char interface[IF_NAMESIZE];
char *str_addr, *str_domain = NULL;
@@ -418,16 +367,19 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
memset(&interface, 0, sizeof(interface));
/* parse the IP address */
addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, NULL);
if (addr_err)
{
if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
/* 0.0.0.0 for server address == NULL, for Dbus */
if (addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0)
flags |= SERV_NO_ADDR;
if (strings)
{
char *p;
@@ -441,7 +393,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
else
p = NULL;
add_update_server(&addr, &source_addr, interface, str_domain);
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
} while ((str_domain = p));
}
else
@@ -456,7 +408,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
dbus_message_iter_get_basic(&string_iter, &str);
dbus_message_iter_next (&string_iter);
add_update_server(&addr, &source_addr, interface, str);
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
}
@@ -464,7 +416,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
dbus_message_iter_next(&array_iter);
}
cleanup_dbus();
cleanup_servers();
if (dup)
free(dup);
@@ -472,12 +424,203 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
return error;
}
static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
{
DBusMessageIter iter;
dbus_bool_t enabled;
if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
dbus_message_iter_get_basic(&iter, &enabled);
if (enabled)
{
my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
set_option_bool(flag);
}
else
{
my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
reset_option_bool(flag);
}
return NULL;
}
#ifdef HAVE_DHCP
static DBusMessage *dbus_add_lease(DBusMessage* message)
{
struct dhcp_lease *lease;
const char *ipaddr, *hwaddr, *hostname, *tmp;
const unsigned char* clid;
int clid_len, hostname_len, hw_len, hw_type;
dbus_uint32_t expires, ia_id;
dbus_bool_t is_temporary;
struct all_addr addr;
time_t now = dnsmasq_time();
unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
DBusMessageIter iter, array_iter;
if (!dbus_message_iter_init(message, &iter))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as first argument");
dbus_message_iter_get_basic(&iter, &ipaddr);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as second argument");
dbus_message_iter_get_basic(&iter, &hwaddr);
dbus_message_iter_next(&iter);
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected byte array as third argument");
dbus_message_iter_recurse(&iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
tmp = memchr(hostname, '\0', hostname_len);
if (tmp)
{
if (tmp == &hostname[hostname_len - 1])
hostname_len--;
else
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Hostname contains an embedded NUL character");
}
dbus_message_iter_next(&iter);
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected byte array as fourth argument");
dbus_message_iter_recurse(&iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as fifth argument");
dbus_message_iter_get_basic(&iter, &expires);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as sixth argument");
dbus_message_iter_get_basic(&iter, &ia_id);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as sixth argument");
dbus_message_iter_get_basic(&iter, &is_temporary);
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
{
if (ia_id != 0 || is_temporary)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"ia_id and is_temporary must be zero for IPv4 lease");
if (!(lease = lease_find_by_addr(addr.addr.addr4)))
lease = lease4_allocate(addr.addr.addr4);
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
{
if (!(lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0)))
lease = lease6_allocate(&addr.addr.addr6,
is_temporary ? LEASE_TA : LEASE_NA);
lease_set_iaid(lease, ia_id);
}
#endif
else
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s'", ipaddr);
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL,
&hw_type);
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
clid_len, now, 0);
lease_set_expires(lease, expires, now);
if (hostname_len != 0)
lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
lease_update_file(now);
lease_update_dns(0);
return NULL;
}
static DBusMessage *dbus_del_lease(DBusMessage* message)
{
struct dhcp_lease *lease;
DBusMessageIter iter;
const char *ipaddr;
DBusMessage *reply;
struct all_addr addr;
dbus_bool_t ret = 1;
time_t now = dnsmasq_time();
if (!dbus_message_iter_init(message, &iter))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as first argument");
dbus_message_iter_get_basic(&iter, &ipaddr);
if (inet_pton(AF_INET, ipaddr, &addr.addr.addr4))
lease = lease_find_by_addr(addr.addr.addr4);
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, ipaddr, &addr.addr.addr6))
lease = lease6_find_by_addr(&addr.addr.addr6, 128, 0);
#endif
else
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s'", ipaddr);
if (lease)
{
lease_prune(lease, now);
lease_update_file(now);
lease_update_dns(0);
}
else
ret = 0;
if ((reply = dbus_message_new_method_return(message)))
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
DBUS_TYPE_INVALID);
return reply;
}
#endif
DBusHandlerResult message_handler(DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
char *method = (char *)dbus_message_get_member(message);
DBusMessage *reply = NULL;
int clear_cache = 0, new_servers = 0;
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
@@ -499,26 +642,60 @@ DBusHandlerResult message_handler(DBusConnection *connection,
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
}
#ifdef HAVE_LOOP
else if (strcmp(method, "GetLoopServers") == 0)
{
reply = dbus_reply_server_loop(message);
}
#endif
else if (strcmp(method, "SetServers") == 0)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
dbus_read_servers(message);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "SetServersEx") == 0)
{
reply = dbus_read_servers_ex(message, 0);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "SetDomainServers") == 0)
{
reply = dbus_read_servers_ex(message, 1);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "SetFilterWin2KOption") == 0)
{
reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
}
else if (strcmp(method, "SetBogusPrivOption") == 0)
{
reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
}
#ifdef HAVE_DHCP
else if (strcmp(method, "AddDhcpLease") == 0)
{
reply = dbus_add_lease(message);
}
else if (strcmp(method, "DeleteDhcpLease") == 0)
{
reply = dbus_del_lease(message);
}
#endif
else if (strcmp(method, "ClearCache") == 0)
clear_cache_and_reload(dnsmasq_time());
clear_cache = 1;
else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
if (new_servers)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
check_servers();
if (option_bool(OPT_RELOAD))
clear_cache = 1;
}
if (clear_cache)
clear_cache_and_reload(dnsmasq_time());
method = user_data; /* no warning */
@@ -572,8 +749,7 @@ char *dbus_init(void)
}
void set_dbus_listeners(int *maxfdp,
fd_set *rset, fd_set *wset, fd_set *eset)
void set_dbus_listeners(void)
{
struct watch *w;
@@ -583,19 +759,17 @@ void set_dbus_listeners(int *maxfdp,
unsigned int flags = dbus_watch_get_flags(w->watch);
int fd = dbus_watch_get_unix_fd(w->watch);
bump_maxfd(fd, maxfdp);
if (flags & DBUS_WATCH_READABLE)
FD_SET(fd, rset);
poll_listen(fd, POLLIN);
if (flags & DBUS_WATCH_WRITABLE)
FD_SET(fd, wset);
poll_listen(fd, POLLOUT);
FD_SET(fd, eset);
poll_listen(fd, POLLERR);
}
}
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
void check_dbus_listeners()
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
struct watch *w;
@@ -606,13 +780,13 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
unsigned int flags = 0;
int fd = dbus_watch_get_unix_fd(w->watch);
if (FD_ISSET(fd, rset))
if (poll_check(fd, POLLIN))
flags |= DBUS_WATCH_READABLE;
if (FD_ISSET(fd, wset))
if (poll_check(fd, POLLOUT))
flags |= DBUS_WATCH_WRITABLE;
if (FD_ISSET(fd, eset))
if (poll_check(fd, POLLERR))
flags |= DBUS_WATCH_ERROR;
if (flags != 0)
@@ -647,7 +821,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
if (lease->flags & (LEASE_TA | LEASE_NA))
{
print_mac(mac, lease->clid, lease->clid_len);
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
}
else
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -253,6 +253,110 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
return 1;
#ifdef HAVE_DHCP6
if ((context->flags & CONTEXT_V6) && (config->flags & CONFIG_WILDCARD))
return 1;
#endif
for (; context; context = context->current)
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_V6)
{
if ((config->flags & CONFIG_ADDR6) && is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
}
else
#endif
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_config_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here. This is IPv4 only. context==NULL implies IPv4,
see lease_update_from_configs() */
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_config_in_context(context, config))
return config;
}
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_config_in_context(context, config))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context(context, config))
return config;
if (!hwaddr)
return NULL;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_config_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
@@ -295,13 +399,13 @@ void dhcp_update_configs(struct dhcp_config *configs)
if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
{
/* use primary (first) address */
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
if (!crec)
continue; /* should be never */
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, daemon->addrbuff);
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
if (!crec)
continue; /* should be never */
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, daemon->addrbuff);
}
if (prot == AF_INET &&
@@ -341,38 +445,53 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_LINUX_NETWORK
void bindtodevice(int fd)
char *whichdevice(void)
{
/* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
to that device. This is for the use case of (eg) OpenStack, which runs a new
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
individual processes don't always see the packets they should.
SO_BINDTODEVICE is only available Linux. */
SO_BINDTODEVICE is only available Linux.
Note that if wildcards are used in --interface, or --interface is not used at all,
or a configured interface doesn't yet exist, then more interfaces may arrive later,
so we can't safely assert there is only one interface and proceed.
*/
struct irec *iface, *found;
struct iname *if_tmp;
if (!daemon->if_names)
return NULL;
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
return NULL;
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok)
{
if (!found)
found = iface;
else if (strcmp(found->name, iface->name) != 0)
{
/* more than one. */
found = NULL;
break;
}
return NULL; /* more than one. */
}
if (found)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, found->name);
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
}
return found->name;
return NULL;
}
void bindtodevice(char *device, int fd)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, device);
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
}
#endif
@@ -426,8 +545,8 @@ static const struct opttab_t {
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_INTERNAL | OT_TIME},
{ "T2", 59, OT_INTERNAL | OT_TIME},
{ "T1", 58, OT_TIME},
{ "T2", 59, OT_TIME},
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
@@ -517,6 +636,8 @@ int lookup_dhcp_opt(int prot, char *name)
const struct opttab_t *t;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -536,6 +657,8 @@ int lookup_dhcp_len(int prot, int val)
const struct opttab_t *t;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -713,43 +836,70 @@ void log_context(int family, struct dhcp_context *context)
template = p;
p += sprintf(p, ", ");
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "constructed for %s", ifrn_name);
if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
}
else if (context->flags & CONTEXT_TEMPLATE)
else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
{
template = p;
p += sprintf(p, ", ");
sprintf(p, "template for %s", context->template_interface);
}
#endif
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET))
{
inet_ntop(family, start, daemon->dhcp_buff, 256);
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_STATELESS)
{
if (context->flags & CONTEXT_TEMPLATE)
strncpy(daemon->dhcp_buff, context->template_interface, 256);
else
strcpy(daemon->dhcp_buff, daemon->addrbuff);
}
else
#endif
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_NAME)
if (context->flags & CONTEXT_TEMPLATE)
{
strcpy(daemon->addrbuff, context->template_interface);
template = "";
}
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
#endif
}
void log_relay(int family, struct dhcp_relay *relay)
{
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
if (relay->interface)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
}
#endif

View File

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

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,6 +20,8 @@
struct iface_param {
struct dhcp_context *current;
struct dhcp_relay *relay;
struct in_addr relay_local;
int ind;
};
@@ -32,6 +34,8 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
static int make_fd(int port)
{
@@ -70,15 +74,15 @@ static int make_fd(int port)
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = -1, porterr = 0;
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno != ENOPROTOOPT)
porterr = 1;
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc == -1 && !porterr)
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
struct dhcp_packet *mess;
struct dhcp_context *context;
struct dhcp_relay *relay;
int is_relay_reply = 0;
struct iname *tmp;
struct ifreq ifr;
struct msghdr msg;
@@ -219,18 +225,21 @@ void dhcp_packet(time_t now, int pxe_fd)
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
#endif
/* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address.
We allow these to be treated as aliases of another interface which does have
an IP address with --dhcp-bridge=interface,alias,alias */
/* If the interface on which the DHCP request was received is an
alias of some other interface (as specified by the
--bridge-interface option), change ifr.ifr_name so that we look
for DHCP contexts associated with the aliased interface instead
of with the aliasing one. */
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
{
if (!(iface_index = if_nametoindex(bridge->iface)))
{
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
my_syslog(MS_DHCP | LOG_WARNING,
_("unknown interface %s in bridge-interface"),
bridge->iface);
return;
}
else
@@ -250,57 +259,86 @@ void dhcp_packet(time_t now, int pxe_fd)
unicast_dest = 1;
#endif
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
{
/* Reply from server, using us as relay. */
iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
is_relay_reply = 1;
iov.iov_len = sz;
#ifdef HAVE_LINUX_NETWORK
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
#endif
}
else
{
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
parm.current = NULL;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
else
{
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
match.matched = 0;
match.ind = iface_index;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
/* unlinked contexts/relays are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
for (relay = daemon->relay4; relay; relay = relay->next)
relay->current = relay;
parm.current = NULL;
parm.relay = NULL;
parm.relay_local.s_addr = 0;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
match.matched = 0;
match.ind = iface_index;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
return;
/* May have configured relay, but not DHCP server */
if (!daemon->dhcp)
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now);
lease_update_dns(0);
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now);
lease_update_dns(0);
if (iov.iov_len == 0)
return;
if (iov.iov_len == 0)
return;
}
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
@@ -321,7 +359,7 @@ void dhcp_packet(time_t now, int pxe_fd)
if (mess->ciaddr.s_addr != 0)
dest.sin_addr = mess->ciaddr;
}
else if (mess->giaddr.s_addr)
else if (mess->giaddr.s_addr && !is_relay_reply)
{
/* Send to BOOTP relay */
dest.sin_port = htons(daemon->dhcp_server_port);
@@ -334,17 +372,16 @@ void dhcp_packet(time_t now, int pxe_fd)
source port too, and send back to that. If we're replying
to a DHCPINFORM, trust the source address always. */
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
{
dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->ciaddr;
}
}
#if defined(HAVE_LINUX_NETWORK)
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
else
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
/* fill cmsg for outbound interface (both broadcast & unicast) */
struct in_pktinfo *pkt;
msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u);
@@ -354,22 +391,29 @@ void dhcp_packet(time_t now, int pxe_fd)
pkt->ipi_spec_dst.s_addr = 0;
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_PKTINFO;
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
struct sockaddr limits size to 14 bytes. */
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
arp_req.arp_ha.sa_family = mess->htype;
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
/* interface name already copied in */
arp_req.arp_flags = ATF_COM;
ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
cmptr->cmsg_type = IP_PKTINFO;
if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
struct sockaddr limits size to 14 bytes. */
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
arp_req.arp_ha.sa_family = mess->htype;
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
/* interface name already copied in */
arp_req.arp_flags = ATF_COM;
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
}
}
#elif defined(HAVE_SOLARIS_NETWORK)
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
@@ -407,7 +451,7 @@ void dhcp_packet(time_t now, int pxe_fd)
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
#endif
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
while(retry_send(sendmsg(fd, &msg, 0)));
}
/* check against secondary interface addresses */
@@ -450,6 +494,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
(void)label;
@@ -495,6 +540,15 @@ static int complete_context(struct in_addr local, int if_index, char *label,
}
}
for (relay = daemon->relay4; relay; relay = relay->next)
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = local;
}
return 1;
}
@@ -704,89 +758,6 @@ int address_allocate(struct dhcp_context *context,
return 0;
}
static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current)
if (is_same_net(config->addr, context->start, context->netmask))
return 1;
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_addr_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (*clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_addr_in_context(context, config))
return config;
}
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context(context, config))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_read_ethers(void)
{
FILE *f = fopen(ETHERSFILE, "r");
@@ -988,5 +959,74 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
#endif
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
{
/* ->local is same value for all relays on ->current chain */
struct all_addr from;
if (mess->op != BOOTREQUEST)
return 0;
/* source address == relay address */
from.addr.addr4 = relay->local.addr.addr4;
/* already gatewayed ? */
if (mess->giaddr.s_addr)
{
/* if so check if by us, to stomp on loops. */
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
return 1;
}
else
{
/* plug in our address */
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
}
if ((mess->hops++) > 20)
return 1;
for (; relay; relay = relay->current)
{
union mysockaddr to;
to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr.addr4;
to.in.sin_port = htons(daemon->dhcp_server_port);
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
}
/* Save this for replies */
relay->iface_index = iface_index;
}
return 1;
}
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
{
struct dhcp_relay *relay;
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
return NULL;
for (relay = daemon->relay4; relay; relay = relay->next)
{
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
{
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
return relay->iface_index != 0 ? relay : NULL;
}
}
return NULL;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,9 +55,11 @@
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_DOMAIN_SEARCH 24
#define OPTION6_REFRESH_TIME 32
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define OPTION6_CLIENT_MAC 79
/* replace this with the real number when allocated.
defining this also enables the relevant code. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -18,16 +18,26 @@
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct iface_param {
struct dhcp_context *current;
struct in6_addr fallback;
struct dhcp_relay *relay;
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
int ind, addr_match;
};
struct mac_param {
struct in6_addr *target;
unsigned char *mac;
unsigned int maclen;
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void)
@@ -55,15 +65,15 @@ void dhcp6_init(void)
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = -1, porterr = 0;
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno != ENOPROTOOPT)
porterr = 1;
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc == -1 && !porterr)
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
@@ -87,6 +97,7 @@ void dhcp6_init(void)
void dhcp6_packet(time_t now)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param parm;
struct cmsghdr *cmptr;
struct msghdr msg;
@@ -100,6 +111,9 @@ void dhcp6_packet(time_t now)
struct ifreq ifr;
struct iname *tmp;
unsigned short port;
struct in6_addr dst_addr;
memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
@@ -122,60 +136,114 @@ void dhcp6_packet(time_t now)
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
dst_addr = p.p->ipi6_addr;
}
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
parm.current = NULL;
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
struct dhcp_bridge *bridge, *alias;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break;
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
parm.current = NULL;
parm.relay = NULL;
memset(&parm.relay_local, 0, IN6ADDRSZ);
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
memset(&parm.ll_addr, 0, IN6ADDRSZ);
memset(&parm.ula_addr, 0, IN6ADDRSZ);
if (!tmp && !parm.addr_match)
/* If the interface on which the DHCPv6 request was received is
an alias of some other interface (as specified by the
--bridge-interface option), change parm.ind so that we look
for DHCPv6 contexts associated with the aliased interface
instead of with the aliasing one. */
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
{
parm.ind = if_nametoindex(bridge->iface);
if (!parm.ind)
{
my_syslog(MS_DHCP | LOG_WARNING,
_("unknown interface %s in bridge-interface"),
bridge->iface);
return;
}
break;
}
if (alias)
break;
}
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
for (relay = daemon->relay6; relay; relay = relay->next)
relay->current = relay;
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break;
if (!tmp && !parm.addr_match)
return;
}
if (parm.relay)
{
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
we're listening there for DHCPv6 server reasons. */
struct in6_addr all_servers;
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
return;
}
/* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6)
return;
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
lease_update_file(now);
lease_update_dns(0);
}
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now);
lease_update_dns(0);
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
@@ -183,81 +251,169 @@ void dhcp6_packet(time_t now)
if (port != 0)
{
from.sin6_port = htons(port);
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
retry_send());
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(0), 0, (struct sockaddr *)&from,
sizeof(from))));
}
}
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
{
/* Recieving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh;
struct sockaddr_in6 addr;
struct mac_param mac_param;
int i;
neigh.type = ND_NEIGHBOR_SOLICIT;
neigh.code = 0;
neigh.reserved = 0;
neigh.target = *client;
/* RFC4443 section-2.3: checksum has to be zero to be calculated */
neigh.checksum = 0;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = *client;
addr.sin6_scope_id = iface;
mac_param.target = client;
mac_param.maclen = 0;
mac_param.mac = mac;
for (i = 0; i < 5; i++)
{
struct timespec ts;
iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
if (mac_param.maclen != 0)
break;
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
*maclenp = mac_param.maclen;
*mactypep = ARPHRD_ETHER;
}
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
struct mac_param *parm = parmv;
if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
{
if (maclen <= DHCP_CHADDR_MAX)
{
parm->maclen = maclen;
memcpy(parm->mac, mac, maclen);
}
return 0; /* found, abort */
}
return 1;
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
if (if_index == param->ind)
{
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_LINKLOCAL(local))
param->ll_addr = *local;
else if (IN6_IS_ADDR_ULA(local))
param->ula_addr = *local;
if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
}
return 1;
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
@@ -273,7 +429,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return NULL;
}
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
@@ -290,9 +446,13 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
u64 j;
/* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */
for (j = iaid, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
for MAC addresses, let's see how it manages with client-ids!
For temporary addresses, we generate a new random one each time. */
if (temp_addr)
j = rand64();
else
for (j = iaid, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current)
@@ -302,7 +462,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
continue;
else
{
if (option_bool(OPT_CONSEC_ADDR))
if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
@@ -400,50 +560,10 @@ int config_valid(struct dhcp_config *config, struct dhcp_context *context, struc
return 0;
}
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{
if (!(config->flags & CONFIG_ADDR6) ||
(config->flags & CONFIG_WILDCARD))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0;
}
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname)
{
struct dhcp_config *config;
if (duid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == duid_len &&
memcmp(config->clid, duid, duid_len) == 0 &&
is_config_in_context6(context, config))
return config;
}
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context6(context, config))
return config;
return NULL;
}
void make_duid(time_t now)
{
(void)now;
if (daemon->duid_config)
{
unsigned char *p;
@@ -456,8 +576,14 @@ void make_duid(time_t now)
}
else
{
time_t newnow = 0;
/* If we have no persistent lease database, or a non-stable RTC, use DUID_LL (newnow == 0) */
#ifndef HAVE_BROKEN_RTC
/* rebase epoch to 1/1/2000 */
time_t newnow = now - 946684800;
if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
newnow = now - 946684800;
#endif
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
@@ -475,23 +601,28 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
unsigned char *p;
(void)index;
(void)parm;
time_t newnow = *((time_t *)parm);
if (type >= 256)
return 1;
#ifdef HAVE_BROKEN_RTC
daemon->duid = p = safe_malloc(maclen + 4);
daemon->duid_len = maclen + 4;
PUTSHORT(3, p); /* DUID_LL */
PUTSHORT(type, p); /* address type */
#else
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
PUTSHORT(1, p); /* DUID_LLT */
PUTSHORT(type, p); /* address type */
PUTLONG(*((time_t *)parm), p); /* time */
#endif
if (newnow == 0)
{
daemon->duid = p = safe_malloc(maclen + 4);
daemon->duid_len = maclen + 4;
PUTSHORT(3, p); /* DUID_LL */
PUTSHORT(type, p); /* address type */
}
else
{
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
PUTSHORT(1, p); /* DUID_LLT */
PUTSHORT(type, p); /* address type */
PUTLONG(*((time_t *)parm), p); /* time */
}
memcpy(p, mac, maclen);
return 0;
@@ -522,23 +653,30 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_IS_ADDR_MULTICAST(local))
return 1;
if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
if (!(flags & IFACE_PERMANENT))
return 1;
if (flags & IFACE_DEPRECATED)
return 1;
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name))
return 0;
for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & CONTEXT_TEMPLATE))
{
/* non-template entries, just fill in interface and local addresses */
if (prefix == template->prefix &&
is_same_net6(local, &template->start6, prefix) &&
is_same_net6(local, &template->end6, prefix))
if (prefix <= template->prefix &&
is_same_net6(local, &template->start6, template->prefix) &&
is_same_net6(local, &template->end6, template->prefix))
{
template->if_index = if_index;
template->local6 = *local;
}
}
else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
else if (wildcard_match(template->template_interface, ifrn_name) &&
template->prefix >= prefix)
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
@@ -550,7 +688,19 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
context->flags &= ~CONTEXT_GC;
int flags = context->flags;
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
if (flags & CONTEXT_OLD)
{
/* address went, now it's back */
log_context(AF_INET6, context);
/* fast RAs for a while */
ra_start_unsolicted(param->now, context);
param->newone = 1;
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
}
break;
}
@@ -563,6 +713,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->saved_valid = 0;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
@@ -585,35 +736,55 @@ static int construct_worker(struct in6_addr *local, int prefix,
void dhcp_construct_contexts(time_t now)
{
struct dhcp_context *tmp, *context, **up;
struct dhcp_context *context, *tmp, **up;
struct cparam param;
param.newone = 0;
param.newname = 0;
param.now = now;
for (context = daemon->dhcp6; context; context = context->next)
{
context->if_index = 0;
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
}
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->flags & CONTEXT_GC)
tmp = context->next;
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
{
*up = context->next;
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
free(context);
if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
{
/* previously constructed context has gone. advertise it's demise */
context->flags |= CONTEXT_OLD;
context->address_lost_time = now;
/* Apply same ceiling of configured lease time as in radv.c */
if (context->saved_valid > context->lease_time)
context->saved_valid = context->lease_time;
/* maximum time is 2 hours, from RFC */
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
ra_start_unsolicted(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
log_context(AF_INET6, context);
up = &context->next;
}
else
{
/* we were never doing RA for this, so free now */
*up = context->next;
free(context);
}
}
else
up = &context->next;
up = &context->next;
}
if (param.newone)

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,44 +36,68 @@
#define C_IN 1 /* the arpa internet */
#define C_CHAOS 3 /* for chaos net (MIT) */
#define C_HESIOD 4 /* hesiod */
#define C_ANY 255 /* wildcard match */
#define T_A 1
#define T_NS 2
#define T_NS 2
#define T_MD 3
#define T_MF 4
#define T_CNAME 5
#define T_SOA 6
#define T_MB 7
#define T_MG 8
#define T_MR 9
#define T_PTR 12
#define T_MINFO 14
#define T_MX 15
#define T_TXT 16
#define T_RP 17
#define T_AFSDB 18
#define T_RT 21
#define T_SIG 24
#define T_PX 26
#define T_AAAA 28
#define T_NXT 30
#define T_SRV 33
#define T_NAPTR 35
#define T_KX 36
#define T_DNAME 39
#define T_OPT 41
#define T_DS 43
#define T_RRSIG 46
#define T_NSEC 47
#define T_DNSKEY 48
#define T_NSEC3 50
#define T_TKEY 249
#define T_TSIG 250
#define T_AXFR 252
#define T_MAILB 253
#define T_ANY 255
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
struct dns_header {
u16 id;
u8 hb3,hb4;
u16 qdcount,ancount,nscount,arcount;
};
#define HB3_QR 0x80
#define HB3_QR 0x80 /* Query */
#define HB3_OPCODE 0x78
#define HB3_AA 0x04
#define HB3_TC 0x02
#define HB3_RD 0x01
#define HB3_AA 0x04 /* Authoritative Answer */
#define HB3_TC 0x02 /* TrunCated */
#define HB3_RD 0x01 /* Recursion Desired */
#define HB4_RA 0x80
#define HB4_AD 0x20
#define HB4_CD 0x10
#define HB4_RA 0x80 /* Recursion Available */
#define HB4_AD 0x20 /* Authenticated Data */
#define HB4_CD 0x10 /* Checking Disabled */
#define HB4_RCODE 0x0f
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
#define SET_OPCODE(x, code) (x)->hb3 = ((x)->hb3 & ~HB3_OPCODE) | code
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
@@ -113,3 +137,16 @@ struct dns_header {
(cp) += 4; \
}
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
/* Escape character in our presentation format for names.
Cannot be '.' or /000 and must be !isprint().
Note that escaped chars are stored as
<NAME_ESCAPE> <orig-char+1>
to ensure that the escaped form of /000 doesn't include /000
*/
#define NAME_ESCAPE 1

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2013 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2015 Simon Kelley"
#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
@@ -50,12 +50,16 @@
#include <getopt.h>
#include "config.h"
#include "ip6addr.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#define countof(x) (long)(sizeof(x) / sizeof(x[0]))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#include "dns-protocol.h"
#include "dhcp-protocol.h"
#ifdef HAVE_DHCP6
@@ -78,7 +82,7 @@ typedef unsigned long long u64;
#if defined(HAVE_SOLARIS_NETWORK)
# include <sys/sockio.h>
#endif
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/un.h>
@@ -113,6 +117,7 @@ typedef unsigned long long u64;
#include <sys/uio.h>
#include <syslog.h>
#include <dirent.h>
#include <utime.h>
#ifndef HAVE_LINUX_NETWORK
# include <net/if_dl.h>
#endif
@@ -160,6 +165,10 @@ struct event_desc {
#define EVENT_FORK_ERR 18
#define EVENT_LUA_ERR 19
#define EVENT_TFTP_ERR 20
#define EVENT_INIT 21
#define EVENT_NEWADDR 22
#define EVENT_NEWROUTE 23
#define EVENT_TIME_ERR 24
/* Exit codes. */
#define EC_GOOD 0
@@ -213,7 +222,7 @@ struct event_desc {
#define OPT_NO_OVERRIDE 30
#define OPT_NO_REBIND 31
#define OPT_ADD_MAC 32
#define OPT_DNSSEC 33
#define OPT_DNSSEC_PROXY 33
#define OPT_CONSEC_ADDR 34
#define OPT_CONNTRACK 35
#define OPT_FQDN_UPDATE 36
@@ -221,7 +230,19 @@ struct event_desc {
#define OPT_TFTP_LC 38
#define OPT_CLEVERBIND 39
#define OPT_TFTP 40
#define OPT_LAST 41
#define OPT_CLIENT_SUBNET 41
#define OPT_QUIET_DHCP 42
#define OPT_QUIET_DHCP6 43
#define OPT_QUIET_RA 44
#define OPT_DNSSEC_VALID 45
#define OPT_DNSSEC_TIME 46
#define OPT_DNSSEC_DEBUG 47
#define OPT_DNSSEC_NO_SIGN 48
#define OPT_LOCAL_SERVICE 49
#define OPT_LOOP_DETECT 50
#define OPT_EXTRALOG 51
#define OPT_TFTP_NO_FAIL 52
#define OPT_LAST 53
/* 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. */
@@ -234,6 +255,12 @@ struct all_addr {
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
/* for log_query */
unsigned int keytag;
/* for cache_insert if RRSIG, DNSKEY, DS */
struct {
unsigned short class, type;
} dnssec;
} addr;
};
@@ -261,10 +288,19 @@ struct naptr {
struct naptr *next;
};
#define TXT_STAT_CACHESIZE 1
#define TXT_STAT_INSERTS 2
#define TXT_STAT_EVICTIONS 3
#define TXT_STAT_MISSES 4
#define TXT_STAT_HITS 5
#define TXT_STAT_AUTH 6
#define TXT_STAT_SERVERS 7
struct txt_record {
char *name;
unsigned char *txt;
unsigned short class, len;
int stat;
struct txt_record *next;
};
@@ -276,18 +312,35 @@ struct ptr_record {
struct cname {
char *alias, *target;
struct cname *next;
};
struct ds_config {
char *name, *digest;
int digestlen, class, algo, keytag, digest_type;
struct ds_config *next;
};
#define ADDRLIST_LITERAL 1
#define ADDRLIST_IPV6 2
#define ADDRLIST_REVONLY 4
struct addrlist {
struct all_addr addr;
int flags, prefixlen;
struct addrlist *next;
};
#define AUTH6 1
#define AUTH4 2
struct auth_zone {
char *domain;
struct subnet {
int is6, prefixlen;
struct in_addr addr4;
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
struct subnet *next;
} *subnet;
struct auth_name_list {
char *name;
int flags;
struct auth_name_list *next;
} *interface_names;
struct addrlist *subnet;
struct auth_zone *next;
};
@@ -307,6 +360,8 @@ struct host_record {
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
int family; /* AF_INET, AF_INET6 or zero for both */
struct addrlist *addr;
struct interface_name *next;
};
@@ -315,8 +370,8 @@ union bigname {
union bigname *next; /* freelist */
};
struct keydata {
struct keydata *next;
struct blockdata {
struct blockdata *next;
unsigned char key[KEYBLOCK_LEN];
};
@@ -326,19 +381,32 @@ struct crec {
union {
struct all_addr addr;
struct {
struct crec *cache;
int uid;
union {
struct crec *cache;
struct interface_name *int_name;
} target;
unsigned int uid; /* 0 if union is interface-name */
} cname;
struct {
struct keydata *keydata;
struct blockdata *keydata;
unsigned short keylen, flags, keytag;
unsigned char algo;
unsigned char digest; /* DS only */
unsigned short flags_or_keyid; /* flags for DNSKEY, keyid for DS */
} key;
} key;
struct {
struct blockdata *keydata;
unsigned short keylen, keytag;
unsigned char algo;
unsigned char digest;
} ds;
struct {
struct blockdata *keydata;
unsigned short keylen, type_covered, keytag;
char algo;
} sig;
} addr;
time_t ttd; /* time to die */
/* used as keylen if F_DS or F_DNSKEY, index to source for F_HOSTS */
int uid;
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
unsigned int uid;
unsigned short flags;
union {
char sname[SMALLDNAME];
@@ -372,10 +440,19 @@ struct crec {
#define F_QUERY (1u<<19)
#define F_NOERR (1u<<20)
#define F_AUTH (1u<<21)
#define F_DNSSEC (1u<<22)
#define F_KEYTAG (1u<<23)
#define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
#define F_NSIGMATCH (1u<<27)
#define F_NOEXTRA (1u<<28)
/* composites */
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
/* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0
#define SRC_CONFIG 1
#define SRC_HOSTS 2
#define SRC_AH 3
/* struct sockaddr is not large enough to hold any address,
@@ -392,6 +469,7 @@ union mysockaddr {
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2
#define IFACE_PERMANENT 4
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
@@ -407,6 +485,8 @@ union mysockaddr {
#define SERV_COUNTED 512 /* workspace for log code */
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
#define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */
struct serverfd {
int fd;
@@ -425,8 +505,11 @@ struct server {
char interface[IF_NAMESIZE+1];
struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd;
int flags, tcpfd, edns_pktsz;
unsigned int queries, failed_queries;
#ifdef HAVE_LOOP
u32 uid;
#endif
struct server *next;
};
@@ -439,7 +522,7 @@ struct ipsets {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found;
char *name;
struct irec *next;
};
@@ -464,20 +547,61 @@ struct resolvc {
int is_default, logged;
time_t mtime;
char *name;
#ifdef HAVE_INOTIFY
int wd; /* inotify watch descriptor */
char *file; /* pointer to file part if path */
#endif
};
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
#define AH_DIR 1
#define AH_INACTIVE 2
#define AH_WD_DONE 4
#define AH_HOSTS 8
#define AH_DHCP_HST 16
#define AH_DHCP_OPT 32
struct hostsfile {
struct hostsfile *next;
int flags;
char *fname;
int index; /* matches to cache entries for logging */
#ifdef HAVE_INOTIFY
int wd; /* inotify watch descriptor */
#endif
unsigned int index; /* matches to cache entries for logging */
};
/* DNSSEC status values. */
#define STAT_SECURE 1
#define STAT_INSECURE 2
#define STAT_BOGUS 3
#define STAT_NEED_DS 4
#define STAT_NEED_KEY 5
#define STAT_TRUNCATED 6
#define STAT_SECURE_WILDCARD 7
#define STAT_NO_SIG 8
#define STAT_NO_DS 9
#define STAT_NO_NS 10
#define STAT_NEED_DS_NEG 11
#define STAT_CHASE_CNAME 12
#define STAT_INSECURE_DS 13
#define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2
#define FREC_HAS_SUBNET 4
#define FREC_DNSKEY_QUERY 8
#define FREC_DS_QUERY 16
#define FREC_AD_QUESTION 32
#define FREC_DO_QUESTION 64
#define FREC_ADDED_PHEADER 128
#define FREC_CHECK_NOSIGN 256
#define FREC_TEST_PKTSZ 512
#ifdef HAVE_DNSSEC
#define HASH_SIZE 20 /* SHA-1 digest size */
#else
#define HASH_SIZE sizeof(int)
#endif
struct frec {
union mysockaddr source;
@@ -489,9 +613,18 @@ struct frec {
#endif
unsigned int iface;
unsigned short orig_id, new_id;
int fd, forwardall, flags;
unsigned int crc;
int log_id, fd, forwardall, flags;
time_t time;
unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC
int class, work_counter;
struct blockdata *stash; /* Saved reply, whilst we validate */
struct blockdata *orig_domain; /* domain of original query, whilst
we're seeing is if in unsigned domain */
size_t stash_len, name_start, name_len;
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
struct frec *blocking_query; /* Query which is blocking us. */
#endif
struct frec *next;
};
@@ -530,15 +663,19 @@ struct dhcp_lease {
#ifdef HAVE_BROKEN_RTC
unsigned int length;
#endif
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override, giaddr;
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
int new_interface; /* save possible originated interface */
int new_prefixlen; /* and its prefix length */
#ifdef HAVE_DHCP6
struct in6_addr addr6;
int iaid;
struct slaac_address {
struct in6_addr addr, local;
struct in6_addr addr;
time_t ping_time;
int backoff; /* zero -> confirmed */
struct slaac_address *next;
@@ -690,6 +827,12 @@ struct prefix_class {
};
#endif
struct ra_interface {
char *name;
int interval, lifetime, prio;
struct ra_interface *next;
};
struct dhcp_context {
unsigned int lease_time, addr_epoch;
struct in_addr netmask, broadcast;
@@ -699,8 +842,8 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
unsigned int valid, preferred;
time_t ra_time, ra_short_period_start;
unsigned int valid, preferred, saved_valid;
time_t ra_time, ra_short_period_start, address_lost_time;
char *template_interface;
#endif
int flags;
@@ -708,22 +851,25 @@ struct dhcp_context {
struct dhcp_context *next, *current;
};
#define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
#define CONTEXT_DEPRECATE 512
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED 2048
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
#define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768
#define CONTEXT_STATIC (1u<<0)
#define CONTEXT_NETMASK (1u<<1)
#define CONTEXT_BRDCAST (1u<<2)
#define CONTEXT_PROXY (1u<<3)
#define CONTEXT_RA_ROUTER (1u<<4)
#define CONTEXT_RA_DONE (1u<<5)
#define CONTEXT_RA_NAME (1u<<6)
#define CONTEXT_RA_STATELESS (1u<<7)
#define CONTEXT_DHCP (1u<<8)
#define CONTEXT_DEPRECATE (1u<<9)
#define CONTEXT_TEMPLATE (1u<<10) /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED (1u<<11)
#define CONTEXT_GC (1u<<12)
#define CONTEXT_RA (1u<<13)
#define CONTEXT_CONF_USED (1u<<14)
#define CONTEXT_USED (1u<<15)
#define CONTEXT_OLD (1u<<16)
#define CONTEXT_V6 (1u<<17)
#define CONTEXT_RA_OFF_LINK (1u<<18)
struct ping_result {
struct in_addr addr;
@@ -760,9 +906,16 @@ struct addr_list {
struct tftp_prefix {
char *interface;
char *prefix;
int missing;
struct tftp_prefix *next;
};
struct dhcp_relay {
struct all_addr local, server;
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
int iface_index; /* working - interface in which requests arrived, for return */
struct dhcp_relay *current, *next;
};
extern struct daemon {
/* datastuctures representing the command-line and
@@ -772,6 +925,7 @@ extern struct daemon {
unsigned int options, options2;
struct resolvc default_resolv, *resolv_files;
time_t last_resolv;
char *servers_file;
struct mx_srv_record *mxnames;
struct naptr *naptr;
struct txt_record *txt, *rr;
@@ -781,6 +935,8 @@ extern struct daemon {
struct auth_zone *auth_zones;
struct interface_name *int_names;
char *mxtarget;
int addr4_netmask;
int addr6_netmask;
char *lease_file;
char *username, *groupname, *scriptuser;
char *luascript;
@@ -792,8 +948,8 @@ extern struct daemon {
struct cond_domain *cond_domain, *synth_domains;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
struct bogus_addr *bogus_addr;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers;
struct ipsets *ipsets;
int log_fac; /* log facility */
@@ -801,9 +957,10 @@ extern struct daemon {
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_vendor *dhcp_vendors;
@@ -812,12 +969,13 @@ extern struct daemon {
struct pxe_service *pxe_services;
struct tag_if *tag_if;
struct addr_list *override_relays;
struct dhcp_relay *relay4, *relay6;
int override;
int enable_pxe;
int doing_ra, doing_dhcp6;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *dynamic_dirs;
int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port;
int start_tftp_port, end_tftp_port;
@@ -833,12 +991,21 @@ extern struct daemon {
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *prefix_classes;
#endif
#ifdef HAVE_DNSSEC
struct ds_config *ds;
int back_to_the_future;
char *timestamp_file;
#endif
/* globally used stuff for DNS */
char *packet; /* packet buffer */
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
unsigned int local_answer, queries_forwarded;
#ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */
#endif
unsigned int local_answer, queries_forwarded, auth_answer;
struct frec *frec_list;
struct serverfd *sfds;
struct irec *interfaces;
@@ -852,13 +1019,19 @@ extern struct daemon {
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
int log_id, log_display_id; /* ids of transactions for logging */
union mysockaddr *log_source_addr;
/* DHCP state */
int dhcpfd, helperfd, pxefd;
#ifdef HAVE_INOTIFY
int inotifyfd;
#endif
#if defined(HAVE_LINUX_NETWORK)
int netlinkfd;
#elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd;
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
#endif
struct iovec dhcp_packet;
char *dhcp_buff, *dhcp_buff2, *dhcp_buff3;
@@ -883,19 +1056,20 @@ extern struct daemon {
/* utility string buffer, hold max sized IP address as string */
char *addrbuff;
char *addrbuff2; /* only allocated when OPT_EXTRALOG */
} *daemon;
/* cache.c */
void cache_init(void);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(int index);
void querystr(char *desc, char *str, unsigned short type);
char *record_source(unsigned int index);
char *querystr(char *desc, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
unsigned short prot);
unsigned int prot);
struct crec *cache_find_by_name(struct crec *crecp,
char *name, time_t now, unsigned short prot);
char *name, time_t now, unsigned int prot);
void cache_end_insert(void);
void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
@@ -905,11 +1079,20 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
int cache_make_stat(struct txt_record *t);
char *cache_get_name(struct crec *crecp);
char *cache_get_cname_target(struct crec *crecp);
struct crec *cache_enumerate(int init);
int read_hostsfile(char *filename, unsigned int index, int cache_size,
struct crec **rhash, int hashsz);
/* blockdata.c */
#ifdef HAVE_DNSSEC
struct keydata *keydata_alloc(char *data, size_t len);
void keydata_free(struct keydata *blocks);
void blockdata_init(void);
void blockdata_report(void);
struct blockdata *blockdata_alloc(char *data, size_t len);
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data);
void blockdata_free(struct blockdata *blocks);
#endif
/* domain.c */
@@ -921,6 +1104,11 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr);
int is_rev_synth(int flag, struct all_addr *addr, char *name);
/* rfc1035.c */
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
unsigned char *skip_questions(struct dns_header *header, size_t plen);
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep);
size_t setup_reply(struct dns_header *header, size_t qlen,
@@ -928,11 +1116,13 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
unsigned long local_ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
time_t now, char **ipsets, int is_sign, int checkrebind,
int checking_disabled);
int no_cache, int secure, int *doctored);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int *ad_reqd, int *do_bit);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign);
int check_for_local_domain(char *name, time_t now);
@@ -940,6 +1130,11 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
#ifdef HAVE_DNSSEC
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
#endif
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
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, ...);
@@ -947,15 +1142,31 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
int private_net(struct in_addr addr, int ban_localhost);
/* auth.c */
#ifdef HAVE_AUTH
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr);
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen,
time_t now, union mysockaddr *peer_addr, int local_query);
int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif
/* dnssec.c */
size_t dnssec_generate_query(struct dns_header *header, 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_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 *neganswer, int *nons);
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
size_t filter_rrsigs(struct dns_header *header, size_t plen);
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
int setup_timestamp(void);
/* util.c */
void rand_init(void);
unsigned short rand16(void);
u32 rand32(void);
u64 rand64(void);
int legal_hostname(char *c);
char *canonicalise(char *s, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
@@ -966,13 +1177,14 @@ int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(const char *a, const char *b);
time_t dnsmasq_time(void);
int netmask_length(struct in_addr mask);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
u64 addr6part(struct in6_addr *addr);
void setaddr6part(struct in6_addr *addr, u64 host);
#endif
int retry_send(void);
int retry_send(ssize_t rc);
void prettyprint_time(char *buf, unsigned int t);
int prettyprint_addr(union mysockaddr *addr, char *buf);
int parse_hex(char *in, unsigned char *out, int maxlen,
@@ -981,18 +1193,18 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
unsigned int mask);
int expand_buf(struct iovec *iov, size_t size);
char *print_mac(char *buff, unsigned char *mac, int len);
void bump_maxfd(int fd, int *max);
int read_write(int fd, unsigned char *packet, int size, int rw);
int wildcard_match(const char* wildcard, const char* match);
int wildcard_matchn(const char* wildcard, const char* match, int num);
/* log.c */
void die(char *message, char *arg1, int exit_code);
int log_start(struct passwd *ent_pw, int errfd);
int log_reopen(char *log_file);
void my_syslog(int priority, const char *format, ...);
void set_log_writer(fd_set *set, int *maxfdp);
void check_log_writer(fd_set *set);
void set_log_writer(void);
void check_log_writer(int force);
void flush_log(void);
/* option.c */
@@ -1000,11 +1212,13 @@ void read_opts (int argc, char **argv, char *compile_opts);
char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len);
void reread_dhcp(void);
void read_servers_file(void);
void set_option_bool(unsigned int opt);
void reset_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list);
char *parse_server(char *arg, union mysockaddr *addr,
union mysockaddr *source_addr, char *interface, int *flags);
int option_read_dynfile(char *file, int flags);
/* forward.c */
void reply_query(int fd, int family, time_t now);
@@ -1012,10 +1226,13 @@ void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait);
struct frec *get_new_frec(time_t now, int *wait, int force);
int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source,
unsigned int iface);
void resend_query();
struct randfd *allocate_rfd(int family);
void free_rfd(struct randfd *rfd);
/* network.c */
int indextoname(int fd, int index, char *name);
@@ -1023,23 +1240,35 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void mark_servers(int flag);
void cleanup_servers(void);
void add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
const char *interface,
const char *domain);
void check_servers(void);
int enumerate_interfaces();
int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
void warn_bound_listeners(void);
void warn_int_names(void);
int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd);
int tcp_interface(int fd, int af);
struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
#if defined(HAVE_LINUX_NETWORK) || defined(HAVE_BSD_NETWORK)
void newaddress(time_t now);
#endif
/* dhcp.c */
#ifdef HAVE_DHCP
@@ -1054,12 +1283,6 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname);
void dhcp_read_ethers(void);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *host_from_dns(struct in_addr addr);
@@ -1081,10 +1304,13 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
void lease_update_slaac(time_t now);
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
void lease_make_duid(time_t now);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
const unsigned char *clid, int hw_len, int hw_type,
int clid_len, time_t now, int force);
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -1115,15 +1341,15 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
#endif
void queue_event(int event);
void send_alarm(time_t event, time_t now);
void send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now);
void poll_resolv(int force, int do_reload, time_t now);
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
void netlink_multicast(time_t now);
void netlink_multicast(void);
#endif
/* bpf.c */
@@ -1131,6 +1357,8 @@ void netlink_multicast(time_t now);
void init_bpf(void);
void send_via_bpf(struct dhcp_packet *mess, size_t len,
struct in_addr iface_addr, struct ifreq *ifr);
void route_init(void);
void route_sock(void);
#endif
/* bpf.c or netlink.c */
@@ -1139,8 +1367,8 @@ int iface_enumerate(int family, void *parm, int (callback)());
/* dbus.c */
#ifdef HAVE_DBUS
char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
void check_dbus_listeners(void);
void set_dbus_listeners(void);
# ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif
@@ -1167,7 +1395,7 @@ int helper_buf_empty(void);
/* tftp.c */
#ifdef HAVE_TFTP
void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now);
void check_tftp_listeners(time_t now);
int do_tftp_script_run(void);
#endif
@@ -1181,7 +1409,7 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
#ifdef HAVE_DHCP6
void dhcp6_init(void);
void dhcp6_packet(time_t now);
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
struct dhcp_context *address6_available(struct dhcp_context *context,
@@ -1192,20 +1420,22 @@ struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
int plain_range);
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname);
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
unsigned int *maclenp, unsigned int *mactypep);
#endif
/* rfc3315.c */
#ifdef HAVE_DHCP6
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
size_t sz, struct in6_addr *client_addr, time_t now);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
#endif
/* dhcp-common.c */
@@ -1225,13 +1455,21 @@ int lookup_dhcp_opt(int prot, char *name);
int lookup_dhcp_len(int prot, int val);
char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK
void bindtodevice(int fd);
char *whichdevice(void);
void bindtodevice(char *device, int fd);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
# endif
void log_context(int family, struct dhcp_context *context);
void log_relay(int family, struct dhcp_relay *relay);
#endif
/* outpacket.c */
@@ -1261,3 +1499,23 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
#endif
/* loop.c */
#ifdef HAVE_LOOP
void loop_send_probes();
int detect_loop(char *query, int type);
#endif
/* inotify.c */
#ifdef HAVE_INOTIFY
void inotify_dnsmasq_init();
int inotify_check(time_t now);
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
#endif
/* poll.c */
void poll_reset(void);
int poll_check(int fd, short event);
void poll_listen(int fd, short event);
int do_poll(int timeout);

2544
src/dnssec.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -224,7 +224,7 @@ char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
if ((c = search_domain6(addr, daemon->cond_domain)))
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -60,10 +60,18 @@ struct script_data
unsigned int length;
#else
time_t expires;
#endif
#ifdef HAVE_TFTP
off_t file_len;
#endif
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
#ifdef HAVE_DHCP6
int iaid, vendorclass_count;
#endif
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
};
static struct script_data *buf = NULL;
@@ -215,20 +223,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
if (!is6)
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
/* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
@@ -239,32 +244,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
/* CLID into packet */
if (!is6)
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
}
#ifdef HAVE_DHCP6
else
if (is6)
{
/* or IAID and server DUID for IPv6 */
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
{
p += sprintf(p, "%.2x", daemon->duid[i]);
if (i != daemon->duid_len - 1)
p += sprintf(p, ":");
}
/* duid not MAC for IPv6 */
for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
}
#endif
@@ -293,13 +291,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_DHCP6
else
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
#endif
#ifdef HAVE_TFTP
/* file length */
if (data.action == ACTION_TFTP)
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%lu", (unsigned long)data.file_len);
#endif
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
@@ -316,7 +316,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield(lua, -2, "destination_address");
lua_pushstring(lua, hostname);
lua_setfield(lua, -2, "file_name");
lua_pushstring(lua, daemon->dhcp_buff);
lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
lua_setfield(lua, -2, "file_size");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
@@ -329,9 +329,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (is6)
{
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "client_duid");
lua_pushstring(lua, daemon->packet);
lua_setfield(lua, -2, "client_duid");
lua_pushstring(lua, daemon->dhcp_packet.iov_base);
lua_setfield(lua, -2, "server_duid");
lua_pushstring(lua, daemon->dhcp_buff3);
lua_setfield(lua, -2, "iaid");
@@ -375,12 +375,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (!is6)
buf = grab_extradata_lua(buf, end, "vendor_class");
#ifdef HAVE_DHCP6
else
for (i = 0; i < data.hwaddr_len; i++)
{
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
else if (data.vendorclass_count != 0)
{
sprintf(daemon->dhcp_buff2, "vendor_class_id");
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
for (i = 0; i < data.vendorclass_count - 1; i++)
{
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
}
#endif
buf = grab_extradata_lua(buf, end, "supplied_hostname");
@@ -423,7 +427,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield(lua, -2, "old_hostname");
}
if (!is6)
if (!is6 || data.hwaddr_len != 0)
{
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "mac_address");
@@ -476,17 +480,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (data.action != ACTION_TFTP)
{
if (is6)
{
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
}
#ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
my_setenv("DNSMASQ_SERVER_DUID", is6 ? daemon->dhcp_packet.iov_base : NULL, &err);
my_setenv("DNSMASQ_MAC", is6 && data.hwaddr_len != 0 ? daemon->dhcp_buff : NULL, &err);
#endif
if (!is6 && data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
if (strlen(data.interface) != 0)
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
my_setenv("DNSMASQ_CLIENT_ID", !is6 && data.clid_len != 0 ? daemon->packet : NULL, &err);
my_setenv("DNSMASQ_INTERFACE", strlen(data.interface) != 0 ? data.interface : NULL, &err);
#ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u", data.length);
@@ -496,8 +497,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif
if (domain)
my_setenv("DNSMASQ_DOMAIN", domain, &err);
my_setenv("DNSMASQ_DOMAIN", domain, &err);
end = extradata + data.ed_len;
buf = extradata;
@@ -507,10 +507,10 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
#ifdef HAVE_DHCP6
else
{
if (data.hwaddr_len != 0)
if (data.vendorclass_count != 0)
{
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
for (i = 0; i < data.hwaddr_len - 1; i++)
for (i = 0; i < data.vendorclass_count - 1; i++)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
@@ -535,8 +535,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
if (is6)
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
else if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
else
my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
for (i = 0; buf; i++)
{
@@ -544,22 +544,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
}
if (data.action != ACTION_DEL && data.remaining_time != 0)
{
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
}
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", data.action != ACTION_DEL && data.remaining_time != 0 ? daemon->dhcp_buff2 : NULL, &err);
if (data.action == ACTION_OLD_HOSTNAME && hostname)
{
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
hostname = NULL;
}
my_setenv("DNSMASQ_OLD_HOSTNAME", data.action == ACTION_OLD_HOSTNAME ? hostname : NULL, &err);
if (data.action == ACTION_OLD_HOSTNAME)
hostname = NULL;
}
if (option_bool(OPT_LOG_OPTS))
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
my_setenv("DNSMASQ_LOG_DHCP", option_bool(OPT_LOG_OPTS) ? "1" : NULL, &err);
/* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
@@ -570,7 +564,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
execl(daemon->lease_change_command,
p ? p+1 : daemon->lease_change_command,
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
action_str, is6 ? daemon->packet : daemon->dhcp_buff,
daemon->addrbuff, hostname, (char*)NULL);
err = errno;
}
/* failed, send event so the main process logs the problem */
@@ -581,31 +576,44 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
static void my_setenv(const char *name, const char *value, int *error)
{
if (*error == 0 && setenv(name, value, 1) != 0)
*error = errno;
if (*error == 0)
{
if (!value)
unsetenv(name);
else if (setenv(name, value, 1) != 0)
*error = errno;
}
}
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
{
unsigned char *next;
unsigned char *next = NULL;
char *val = NULL;
if (!buf || (buf == end))
return NULL;
for (next = buf; *next != 0; next++)
if (next == end)
return NULL;
if (next != buf)
if (buf && (buf != end))
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv(env, (char *)buf, err);
}
for (next = buf; ; next++)
if (next == end)
{
next = NULL;
break;
}
else if (*next == 0)
break;
return next + 1;
if (next && (next != buf))
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
val = (char *)buf;
}
}
my_setenv(env, val, err);
return next ? next + 1 : NULL;
}
#ifdef HAVE_LUASCRIPT
@@ -656,8 +664,6 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6
int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
if (!daemon->dhcp)
fd = daemon->dhcp6fd;
#endif
@@ -678,11 +684,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->action = action;
buf->flags = lease->flags;
#ifdef HAVE_DHCP6
if (is6)
buf->hwaddr_len = lease->vendorclass_count;
else
buf->vendorclass_count = lease->vendorclass_count;
buf->addr6 = lease->addr6;
buf->iaid = lease->iaid;
#endif
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len;
buf->ed_len = ed_len;
@@ -739,13 +745,13 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
buf->action = ACTION_TFTP;
buf->hostname_len = filename_len;
buf->hwaddr_len = file_len;
buf->file_len = file_len;
if ((buf->flags = peer->sa.sa_family) == AF_INET)
buf->addr = peer->in.sin_addr;
#ifdef HAVE_IPV6
else
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
buf->addr6 = peer->in6.sin6_addr;
#endif
memcpy((unsigned char *)(buf+1), filename, filename_len);

288
src/inotify.c Normal file
View File

@@ -0,0 +1,288 @@
/* dnsmasq is Copyright (c) 2000-2015 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_INOTIFY
#include <sys/inotify.h>
#include <sys/param.h> /* For MAXSYMLINKS */
/* the strategy is to set a inotify on the directories containing
resolv files, for any files in the directory which are close-write
or moved into the directory.
When either of those happen, we look to see if the file involved
is actually a resolv-file, and if so, call poll-resolv with
the "force" argument, to ensure it's read.
This adds one new error condition: the directories containing
all specified resolv-files must exist at start-up, even if the actual
files don't.
*/
static char *inotify_buffer;
#define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
/* If path is a symbolic link, return the path it
points to, made absolute if relative.
If path doesn't exist or is not a symlink, return NULL.
Return value is malloc'ed */
static char *my_readlink(char *path)
{
ssize_t rc, size = 64;
char *buf;
while (1)
{
buf = safe_malloc(size);
rc = readlink(path, buf, (size_t)size);
if (rc == -1)
{
/* Not link or doesn't exist. */
if (errno == EINVAL || errno == ENOENT)
return NULL;
else
die(_("cannot access path %s: %s"), path, EC_MISC);
}
else if (rc < size-1)
{
char *d;
buf[rc] = 0;
if (buf[0] != '/' && ((d = strrchr(path, '/'))))
{
/* Add path to relative link */
char *new_buf = safe_malloc((d - path) + strlen(buf) + 2);
*(d+1) = 0;
strcpy(new_buf, path);
strcat(new_buf, buf);
free(buf);
buf = new_buf;
}
return buf;
}
/* Buffer too small, increase and retry */
size += 64;
free(buf);
}
}
void inotify_dnsmasq_init()
{
struct resolvc *res;
inotify_buffer = safe_malloc(INOTIFY_SZ);
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (daemon->inotifyfd == -1)
die(_("failed to create inotify: %s"), NULL, EC_MISC);
for (res = daemon->resolv_files; res; res = res->next)
{
char *d, *new_path, *path = safe_malloc(strlen(res->name) + 1);
int links = MAXSYMLINKS;
strcpy(path, res->name);
/* Follow symlinks until we reach a non-symlink, or a non-existant file. */
while ((new_path = my_readlink(path)))
{
if (links-- == 0)
die(_("too many symlinks following %s"), res->name, EC_MISC);
free(path);
path = new_path;
}
res->wd = -1;
if ((d = strrchr(path, '/')))
{
*d = 0; /* make path just directory */
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
res->file = d+1; /* pointer to filename */
*d = '/';
if (res->wd == -1 && errno == ENOENT)
die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
}
if (res->wd == -1)
die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
}
}
/* initialisation for dynamic-dir. Set inotify watch for each directory, and read pre-existing files */
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz)
{
struct hostsfile *ah;
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
{
DIR *dir_stream = NULL;
struct dirent *ent;
struct stat buf;
if (!(ah->flags & flag))
continue;
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
{
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
ah->fname, strerror(errno));
continue;
}
if (!(ah->flags & AH_WD_DONE))
{
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
ah->flags |= AH_WD_DONE;
}
/* Read contents of dir _after_ calling add_watch, in the hope of avoiding
a race which misses files being added as we start */
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
{
my_syslog(LOG_ERR, _("failed to create inotify for %s: %s"),
ah->fname, strerror(errno));
continue;
}
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
if ((path = whine_malloc(lendir + lenfile + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, ent->d_name);
/* ignore non-regular files */
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
{
if (ah->flags & AH_HOSTS)
total_size = read_hostsfile(path, ah->index, total_size, rhash, revhashsz);
#ifdef HAVE_DHCP
else if (ah->flags & (AH_DHCP_HST | AH_DHCP_OPT))
option_read_dynfile(path, ah->flags);
#endif
}
free(path);
}
}
}
}
int inotify_check(time_t now)
{
int hit = 0;
struct hostsfile *ah;
while (1)
{
int rc;
char *p;
struct resolvc *res;
struct inotify_event *in;
while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
if (rc <= 0)
break;
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
{
in = (struct inotify_event*)p;
for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
hit = 1;
/* ignore emacs backups and dotfiles */
if (in->len == 0 ||
in->name[in->len - 1] == '~' ||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
in->name[0] == '.')
continue;
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
if (ah->wd == in->wd)
{
size_t lendir = strlen(ah->fname);
char *path;
if ((path = whine_malloc(lendir + in->len + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, in->name);
my_syslog(LOG_INFO, _("inotify, new or changed file %s"), path);
if (ah->flags & AH_HOSTS)
{
read_hostsfile(path, ah->index, 0, NULL, 0);
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6)
{
/* Propogate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
#endif
}
#ifdef HAVE_DHCP
else if (ah->flags & AH_DHCP_HST)
{
if (option_read_dynfile(path, AH_DHCP_HST))
{
/* Propogate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
}
else if (ah->flags & AH_DHCP_OPT)
option_read_dynfile(path, AH_DHCP_OPT);
#endif
free(path);
}
}
}
}
return hit;
}
#endif /* INOTIFY */

34
src/ip6addr.h Normal file
View File

@@ -0,0 +1,34 @@
/* dnsmasq is Copyright (c) 2000-2015 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/>.
*/
#define IN6_IS_ADDR_ULA(a) \
((((__const uint32_t *) (a))[0] & htonl (0xff000000)) \
== htonl (0xfd000000))
#define IN6_IS_ADDR_ULA_ZERO(a) \
(((__const uint32_t *) (a))[0] == htonl (0xfd000000) \
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)
#define IN6_IS_ADDR_LINK_LOCAL_ZERO(a) \
(((__const uint32_t *) (a))[0] == htonl (0xfe800000) \
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)

View File

@@ -16,7 +16,7 @@
#include "dnsmasq.h"
#ifdef HAVE_IPSET
#if defined(HAVE_IPSET) && defined(HAVE_LINUX_NETWORK)
#include <string.h>
#include <errno.h>
@@ -121,7 +121,6 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
struct my_nlattr *nested[2];
uint8_t proto;
int addrsz = INADDRSZ;
ssize_t rc;
#ifdef HAVE_IPV6
if (af == AF_INET6)
@@ -162,9 +161,10 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
while ((rc = sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
(struct sockaddr *)&snl, sizeof(snl))) == -1 && retry_send());
return rc;
while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
(struct sockaddr *)&snl, sizeof(snl))));
return errno == 0 ? 0 : -1;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -108,6 +108,7 @@ void lease_init(time_t now)
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
int iaid;
if (s[0] == 'T')
{
@@ -115,12 +116,12 @@ void lease_init(time_t now)
s++;
}
hw_type = strtoul(s, NULL, 10);
iaid = strtoul(s, NULL, 10);
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now, 0);
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, 0, clid_len, now, 0);
lease_set_iaid(lease, iaid);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
}
@@ -187,10 +188,12 @@ void lease_update_from_configs(void)
char *name;
for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
@@ -277,10 +280,10 @@ void lease_update_file(time_t now)
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
#endif
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
lease->hwaddr_type, daemon->addrbuff);
lease->iaid, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0)
@@ -303,7 +306,7 @@ void lease_update_file(time_t now)
file_dirty = 0;
}
/* Set alarm for when the first lease expires + slop. */
/* Set alarm for when the first lease expires. */
next_event = 0;
#ifdef HAVE_DHCP6
@@ -328,8 +331,8 @@ void lease_update_file(time_t now)
for (lease = leases; lease; lease = lease->next)
if (lease->expires != 0 &&
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
next_event = lease->expires + 10;
(next_event == 0 || difftime(next_event, lease->expires) > 0.0))
next_event = lease->expires;
if (err)
{
@@ -349,16 +352,21 @@ static int find_interface_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_lease *lease;
int prefix = netmask_length(netmask);
(void) label;
(void) broadcast;
(void) vparam;
for (lease = leases; lease; lease = lease->next)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net(local, lease->addr, netmask))
lease_set_interface(lease, if_index, *((time_t *)vparam));
if (!(lease->flags & (LEASE_TA | LEASE_NA)) &&
is_same_net(local, lease->addr, netmask) &&
prefix > lease->new_prefixlen)
{
lease->new_interface = if_index;
lease->new_prefixlen = prefix;
}
return 1;
}
@@ -368,17 +376,23 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
int preferred, int valid, void *vparam)
{
struct dhcp_lease *lease;
(void)scope;
(void)flags;
(void)preferred;
(void)valid;
(void)vparam;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
lease_set_interface(lease, if_index, *((time_t *)vparam));
if (is_same_net6(local, &lease->addr6, prefix) && prefix > lease->new_prefixlen) {
/* save prefix length for comparison, as we might get shorter matching
* prefix in upcoming netlink GETADDR responses
* */
lease->new_interface = if_index;
lease->new_prefixlen = prefix;
}
return 1;
}
@@ -411,18 +425,33 @@ void lease_update_slaac(time_t now)
start-time. */
void lease_find_interfaces(time_t now)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
lease->new_prefixlen = lease->new_interface = 0;
iface_enumerate(AF_INET, &now, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);
#endif
for (lease = leases; lease; lease = lease->next)
if (lease->new_interface != 0)
lease_set_interface(lease, lease->new_interface, now);
}
#ifdef HAVE_DHCP6
void lease_make_duid(time_t now)
{
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (!daemon->duid && daemon->dhcp6)
if (!daemon->duid && daemon->doing_dhcp6)
{
file_dirty = 1;
make_duid(now);
}
#endif
}
#endif
@@ -459,17 +488,24 @@ void lease_update_dns(int force)
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
}
}
#endif
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->addr6,
lease->expires);
#else
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, prot, (struct all_addr *)&lease->addr, lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, prot, (struct all_addr *)&lease->addr, lease->expires);
#endif
}
dns_dirty = 0;
@@ -564,10 +600,10 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
for (lease = leases; lease; lease = lease->next)
{
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue;
if (memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
continue;
if ((clid_len != lease->clid_len ||
@@ -604,7 +640,7 @@ struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_typ
if (lease->flags & LEASE_USED)
continue;
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue;
if ((clid_len != lease->clid_len ||
@@ -626,8 +662,8 @@ struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 add
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
if (is_same_net6(&lease->addr6, net, prefix) &&
(prefix == 128 || addr6part(&lease->addr6) == addr))
return lease;
}
@@ -646,11 +682,11 @@ u64 lease_find_max_addr6(struct dhcp_context *context)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr)
addr = addr6part((struct in6_addr *)lease->hwaddr);
if (is_same_net6(&lease->addr6, &context->start6, 64) &&
addr6part(&lease->addr6) > addr6part(&context->start6) &&
addr6part(&lease->addr6) <= addr6part(&context->end6) &&
addr6part(&lease->addr6) > addr)
addr = addr6part(&lease->addr6);
}
return addr;
@@ -692,6 +728,7 @@ static struct dhcp_lease *lease_allocate(void)
#ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */
#endif
lease->hwaddr_len = 256; /* illegal value */
lease->next = leases;
leases = lease;
@@ -705,11 +742,8 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
{
struct dhcp_lease *lease = lease_allocate();
if (lease)
{
lease->addr = addr;
lease->hwaddr_len = 256; /* illegal value */
}
lease->addr = addr;
return lease;
}
@@ -720,8 +754,9 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
if (lease)
{
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->addr6 = *addrp;
lease->flags |= lease_type;
lease->iaid = 0;
}
return lease;
@@ -730,14 +765,23 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
{
time_t exp = now + (time_t)len;
time_t exp;
if (len == 0xffffffff)
{
exp = 0;
len = 0;
}
else
{
exp = now + (time_t)len;
/* Check for 2038 overflow. Make the lease
inifinite in that case, as the least disruptive
thing we can do. */
if (difftime(exp, now) <= 0.0)
exp = 0;
}
if (exp != lease->expires)
{
dns_dirty = 1;
@@ -758,9 +802,20 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
#endif
}
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len,
time_t now, int force)
#ifdef HAVE_DHCP6
void lease_set_iaid(struct dhcp_lease *lease, int iaid)
{
if (lease->iaid != iaid)
{
lease->iaid = iaid;
lease->flags |= LEASE_CHANGED;
}
}
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
const unsigned char *clid, int hw_len, int hw_type,
int clid_len, time_t now, int force)
{
#ifdef HAVE_DHCP6
int change = force;
@@ -768,6 +823,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
#endif
(void)force;
(void)now;
if (hw_len != lease->hwaddr_len ||
hw_type != lease->hwaddr_type ||
@@ -779,9 +835,6 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
lease->hwaddr_type = hw_type;
lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */
#ifdef HAVE_DHCP6
change = 1;
#endif
}
/* only update clid when one is available, stops packets
@@ -844,7 +897,7 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
@@ -939,6 +992,8 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
{
(void)now;
if (lease->last_interface == interface)
return;
@@ -967,6 +1022,8 @@ int do_script_run(time_t now)
{
struct dhcp_lease *lease;
(void)now;
#ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -421,18 +421,15 @@ void my_syslog(int priority, const char *format, ...)
}
}
void set_log_writer(fd_set *set, int *maxfdp)
void set_log_writer(void)
{
if (entries && log_fd != -1 && connection_good)
{
FD_SET(log_fd, set);
bump_maxfd(log_fd, maxfdp);
}
poll_listen(log_fd, POLLOUT);
}
void check_log_writer(fd_set *set)
void check_log_writer(int force)
{
if (log_fd != -1 && (!set || FD_ISSET(log_fd, set)))
if (log_fd != -1 && (force || poll_check(log_fd, POLLOUT)))
log_write();
}

117
src/loop.c Normal file
View File

@@ -0,0 +1,117 @@
/* dnsmasq is Copyright (c) 2000-2015 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_LOOP
static ssize_t loop_make_probe(u32 uid);
void loop_send_probes()
{
struct server *serv;
if (!option_bool(OPT_LOOP_DETECT))
return;
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
{
ssize_t len = loop_make_probe(serv->uid);
int fd;
struct randfd *rfd = NULL;
if (serv->sfd)
fd = serv->sfd->fd;
else
{
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
continue;
fd = rfd->fd;
}
while (retry_send(sendto(fd, daemon->packet, len, 0,
&serv->addr.sa, sa_len(&serv->addr))));
free_rfd(rfd);
}
}
static ssize_t loop_make_probe(u32 uid)
{
struct dns_header *header = (struct dns_header *)daemon->packet;
unsigned char *p = (unsigned char *)(header+1);
/* packet buffer overwritten */
daemon->srv_save = NULL;
header->id = rand16();
header->ancount = header->nscount = header->arcount = htons(0);
header->qdcount = htons(1);
header->hb3 = HB3_RD;
header->hb4 = 0;
SET_OPCODE(header, QUERY);
*p++ = 8;
sprintf((char *)p, "%.8x", uid);
p += 8;
*p++ = strlen(LOOP_TEST_DOMAIN);
strcpy((char *)p, LOOP_TEST_DOMAIN); /* Add terminating zero */
p += strlen(LOOP_TEST_DOMAIN) + 1;
PUTSHORT(LOOP_TEST_TYPE, p);
PUTSHORT(C_IN, p);
return p - (unsigned char *)header;
}
int detect_loop(char *query, int type)
{
int i;
u32 uid;
struct server *serv;
if (!option_bool(OPT_LOOP_DETECT))
return 0;
if (type != LOOP_TEST_TYPE ||
strlen(LOOP_TEST_DOMAIN) + 9 != strlen(query) ||
strstr(query, LOOP_TEST_DOMAIN) != query + 9)
return 0;
for (i = 0; i < 8; i++)
if (!isxdigit(query[i]))
return 0;
uid = strtol(query, NULL, 16);
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
uid == serv->uid)
{
serv->flags |= SERV_LOOP;
check_servers(); /* log new state */
return 1;
}
return 0;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -38,8 +38,7 @@
static struct iovec iov;
static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h);
static void nl_newaddress(time_t now);
static void nl_async(struct nlmsghdr *h);
void netlink_init(void)
{
@@ -143,7 +142,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct nlmsghdr *h;
ssize_t len;
static unsigned int seq = 0;
int callback_ok = 1, newaddr = 0;
int callback_ok = 1;
struct {
struct nlmsghdr nlh;
@@ -170,10 +169,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
req.g.rtgen_family = family;
/* Don't block in recvfrom if send fails */
while((len = sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
(struct sockaddr *)&addr, sizeof(addr))) == -1 && retry_send());
if (len == -1)
while(retry_send(sendto(daemon->netlinkfd, (void *)&req, sizeof(req), 0,
(struct sockaddr *)&addr, sizeof(addr))));
if (errno != 0)
return 0;
while (1)
@@ -192,18 +191,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{
/* May be multicast arriving async */
if (nl_async(h))
newaddr = 1;
nl_async(h);
}
else if (h->nlmsg_type == NLMSG_DONE)
{
/* handle async new interface address arrivals, these have to be done
after we complete as we're not re-entrant */
if (newaddr)
nl_newaddress(dnsmasq_time());
return callback_ok;
}
return callback_ok;
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
@@ -217,7 +208,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct in_addr netmask, addr, broadcast;
char *label = NULL;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
broadcast.s_addr = 0;
@@ -263,6 +255,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifa->ifa_flags & IFA_F_DEPRECATED)
flags |= IFACE_DEPRECATED;
if (!(ifa->ifa_flags & IFA_F_TEMPORARY))
flags |= IFACE_PERMANENT;
if (addrp && callback_ok)
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), flags,
@@ -325,11 +320,11 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
}
void netlink_multicast(time_t now)
void netlink_multicast(void)
{
ssize_t len;
struct nlmsghdr *h;
int flags, newaddr = 0;
int flags;
/* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
@@ -338,24 +333,19 @@ void netlink_multicast(time_t now)
if ((len = netlink_recv()) != -1)
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (nl_async(h))
newaddr = 1;
nl_async(h);
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
nl_newaddress(now);
}
static int nl_async(struct nlmsghdr *h)
static void nl_async(struct nlmsghdr *h)
{
if (h->nlmsg_type == NLMSG_ERROR)
{
struct nlmsgerr *err = NLMSG_DATA(h);
if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
return 0;
}
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
{
@@ -367,54 +357,11 @@ static int nl_async(struct nlmsghdr *h)
struct rtmsg *rtm = NLMSG_DATA(h);
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK)
{
/* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0;
if (daemon->srv_save)
{
int fd;
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return 0;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
}
return 0;
queue_event(EVENT_NEWROUTE);
}
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
return 1; /* clever bind mode - rescan */
return 0;
queue_event(EVENT_NEWADDR);
}
static void nl_newaddress(time_t now)
{
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
enumerate_interfaces();
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
join_multicast(0);
dhcp_construct_contexts(now);
}
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -99,6 +99,8 @@ int indextoname(int fd, int index, char *name)
int indextoname(int fd, int index, char *name)
{
(void)fd;
if (index == 0 || !if_indextoname(index, name))
return 0;
@@ -110,10 +112,12 @@ int indextoname(int fd, int index, char *name)
int iface_check(int family, struct all_addr *addr, char *name, int *auth)
{
struct iname *tmp;
int ret = 1;
int ret = 1, match_addr = 0;
/* Note: have to check all and not bail out early, so that we set the
"used" flags. */
"used" flags.
May be called with family == AF_LOCALto check interface by name only. */
if (auth)
*auth = 0;
@@ -132,25 +136,27 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
{
if (family == AF_INET &&
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
ret = tmp->used = 1;
ret = match_addr = tmp->used = 1;
#ifdef HAVE_IPV6
else if (family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
&addr->addr.addr6))
ret = tmp->used = 1;
ret = match_addr = tmp->used = 1;
#endif
}
}
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
ret = 0;
if (!match_addr)
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
ret = 0;
for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
if (tmp->name)
{
if (strcmp(tmp->name, name) == 0)
if (strcmp(tmp->name, name) == 0 &&
(tmp->addr.sa.sa_family == 0 || tmp->addr.sa.sa_family == family))
break;
}
else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
@@ -224,52 +230,185 @@ int label_exception(int index, int family, struct all_addr *addr)
return 0;
}
static int iface_allowed(struct irec **irecp, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int dad)
struct iface_param {
struct addrlist *spare;
int fd;
};
static int iface_allowed(struct iface_param *param, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
{
struct irec *iface;
int fd, mtu = 0, loopback;
int mtu = 0, loopback;
struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1;
int auth_dns = 0;
#ifdef HAVE_DHCP
#if defined(HAVE_DHCP) || defined(HAVE_TFTP)
struct iname *tmp;
#endif
/* check whether the interface IP has been added already
we call this routine multiple times. */
for (iface = *irecp; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, addr))
{
iface->dad = dad;
return 1;
}
(void)prefixlen;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
!indextoname(fd, if_index, ifr.ifr_name) ||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
{
if (fd != -1)
{
int errsave = errno;
close(fd);
errno = errsave;
}
return 0;
}
if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
return 0;
loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (loopback)
dhcp_ok = 0;
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
close(fd);
if (!label)
label = ifr.ifr_name;
/* maintain a list of all addresses on all interfaces for --local-service option */
if (option_bool(OPT_LOCAL_SERVICE))
{
struct addrlist *al;
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = daemon->interface_addrs;
daemon->interface_addrs = al;
al->prefixlen = prefixlen;
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
#ifdef HAVE_IPV6
else
{
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
}
#endif
}
}
/* If we are restricting the set of interfaces to use, make
#ifdef HAVE_IPV6
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
#endif
{
struct interface_name *int_name;
struct addrlist *al;
#ifdef HAVE_AUTH
struct auth_zone *zone;
struct auth_name_list *name;
/* Find subnets in auth_zones */
for (zone = daemon->auth_zones; zone; zone = zone->next)
for (name = zone->interface_names; name; name = name->next)
if (wildcard_match(name->name, label))
{
if (addr->sa.sa_family == AF_INET && (name->flags & AUTH4))
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = zone->subnet;
zone->subnet = al;
al->prefixlen = prefixlen;
al->addr.addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
}
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 && (name->flags & AUTH6))
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = zone->subnet;
zone->subnet = al;
al->prefixlen = prefixlen;
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
}
}
#endif
}
#endif
/* Update addresses from interface_names. These are a set independent
of the set we're listening on. */
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0 &&
(addr->sa.sa_family == int_name->family || int_name->family == 0))
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = int_name->addr;
int_name->addr = al;
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
#ifdef HAVE_IPV6
else
{
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
#endif
}
}
}
/* check whether the interface IP has been added already
we call this routine multiple times. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, addr))
{
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
iface->found = 1; /* for garbage collection */
return 1;
}
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (daemon->if_names && loopback)
{
@@ -292,9 +431,6 @@ static int iface_allowed(struct irec **irecp, int if_index, char *label,
}
}
if (!label)
label = ifr.ifr_name;
if (addr->sa.sa_family == AF_INET &&
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
return 1;
@@ -321,6 +457,18 @@ static int iface_allowed(struct irec **irecp, int if_index, char *label,
}
#endif
#ifdef HAVE_TFTP
if (daemon->tftp_interfaces)
{
/* dedicated tftp interface list */
tftp_ok = 0;
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
tftp_ok = 1;
}
#endif
/* add to list */
if ((iface = whine_malloc(sizeof(struct irec))))
{
@@ -330,14 +478,15 @@ static int iface_allowed(struct irec **irecp, int if_index, char *label,
iface->dhcp_ok = dhcp_ok;
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
iface->done = iface->multicast_done = 0;
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
iface->found = 1;
iface->done = iface->multicast_done = iface->warned = 0;
iface->index = if_index;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
iface->next = *irecp;
*irecp = iface;
iface->next = daemon->interfaces;
daemon->interfaces = iface;
return 1;
}
free(iface);
@@ -357,7 +506,6 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
struct in_addr netmask; /* dummy */
netmask.s_addr = 0;
(void)prefix; /* warning */
(void)scope; /* warning */
(void)preferred;
(void)valid;
@@ -369,9 +517,13 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_addr = *local;
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = if_index;
/* FreeBSD insists this is zero for non-linklocal addresses */
if (IN6_IS_ADDR_LINKLOCAL(local))
addr.in6.sin6_scope_id = if_index;
else
addr.in6.sin6_scope_id = 0;
return iface_allowed((struct irec **)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
}
#endif
@@ -379,6 +531,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
union mysockaddr addr;
int prefix, bit;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -389,17 +542,141 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
addr.in.sin_addr = local;
addr.in.sin_port = htons(daemon->port);
return iface_allowed((struct irec **)vparam, if_index, label, &addr, netmask, 0);
/* determine prefix length from netmask */
for (prefix = 32, bit = 1; (bit & ntohl(netmask.s_addr)) == 0 && prefix != 0; bit = bit << 1, prefix--);
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
}
int enumerate_interfaces(void)
int enumerate_interfaces(int reset)
{
#ifdef HAVE_IPV6
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
return 0;
static struct addrlist *spare = NULL;
static int done = 0;
struct iface_param param;
int errsave, ret = 1;
struct addrlist *addr, *tmp;
struct interface_name *intname;
struct irec *iface;
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
/* Do this max once per select cycle - also inhibits netlink socket use
in TCP child processes. */
if (reset)
{
done = 0;
return 1;
}
if (done)
return 1;
done = 1;
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
/* Mark interfaces for garbage collection */
for (iface = daemon->interfaces; iface; iface = iface->next)
iface->found = 0;
/* remove addresses stored against interface_names */
for (intname = daemon->int_names; intname; intname = intname->next)
{
for (addr = intname->addr; addr; addr = tmp)
{
tmp = addr->next;
addr->next = spare;
spare = addr;
}
intname->addr = NULL;
}
/* Remove list of addresses of local interfaces */
for (addr = daemon->interface_addrs; addr; addr = tmp)
{
tmp = addr->next;
addr->next = spare;
spare = addr;
}
daemon->interface_addrs = NULL;
#ifdef HAVE_AUTH
/* remove addresses stored against auth_zone subnets, but not
ones configured as address literals */
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (zone->interface_names)
{
struct addrlist **up;
for (up = &zone->subnet, addr = zone->subnet; addr; addr = tmp)
{
tmp = addr->next;
if (addr->flags & ADDRLIST_LITERAL)
up = &addr->next;
else
{
*up = addr->next;
addr->next = spare;
spare = addr;
}
}
}
#endif
param.spare = spare;
#ifdef HAVE_IPV6
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
#endif
if (ret)
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
errsave = errno;
close(param.fd);
if (option_bool(OPT_CLEVERBIND))
{
/* Garbage-collect listeners listening on addresses that no longer exist.
Does nothing when not binding interfaces or for listeners on localhost,
since the ->iface field is NULL. Note that this needs the protections
against re-entrancy, hence it's here. It also means there's a possibility,
in OPT_CLEVERBIND mode, that at listener will just disappear after
a call to enumerate_interfaces, this is checked OK on all calls. */
struct listener *l, *tmp, **up;
for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
{
tmp = l->next;
if (!l->iface || l->iface->found)
up = &l->next;
else
{
*up = l->next;
/* In case it ever returns */
l->iface->done = 0;
if (l->fd != -1)
close(l->fd);
if (l->tcpfd != -1)
close(l->tcpfd);
if (l->tftpfd != -1)
close(l->tftpfd);
free(l);
}
}
}
errno = errsave;
spare = param.spare;
return ret;
}
/* set NONBLOCK bit on fd: See Stevens 16.6 */
@@ -421,7 +698,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if ((fd = socket(family, type, 0)) == -1)
{
int port;
int port, errsav;
char *s;
/* No error if the kernel just doesn't support this IP flavour */
@@ -431,6 +708,7 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
return -1;
err:
errsav = errno;
port = prettyprint_addr(addr, daemon->addrbuff);
if (!option_bool(OPT_NOWILD) && !option_bool(OPT_CLEVERBIND))
sprintf(daemon->addrbuff, "port %d", port);
@@ -438,7 +716,9 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if (fd != -1)
close (fd);
errno = errsav;
if (dienow)
{
/* failure to bind addresses given by --listen-address at this point
@@ -468,9 +748,9 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
if (listen(fd, 5) == -1)
goto err;
}
else if (!option_bool(OPT_NOWILD))
else if (family == AF_INET)
{
if (family == AF_INET)
if (!option_bool(OPT_NOWILD))
{
#if defined(HAVE_LINUX_NETWORK)
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
@@ -481,11 +761,11 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
goto err;
#endif
}
#ifdef HAVE_IPV6
else if (!set_ipv6pktinfo(fd))
goto err;
#endif
}
#ifdef HAVE_IPV6
else if (!set_ipv6pktinfo(fd))
goto err;
#endif
return fd;
}
@@ -595,6 +875,8 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
struct listener *l = NULL;
int fd = -1, tcpfd = -1, tftpfd = -1;
(void)do_tftp;
if (daemon->port != 0)
{
fd = make_sock(addr, SOCK_DGRAM, dienow);
@@ -631,7 +913,8 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
l->family = addr->sa.sa_family;
l->fd = fd;
l->tcpfd = tcpfd;
l->tftpfd = tftpfd;
l->tftpfd = tftpfd;
l->iface = NULL;
}
return l;
@@ -678,7 +961,7 @@ void create_bound_listeners(int dienow)
struct iname *if_tmp;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (!iface->done && !iface->dad &&
if (!iface->done && !iface->dad && iface->found &&
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
{
new->iface = iface;
@@ -702,12 +985,58 @@ void create_bound_listeners(int dienow)
if (!if_tmp->used &&
(new = create_listeners(&if_tmp->addr, !!option_bool(OPT_TFTP), dienow)))
{
new->iface = NULL;
new->next = daemon->listeners;
daemon->listeners = new;
}
}
/* In --bind-interfaces, the only access control is the addresses we're listening on.
There's nothing to avoid a query to the address of an internal interface arriving via
an external interface where we don't want to accept queries, except that in the usual
case the addresses of internal interfaces are RFC1918. When bind-interfaces in use,
and we listen on an address that looks like it's probably globally routeable, shout.
The fix is to use --bind-dynamic, which actually checks the arrival interface too.
Tough if your platform doesn't support this.
Note that checking the arrival interface is supported in the standard IPv6 API and
always done, so we don't warn about any IPv6 addresses here.
*/
void warn_bound_listeners(void)
{
struct irec *iface;
int advice = 0;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (!iface->dns_auth)
{
if (iface->addr.sa.sa_family == AF_INET)
{
if (!private_net(iface->addr.in.sin_addr, 1))
{
inet_ntop(AF_INET, &iface->addr.in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
iface->warned = advice = 1;
my_syslog(LOG_WARNING,
_("LOUD WARNING: listening on %s may accept requests via interfaces other than %s"),
daemon->addrbuff, iface->name);
}
}
}
if (advice)
my_syslog(LOG_WARNING, _("LOUD WARNING: use --bind-dynamic rather than --bind-interfaces to avoid DNS amplification attacks via these interface(s)"));
}
void warn_int_names(void)
{
struct interface_name *intname;
for (intname = daemon->int_names; intname; intname = intname->next)
if (!intname->addr)
my_syslog(LOG_WARNING, _("warning: no addresses found for interface %s"), intname->intr);
}
int is_dad_listeners(void)
{
struct irec *iface;
@@ -745,7 +1074,7 @@ void join_multicast(int dienow)
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
if ((daemon->doing_dhcp6 || daemon->relay6) &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
@@ -962,87 +1291,206 @@ void pre_allocate_sfds(void)
}
}
void mark_servers(int flag)
{
struct server *serv;
/* mark everything with argument flag */
for (serv = daemon->servers; serv; serv = serv->next)
{
if (serv->flags & flag)
serv->flags |= SERV_MARK;
#ifdef HAVE_LOOP
/* Give looped servers another chance */
serv->flags &= ~SERV_LOOP;
#endif
}
}
void cleanup_servers(void)
{
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
server_gone(serv);
*up = serv->next;
if (serv->domain)
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
#ifdef HAVE_LOOP
/* Now we have a new set of servers, test for loops. */
loop_send_probes();
#endif
}
void add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
const char *interface,
const char *domain)
{
struct server *serv, *next = NULL;
char *domain_str = NULL;
/* See if there is a suitable candidate, and unmark */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_MARK)
{
if (domain)
{
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
continue;
}
else
{
if (serv->flags & SERV_HAS_DOMAIN)
continue;
}
break;
}
if (serv)
{
domain_str = serv->domain;
next = serv->next;
}
else if ((serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
if (domain && !(domain_str = whine_malloc(strlen(domain)+1)))
{
free(serv);
serv = NULL;
}
else
{
struct server *s;
/* Add to the end of the chain, for order */
if (!daemon->servers)
daemon->servers = serv;
else
{
for (s = daemon->servers; s->next; s = s->next);
s->next = serv;
}
if (domain)
strcpy(domain_str, domain);
}
}
if (serv)
{
memset(serv, 0, sizeof(struct server));
serv->flags = flags;
serv->domain = domain_str;
serv->next = next;
serv->queries = serv->failed_queries = 0;
serv->edns_pktsz = daemon->edns_pktsz;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (domain)
serv->flags |= SERV_HAS_DOMAIN;
if (interface)
strcpy(serv->interface, interface);
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
}
void check_servers(void)
{
struct irec *iface;
struct server *new, *tmp, *ret = NULL;
struct server *serv;
int port = 0;
/* interface may be new since startup */
if (!option_bool(OPT_NOWILD))
enumerate_interfaces();
enumerate_interfaces(0);
for (new = daemon->servers; new; new = tmp)
for (serv = daemon->servers; serv; serv = serv->next)
{
tmp = new->next;
if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
port = prettyprint_addr(&new->addr, daemon->namebuff);
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
if (new->addr.sa.sa_family == AF_INET &&
new->addr.in.sin_addr.s_addr == 0)
if (serv->addr.sa.sa_family == AF_INET &&
serv->addr.in.sin_addr.s_addr == 0)
{
free(new);
serv->flags |= SERV_MARK;
continue;
}
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&new->addr, &iface->addr))
if (sockaddr_isequal(&serv->addr, &iface->addr))
break;
if (iface)
{
my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
free(new);
serv->flags |= SERV_MARK;
continue;
}
/* Do we need a socket set? */
if (!new->sfd &&
!(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
if (!serv->sfd &&
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),
daemon->namebuff, strerror(errno));
free(new);
serv->flags |= SERV_MARK;
continue;
}
}
/* reverse order - gets it right. */
new->next = ret;
ret = new;
if (!(new->flags & SERV_NO_REBIND))
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
{
if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
{
char *s1, *s2;
if (!(new->flags & SERV_HAS_DOMAIN))
if (!(serv->flags & SERV_HAS_DOMAIN))
s1 = _("unqualified"), s2 = _("names");
else if (strlen(new->domain) == 0)
else if (strlen(serv->domain) == 0)
s1 = _("default"), s2 = "";
else
s1 = _("domain"), s2 = new->domain;
s1 = _("domain"), s2 = serv->domain;
if (new->flags & SERV_NO_ADDR)
if (serv->flags & SERV_NO_ADDR)
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
else if (new->flags & SERV_USE_RESOLV)
else if (serv->flags & SERV_USE_RESOLV)
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
else if (!(new->flags & SERV_LITERAL_ADDRESS))
else
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
}
else if (new->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
#ifdef HAVE_LOOP
else if (serv->flags & SERV_LOOP)
my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port);
#endif
else if (serv->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
else
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
}
}
daemon->servers = ret;
cleanup_servers();
}
/* Return zero if no servers found, in that case we keep polling.
@@ -1051,9 +1499,6 @@ int reload_servers(char *fname)
{
FILE *f;
char *line;
struct server *old_servers = NULL;
struct server *new_servers = NULL;
struct server *serv;
int gotone = 0;
/* buff happens to be MAXDNAME long... */
@@ -1062,28 +1507,9 @@ int reload_servers(char *fname)
my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
return 0;
}
/* move old servers to free list - we can reuse the memory
and not risk malloc if there are the same or fewer new servers.
Servers which were specced on the command line go to the new list. */
for (serv = daemon->servers; serv;)
{
struct server *tmp = serv->next;
if (serv->flags & SERV_FROM_RESOLV)
{
serv->next = old_servers;
old_servers = serv;
/* forward table rules reference servers, so have to blow them away */
server_gone(serv);
}
else
{
serv->next = new_servers;
new_servers = serv;
}
serv = tmp;
}
mark_servers(SERV_FROM_RESOLV);
while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
{
union mysockaddr addr, source_addr;
@@ -1142,64 +1568,41 @@ int reload_servers(char *fname)
continue;
#endif
if (old_servers)
{
serv = old_servers;
old_servers = old_servers->next;
}
else if (!(serv = whine_malloc(sizeof (struct server))))
continue;
/* this list is reverse ordered:
it gets reversed again in check_servers */
serv->next = new_servers;
new_servers = serv;
serv->addr = addr;
serv->source_addr = source_addr;
serv->domain = NULL;
serv->interface[0] = 0;
serv->sfd = NULL;
serv->flags = SERV_FROM_RESOLV;
serv->queries = serv->failed_queries = 0;
add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL);
gotone = 1;
}
/* Free any memory not used. */
while (old_servers)
{
struct server *tmp = old_servers->next;
free(old_servers);
old_servers = tmp;
}
daemon->servers = new_servers;
fclose(f);
cleanup_servers();
return gotone;
}
/* Use an IPv4 listener socket for ioctling */
struct in_addr get_ifaddr(char *intr)
/* Called when addresses are added or deleted from an interface */
void newaddress(time_t now)
{
struct listener *l;
struct ifreq ifr;
struct sockaddr_in ret;
(void)now;
ret.sin_addr.s_addr = -1;
for (l = daemon->listeners;
l && (l->family != AF_INET || l->fd == -1);
l = l->next);
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
enumerate_interfaces(0);
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
ifr.ifr_addr.sa_family = AF_INET;
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
join_multicast(0);
return ret.sin_addr;
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
{
void *p;
if ((p = expand(len)))
if ((p = expand(len)) && data)
memcpy(p, data, len);
return p;
}

125
src/poll.c Normal file
View File

@@ -0,0 +1,125 @@
/* dnsmasq is Copyright (c) 2000-2015 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"
/* Wrapper for poll(). Allocates and extends array of struct pollfds,
keeps them in fd order so that we can set and test conditions on
fd using a simple but efficient binary chop. */
/* poll_reset()
poll_listen(fd, event)
.
.
poll_listen(fd, event);
hits = do_poll(timeout);
if (poll_check(fd, event)
.
.
if (poll_check(fd, event)
.
.
event is OR of POLLIN, POLLOUT, POLLERR, etc
*/
static struct pollfd *pollfds = NULL;
static nfds_t nfds, arrsize = 0;
/* Binary search. Returns either the pollfd with fd, or
if the fd doesn't match, or return equals nfds, the entry
to the left of which a new record should be inserted. */
static nfds_t fd_search(int fd)
{
nfds_t left, right, mid;
if ((right = nfds) == 0)
return 0;
left = 0;
while (1)
{
if (right == left + 1)
return (pollfds[left].fd >= fd) ? left : right;
mid = (left + right)/2;
if (pollfds[mid].fd > fd)
right = mid;
else
left = mid;
}
}
void poll_reset(void)
{
nfds = 0;
}
int do_poll(int timeout)
{
return poll(pollfds, nfds, timeout);
}
int poll_check(int fd, short event)
{
nfds_t i = fd_search(fd);
if (i < nfds && pollfds[i].fd == fd)
return pollfds[i].revents & event;
return 0;
}
void poll_listen(int fd, short event)
{
nfds_t i = fd_search(fd);
if (i < nfds && pollfds[i].fd == fd)
pollfds[i].events |= event;
else
{
if (arrsize != nfds)
memmove(&pollfds[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
else
{
/* Array too small, extend. */
struct pollfd *new;
arrsize = (arrsize == 0) ? 64 : arrsize * 2;
if (!(new = whine_malloc(arrsize * sizeof(struct pollfd))))
return;
if (pollfds)
{
memcpy(new, pollfds, i * sizeof(struct pollfd));
memcpy(&new[i+1], &pollfds[i], (nfds - i) * sizeof(struct pollfd));
free(pollfds);
}
pollfds = new;
}
pollfds[i].fd = fd;
pollfds[i].events = event;
nfds++;
}
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -33,6 +33,13 @@ struct ra_packet {
u32 retrans_time;
};
struct neigh_packet {
u8 type, code;
u16 checksum;
u16 reserved;
struct in6_addr target;
};
struct prefix_opt {
u8 type, len, prefix_len, flags;
u32 valid_lifetime, preferred_lifetime, reserved;
@@ -42,6 +49,8 @@ struct prefix_opt {
#define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
#define ICMP6_OPT_ADV_INTERVAL 7
#define ICMP6_OPT_RT_INFO 24
#define ICMP6_OPT_RDNSS 25
#define ICMP6_OPT_DNSSL 31

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -28,18 +28,30 @@
struct ra_param {
time_t now;
int ind, managed, other, found_context, first;
int ind, managed, other, found_context, first, adv_router;
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local, link_global;
unsigned int pref_time;
struct in6_addr link_local, link_global, ula;
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval, prio;
};
struct search_param {
time_t now; int iface;
char name[IF_NAMESIZE+1];
};
struct alias_param {
int iface;
struct dhcp_bridge *bridge;
int num_alias_ifs;
int max_alias_ifs;
int *alias_ifs;
};
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest,
int send_iface);
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
@@ -47,6 +59,11 @@ static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now);
static unsigned int calc_lifetime(struct ra_interface *ra);
static unsigned int calc_interval(struct ra_interface *ra);
static unsigned int calc_prio(struct ra_interface *ra);
static struct ra_interface *find_iface_param(char *iface);
static int hop_limit;
@@ -69,10 +86,15 @@ void ra_init(time_t now)
if ((context->flags & CONTEXT_RA_NAME))
break;
/* Need ICMP6 socket for transmission for DHCPv6 even when not doing RA. */
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
if (context)
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
if (daemon->doing_ra)
{
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
if (context)
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
}
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
@@ -88,7 +110,8 @@ void ra_init(time_t now)
daemon->icmp6fd = fd;
ra_start_unsolicted(now, NULL);
if (daemon->doing_ra)
ra_start_unsolicted(now, NULL);
}
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
@@ -169,6 +192,7 @@ void icmp6_packet(time_t now)
else if (packet[0] == ND_ROUTER_SOLICIT)
{
char *mac = "";
struct dhcp_bridge *bridge, *alias;
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
@@ -177,46 +201,76 @@ void icmp6_packet(time_t now)
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
/* source address may not be valid in solicit request. */
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
/* If the incoming interface is an alias of some other one (as
specified by the --bridge-interface option), send an RA using
the context of the aliased interface. */
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
int bridge_index = if_nametoindex(bridge->iface);
if (bridge_index)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (wildcard_matchn(alias->iface, interface, IF_NAMESIZE))
{
/* Send an RA on if_index with information from
bridge_index. */
send_ra_alias(now, bridge_index, bridge->iface, NULL, if_index);
break;
}
if (alias)
break;
}
}
/* If the incoming interface wasn't an alias, send an RA using
the context of the incoming interface. */
if (!bridge)
/* source address may not be valid in solicit request. */
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
}
}
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_addr *dest, int send_iface)
{
struct ra_packet *ra;
struct ra_param parm;
struct ifreq ifr;
struct sockaddr_in6 addr;
struct dhcp_context *context;
struct dhcp_context *context, *tmp, **up;
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
int done_dns = 0;
struct ra_interface *ra_param = find_iface_param(iface_name);
int done_dns = 0, old_prefix = 0;
unsigned int min_pref_time;
#ifdef HAVE_LINUX_NETWORK
FILE *f;
#endif
parm.ind = iface;
parm.managed = 0;
parm.other = 0;
parm.found_context = 0;
parm.adv_router = 0;
parm.if_name = iface_name;
parm.first = 1;
parm.now = now;
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
parm.adv_interval = calc_interval(ra_param);
parm.prio = calc_prio(ra_param);
save_counter(0);
ra = expand(sizeof(struct ra_packet));
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0x00;
ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
ra->flags = parm.prio;
ra->lifetime = htons(calc_lifetime(ra_param));
ra->reachable_time = 0;
ra->retrans_time = 0;
parm.ind = iface;
parm.managed = 0;
parm.other = 0;
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
parm.now = now;
parm.pref_time = 0;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
@@ -228,11 +282,113 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
context->netid.next = &context->netid;
}
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
/* Find smallest preferred time within address classes,
to use as lifetime for options. This is a rather arbitrary choice. */
min_pref_time = 0xffffffff;
if (parm.glob_pref_time != 0 && parm.glob_pref_time < min_pref_time)
min_pref_time = parm.glob_pref_time;
if (parm.ula_pref_time != 0 && parm.ula_pref_time < min_pref_time)
min_pref_time = parm.ula_pref_time;
if (parm.link_pref_time != 0 && parm.link_pref_time < min_pref_time)
min_pref_time = parm.link_pref_time;
/* Look for constructed contexts associated with addresses which have gone,
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
{
unsigned int old = difftime(now, context->address_lost_time);
if (old > context->saved_valid)
{
/* We've advertised this enough, time to go */
*up = context->next;
free(context);
}
else
{
struct prefix_opt *opt;
struct in6_addr local = context->start6;
int do_slaac = 0;
old_prefix = 1;
/* zero net part of address */
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
if (context->flags & CONTEXT_RA)
{
do_slaac = 1;
if (context->flags & CONTEXT_DHCP)
{
parm.other = 1;
if (!(context->flags & CONTEXT_RA_STATELESS))
parm.managed = 1;
}
}
else
{
/* don't do RA for non-ra-only unless --enable-ra is set */
if (option_bool(OPT_RA))
{
parm.managed = 1;
parm.other = 1;
}
}
if ((opt = expand(sizeof(struct prefix_opt))))
{
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = context->prefix;
/* autonomous only if we're not doing dhcp, set
"on-link" unless "off-link" was specified */
opt->flags = (do_slaac ? 0x40 : 0) |
((context->flags & CONTEXT_RA_OFF_LINK) ? 0 : 0x80);
opt->valid_lifetime = htonl(context->saved_valid - old);
opt->preferred_lifetime = htonl(0);
opt->reserved = 0;
opt->prefix = local;
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
}
up = &context->next;
}
}
else
up = &context->next;
}
/* If we're advertising only old prefixes, set router lifetime to zero. */
if (old_prefix && !parm.found_context)
ra->lifetime = htons(0);
/* No prefixes to advertise. */
if (!old_prefix && !parm.found_context)
return;
/* If we're sending router address instead of prefix in at least on prefix,
include the advertisement interval option. */
if (parm.adv_router)
{
put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
put_opt6_char(1);
put_opt6_short(0);
/* interval value is in milliseconds */
put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
}
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
@@ -251,7 +407,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
}
#endif
iface_enumerate(AF_LOCAL, &iface, add_lla);
iface_enumerate(AF_LOCAL, &send_iface, add_lla);
/* RDNSS, RFC 6106, use relevant DHCP6 options */
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
@@ -266,22 +422,48 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
if (opt_cfg->opt == OPTION6_DNS_SERVER)
{
struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
struct in6_addr *a;
int len;
done_dns = 1;
if (opt_cfg->len == 0)
continue;
continue;
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char((opt_cfg->len/8) + 1);
put_opt6_short(0);
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
/* zero means "self" */
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
put_opt6(&parm.link_global, IN6ADDRSZ);
else
put_opt6(a, IN6ADDRSZ);
/* reduce len for any addresses we can't substitute */
for (a = (struct in6_addr *)opt_cfg->val, len = opt_cfg->len, i = 0;
i < opt_cfg->len; i += IN6ADDRSZ, a++)
if ((IN6_IS_ADDR_UNSPECIFIED(a) && parm.glob_pref_time == 0) ||
(IN6_IS_ADDR_ULA_ZERO(a) && parm.ula_pref_time == 0) ||
(IN6_IS_ADDR_LINK_LOCAL_ZERO(a) && parm.link_pref_time == 0))
len -= IN6ADDRSZ;
if (len != 0)
{
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char((len/8) + 1);
put_opt6_short(0);
put_opt6_long(min_pref_time);
for (a = (struct in6_addr *)opt_cfg->val, i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
{
if (parm.glob_pref_time != 0)
put_opt6(&parm.link_global, IN6ADDRSZ);
}
else if (IN6_IS_ADDR_ULA_ZERO(a))
{
if (parm.ula_pref_time != 0)
put_opt6(&parm.ula, IN6ADDRSZ);
}
else if (IN6_IS_ADDR_LINK_LOCAL_ZERO(a))
{
if (parm.link_pref_time != 0)
put_opt6(&parm.link_local, IN6ADDRSZ);
}
else
put_opt6(a, IN6ADDRSZ);
}
}
if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
@@ -291,7 +473,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
put_opt6_char(ICMP6_OPT_DNSSL);
put_opt6_char(len + 1);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6_long(min_pref_time);
put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */
@@ -300,14 +482,14 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
}
}
if (daemon->port == NAMESERVER_PORT && !done_dns)
if (daemon->port == NAMESERVER_PORT && !done_dns && parm.link_pref_time != 0)
{
/* default == us, as long as we are supplying DNS service. */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_global, IN6ADDRSZ);
put_opt6_long(min_pref_time);
put_opt6(&parm.link_local, IN6ADDRSZ);
}
/* set managed bits unless we're providing only RA on this link */
@@ -331,13 +513,24 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
addr.sin6_scope_id = iface;
}
else
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
{
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
}
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
save_counter(0), 0, (struct sockaddr *)&addr,
sizeof(addr))));
}
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
{
/* Send an RA on the same interface that the RA content is based
on. */
send_ra_alias(now, iface, iface_name, dest, iface);
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam)
@@ -349,25 +542,37 @@ static int add_prefixes(struct in6_addr *local, int prefix,
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
{
/* Can there be more than one LL address?
Select the one with the longest preferred time
if there is. */
if (preferred > param->link_pref_time)
{
param->link_pref_time = preferred;
param->link_local = *local;
}
}
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
int do_prefix = 0;
int real_prefix = 0;
int do_slaac = 0;
int deprecate = 0;
int constructed = 0;
int adv_router = 0;
int off_link = 0;
unsigned int time = 0xffffffff;
struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
context->saved_valid = valid;
if (context->flags & CONTEXT_RA)
{
do_slaac = 1;
if (context->flags & CONTEXT_DHCP)
@@ -385,13 +590,23 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->managed = 1;
param->other = 1;
}
/* find floor time, don't reduce below RA interval. */
/* Configured to advertise router address, not prefix. See RFC 3775 7.2
In this case we do all addresses associated with a context,
hence the real_prefix setting here. */
if (context->flags & CONTEXT_RA_ROUTER)
{
adv_router = 1;
param->adv_router = 1;
real_prefix = context->prefix;
}
/* find floor time, don't reduce below 3 * RA interval. */
if (time > context->lease_time)
{
time = context->lease_time;
if (time < ((unsigned int)RA_INTERVAL))
time = RA_INTERVAL;
if (time < ((unsigned int)(3 * param->adv_interval)))
time = 3 * param->adv_interval;
}
if (context->flags & CONTEXT_DEPRECATE)
@@ -411,13 +626,14 @@ static int add_prefixes(struct in6_addr *local, int prefix,
/* subsequent prefixes on the same interface
and subsequent instances of this prefix don't need timers.
Be careful not to find the same prefix twice with different
addresses. */
addresses unless we're advertising the actual addresses. */
if (!(context->flags & CONTEXT_RA_DONE))
{
if (!param->first)
context->ra_time = 0;
context->flags |= CONTEXT_RA_DONE;
do_prefix = 1;
real_prefix = context->prefix;
off_link = (context->flags & CONTEXT_RA_OFF_LINK);
}
param->first = 0;
@@ -437,34 +653,52 @@ static int add_prefixes(struct in6_addr *local, int prefix,
/* configured time is ceiling */
if (!constructed || preferred > time)
preferred = time;
if (preferred > param->pref_time)
if (IN6_IS_ADDR_ULA(local))
{
param->pref_time = preferred;
param->link_global = *local;
if (preferred > param->ula_pref_time)
{
param->ula_pref_time = preferred;
param->ula = *local;
}
}
else
{
if (preferred > param->glob_pref_time)
{
param->glob_pref_time = preferred;
param->link_global = *local;
}
}
if (do_prefix)
if (real_prefix != 0)
{
struct prefix_opt *opt;
if ((opt = expand(sizeof(struct prefix_opt))))
{
/* zero net part of address */
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
if (!adv_router)
setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
opt->prefix_len = real_prefix;
/* autonomous only if we're not doing dhcp, set
"on-link" unless "off-link" was specified */
opt->flags = (off_link ? 0 : 0x80);
if (do_slaac)
opt->flags |= 0x40;
if (adv_router)
opt->flags |= 0x20;
opt->valid_lifetime = htonl(valid);
opt->preferred_lifetime = htonl(preferred);
opt->reserved = 0;
opt->prefix = *local;
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
@@ -498,8 +732,8 @@ time_t periodic_ra(time_t now)
struct search_param param;
struct dhcp_context *context;
time_t next_event;
char interface[IF_NAMESIZE+1];
struct alias_param aparam;
param.now = now;
param.iface = 0;
@@ -520,28 +754,110 @@ time_t periodic_ra(time_t now)
if (!context)
break;
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
if (iface_enumerate(AF_INET6, &param, iface_search))
if ((context->flags & CONTEXT_OLD) &&
context->if_index != 0 &&
indextoname(daemon->icmp6fd, context->if_index, param.name))
{
/* A context for an old address. We'll not find the interface by
looking for addresses, but we know it anyway, since the context is
constructed */
param.iface = context->if_index;
new_timeout(context, param.name, now);
}
else if (iface_enumerate(AF_INET6, &param, iface_search))
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
context->ra_time = 0;
else if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface, NULL))
if (param.iface != 0 &&
iface_check(AF_LOCAL, NULL, param.name, NULL))
{
struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, interface))
if (tmp->name && wildcard_match(tmp->name, param.name))
break;
if (!tmp)
send_ra(now, param.iface, interface, NULL);
{
send_ra(now, param.iface, param.name, NULL);
/* Also send on all interfaces that are aliases of this
one. */
for (aparam.bridge = daemon->bridges;
aparam.bridge;
aparam.bridge = aparam.bridge->next)
if ((int)if_nametoindex(aparam.bridge->iface) == param.iface)
{
/* Count the number of alias interfaces for this
'bridge', by calling iface_enumerate with
send_ra_to_aliases and NULL alias_ifs. */
aparam.iface = param.iface;
aparam.alias_ifs = NULL;
aparam.num_alias_ifs = 0;
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => %d alias(es)",
param.name, daemon->addrbuff, aparam.num_alias_ifs);
/* Allocate memory to store the alias interface
indices. */
aparam.alias_ifs = (int *)whine_malloc(aparam.num_alias_ifs *
sizeof(int));
if (aparam.alias_ifs)
{
/* Use iface_enumerate again to get the alias
interface indices, then send on each of
those. */
aparam.max_alias_ifs = aparam.num_alias_ifs;
aparam.num_alias_ifs = 0;
iface_enumerate(AF_LOCAL, &aparam, send_ra_to_aliases);
for (; aparam.num_alias_ifs; aparam.num_alias_ifs--)
{
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s => i/f %d",
param.name, daemon->addrbuff,
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
send_ra_alias(now,
param.iface,
param.name,
NULL,
aparam.alias_ifs[aparam.num_alias_ifs - 1]);
}
free(aparam.alias_ifs);
}
/* The source interface can only appear in at most
one --bridge-interface. */
break;
}
}
}
}
return next_event;
}
static int send_ra_to_aliases(int index, unsigned int type, char *mac, size_t maclen, void *parm)
{
struct alias_param *aparam = (struct alias_param *)parm;
char ifrn_name[IFNAMSIZ];
struct dhcp_bridge *alias;
(void)type;
(void)mac;
(void)maclen;
if (if_indextoname(index, ifrn_name))
for (alias = aparam->bridge->alias; alias; alias = alias->next)
if (wildcard_matchn(alias->iface, ifrn_name, IFNAMSIZ))
{
if (aparam->alias_ifs && (aparam->num_alias_ifs < aparam->max_alias_ifs))
aparam->alias_ifs[aparam->num_alias_ifs] = index;
aparam->num_alias_ifs++;
}
return 1;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
@@ -554,10 +870,10 @@ static int iface_search(struct in6_addr *local, int prefix,
(void)valid;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix) &&
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix) &&
context->ra_time != 0 &&
difftime(context->ra_time, param->now) <= 0.0)
{
@@ -568,19 +884,21 @@ static int iface_search(struct in6_addr *local, int prefix,
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
/* should never fail */
if (!indextoname(daemon->icmp6fd, if_index, param->name))
{
param->iface = 0;
return 0;
}
new_timeout(context, param->name, param->now);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (prefix <= context->prefix &&
is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
context->ra_time = 0;
return 0; /* found, abort */
@@ -588,6 +906,71 @@ static int iface_search(struct in6_addr *local, int prefix,
return 1; /* keep searching */
}
static void new_timeout(struct dhcp_context *context, char *iface_name, time_t now)
{
if (difftime(now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = now + 5 + (rand16()/4400);
else
{
/* range 3/4 - 1 times MaxRtrAdvInterval */
unsigned int adv_interval = calc_interval(find_iface_param(iface_name));
context->ra_time = now + (3 * adv_interval)/4 + ((adv_interval * (unsigned int)rand16()) >> 18);
}
}
static struct ra_interface *find_iface_param(char *iface)
{
struct ra_interface *ra;
for (ra = daemon->ra_interfaces; ra; ra = ra->next)
if (wildcard_match(ra->name, iface))
return ra;
return NULL;
}
static unsigned int calc_interval(struct ra_interface *ra)
{
int interval = 600;
if (ra && ra->interval != 0)
{
interval = ra->interval;
if (interval > 1800)
interval = 1800;
else if (interval < 4)
interval = 4;
}
return (unsigned int)interval;
}
static unsigned int calc_lifetime(struct ra_interface *ra)
{
int lifetime, interval = (int)calc_interval(ra);
if (!ra || ra->lifetime == -1) /* not specified */
lifetime = 3 * interval;
else
{
lifetime = ra->lifetime;
if (lifetime < interval && lifetime != 0)
lifetime = interval;
else if (lifetime > 9000)
lifetime = 9000;
}
return (unsigned int)lifetime;
}
static unsigned int calc_prio(struct ra_interface *ra)
{
if (ra)
return ra->prio;
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -34,7 +34,7 @@ static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
static struct in_addr option_addr(unsigned char *opt);
static unsigned int option_uint(unsigned char *opt, int i, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, 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_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
@@ -52,7 +52,9 @@ static void do_options(struct dhcp_context *context,
int null_term, int pxearch,
unsigned char *uuid,
int vendor_class_len,
time_t now);
time_t now,
unsigned int lease_time,
unsigned short fuzz);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
@@ -92,7 +94,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
struct dhcp_netid known_id, iface_id, cpewan_id;
struct dhcp_opt *o;
unsigned char pxe_uuid[17];
unsigned char *oui = NULL, *serial = NULL, *class = NULL;
unsigned char *oui = NULL, *serial = NULL;
#ifdef HAVE_SCRIPT
unsigned char *class = NULL;
#endif
subnet_addr.s_addr = override.s_addr = 0;
@@ -156,8 +161,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
unsigned char *y = option_ptr(opt, offset + elen + 5);
oui = option_find1(x, y, 1, 1);
serial = option_find1(x, y, 2, 1);
class = option_find1(x, y, 3, 1);
#ifdef HAVE_SCRIPT
class = option_find1(x, y, 3, 1);
#endif
/* If TR069-id is present set the tag "cpewan-id" to facilitate echoing
the gateway id back. Note that the device class is optional */
if (oui && serial)
@@ -606,16 +612,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
}
}
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, 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);
}
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
{
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
int len = option_len(opt);
@@ -645,7 +651,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
while (*op != 0 && ((op + (*op)) - pp) < len)
{
memcpy(pq, op+1, *op);
pq += *op;
@@ -799,9 +805,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (service->type == type)
break;
if (!service || !service->basename)
return 0;
for (; context; context = context->current)
if (match_netid(context->filter, tagif_netid, 1) &&
is_same_net(mess->ciaddr, context->start, context->netmask))
break;
if (!service || !service->basename || !context)
return 0;
clear_packet(mess, end);
mess->yiaddr = mess->ciaddr;
@@ -827,7 +838,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
opt71.next = daemon->dhcp_opts;
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, NULL, mess->xid);
log_tags(tagif_netid, ntohl(mess->xid));
return dhcp_packet_size(mess, agent_id, real_end);
}
@@ -848,8 +859,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (tmp)
{
struct dhcp_boot *boot = find_boot(tagif_netid);
struct dhcp_boot *boot;
if (tmp->netid.net)
{
tmp->netid.next = netid;
tagif_netid = run_tag_if(&tmp->netid);
}
boot = find_boot(tagif_netid);
mess->yiaddr.s_addr = 0;
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
{
@@ -874,12 +893,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->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);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", 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));
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
@@ -911,7 +930,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)))
return 0;
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, 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)
lease_prune(lease, now);
@@ -943,13 +962,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
message = _("unknown lease");
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
return 0;
case DHCPDISCOVER:
if (ignore || have_config(config, CONFIG_DISABLE))
{
if (option_bool(OPT_QUIET_DHCP))
return 0;
message = _("ignored");
opt = NULL;
}
@@ -1007,7 +1028,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
message = _("no address available");
}
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, 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)))
return 0;
@@ -1020,7 +1041,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, 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));
clear_packet(mess, end);
@@ -1028,13 +1049,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (time != 0xffffffff)
{
option_put(mess, end, OPTION_T1, 4, (time/2));
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1072,7 +1088,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
Have to set override to make sure we echo back the correct server-id */
struct irec *intr;
enumerate_interfaces();
enumerate_interfaces(0);
for (intr = daemon->interfaces; intr; intr = intr->next)
if (intr->addr.sa.sa_family == AF_INET &&
@@ -1136,7 +1152,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->yiaddr = mess->ciaddr;
}
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
if (!message)
{
@@ -1208,7 +1224,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (message)
{
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, message, mess->xid);
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
mess->yiaddr.s_addr = 0;
clear_packet(mess, end);
@@ -1347,21 +1363,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
override = lease->override;
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, mess->xid);
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
clear_packet(mess, end);
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_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
while (fuzz > (time/16))
fuzz = fuzz/2;
option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
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);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
}
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1370,7 +1379,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (ignore || have_config(config, CONFIG_DISABLE))
message = _("ignored");
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, mess->xid);
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
if (message || mess->ciaddr.s_addr == 0)
return 0;
@@ -1385,8 +1394,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease->hostname)
hostname = lease->hostname;
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
domain = get_domain(mess->ciaddr);
if (!hostname)
hostname = host_from_dns(mess->ciaddr);
if (context && context->netid.net)
{
@@ -1396,7 +1405,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
if (lease)
{
@@ -1426,7 +1435,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1530,10 +1539,13 @@ static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
#endif
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid)
int mac_len, char *interface, char *string, char *err, u32 xid)
{
struct in_addr a;
if (!err && !option_bool(OPT_LOG_OPTS) && option_bool(OPT_QUIET_DHCP))
return;
/* addr may be misaligned */
if (addr)
memcpy(&a, addr, sizeof(a));
@@ -1541,22 +1553,24 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
print_mac(daemon->namebuff, ext_mac, mac_len);
if(option_bool(OPT_LOG_OPTS))
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
ntohl(xid),
type,
interface,
addr ? inet_ntoa(a) : "",
addr ? " " : "",
daemon->namebuff,
string ? string : "");
string ? string : "",
err ? err : "");
else
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s",
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
type,
interface,
addr ? inet_ntoa(a) : "",
addr ? " " : "",
daemon->namebuff,
string ? string : "");
string ? string : "",
err ? err : "");
}
static void log_options(unsigned char *start, u32 xid)
@@ -1833,7 +1847,8 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *c
}
}
else
memcpy(p, opt->val, len);
/* empty string may be extended to "\0" by null_term */
memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
}
return len;
}
@@ -2117,7 +2132,9 @@ static void do_options(struct dhcp_context *context,
int null_term, int pxe_arch,
unsigned char *uuid,
int vendor_class_len,
time_t now)
time_t now,
unsigned int lease_time,
unsigned short fuzz)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot;
@@ -2241,7 +2258,42 @@ static void do_options(struct dhcp_context *context,
/* rfc3011 says this doesn't need to be in the requested options list. */
if (subnet_addr.s_addr)
option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
if (lease_time != 0xffffffff)
{
unsigned int t1val = lease_time/2;
unsigned int t2val = (lease_time*7)/8;
unsigned int hval;
/* If set by user, sanity check, so not longer than lease. */
if ((opt = option_find2(OPTION_T1)))
{
hval = ntohl(*((unsigned int *)opt->val));
if (hval < lease_time && hval > 2)
t1val = hval;
}
if ((opt = option_find2(OPTION_T2)))
{
hval = ntohl(*((unsigned int *)opt->val));
if (hval < lease_time && hval > 2)
t2val = hval;
}
/* ensure T1 is still < T2 */
if (t2val <= t1val)
t1val = t2val - 1;
while (fuzz > (t1val/8))
fuzz = fuzz/2;
t1val -= fuzz;
t2val -= fuzz;
option_put(mess, end, OPTION_T1, 4, t1val);
option_put(mess, end, OPTION_T2, 4, t2val);
}
/* replies to DHCPINFORM may not have a valid context */
if (context)
{
@@ -2289,7 +2341,9 @@ static void do_options(struct dhcp_context *context,
if (domain)
len += strlen(domain) + 1;
else if (fqdn_flags & 0x04)
len--;
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
{
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
@@ -2300,8 +2354,10 @@ static void do_options(struct dhcp_context *context,
{
p = do_rfc1035_name(p, hostname);
if (domain)
p = do_rfc1035_name(p, domain);
*p++ = 0;
{
p = do_rfc1035_name(p, domain);
*p++ = 0;
}
}
else
{
@@ -2332,12 +2388,14 @@ static void do_options(struct dhcp_context *context,
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
continue;
/* prohibit some used-internally options */
/* prohibit some used-internally options. T1 and T2 already handled. */
if (optno == OPTION_CLIENT_FQDN ||
optno == OPTION_MAXMESSAGE ||
optno == OPTION_OVERLOAD ||
optno == OPTION_PAD ||
optno == OPTION_END)
optno == OPTION_END ||
optno == OPTION_T1 ||
optno == OPTION_T2)
continue;
if (optno == OPTION_SNAME && done_server)

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
lease->slaac_address = NULL;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
if ((context->flags & CONTEXT_RA_NAME) &&
!(context->flags & CONTEXT_OLD) &&
lease->last_interface == context->if_index)
{
struct in6_addr addr = context->start6;
if (lease->hwaddr_len == 6 &&
@@ -91,7 +93,6 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
slaac->ping_time = now;
slaac->backoff = 1;
slaac->addr = addr;
slaac->local = context->local6;
/* Do RA's to prod it */
ra_start_unsolicted(now, context);
}
@@ -123,7 +124,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
time_t next_event = 0;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
break;
/* nothing configured */
@@ -198,7 +199,8 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
slaac->backoff = 0;
gotone = 1;
inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
if (!option_bool(OPT_QUIET_DHCP6))
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
}
lease_update_dns(gotone);

173
src/tables.c Normal file
View File

@@ -0,0 +1,173 @@
/* tables.c is Copyright (c) 2014 Sven Falempin All Rights Reserved.
Author's email: sfalempin@citypassenger.com
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"
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
#ifndef __FreeBSD__
#include <string.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/pfvar.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#define UNUSED(x) (void)(x)
static char *pf_device = "/dev/pf";
static int dev = -1;
static char *pfr_strerror(int errnum)
{
switch (errnum)
{
case ESRCH:
return "Table does not exist";
case ENOENT:
return "Anchor or Ruleset does not exist";
default:
return strerror(errnum);
}
}
static int pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags)
{
struct pfioc_table io;
if (size < 0 || (size && tbl == NULL))
{
errno = EINVAL;
return (-1);
}
bzero(&io, sizeof io);
io.pfrio_flags = flags;
io.pfrio_buffer = tbl;
io.pfrio_esize = sizeof(*tbl);
io.pfrio_size = size;
if (ioctl(dev, DIOCRADDTABLES, &io))
return (-1);
if (nadd != NULL)
*nadd = io.pfrio_nadd;
return (0);
}
static int fill_addr(const struct all_addr *ipaddr, int flags, struct pfr_addr* addr) {
if ( !addr || !ipaddr)
{
my_syslog(LOG_ERR, _("error: fill_addr missused"));
return -1;
}
bzero(addr, sizeof(*addr));
#ifdef HAVE_IPV6
if (flags & F_IPV6)
{
addr->pfra_af = AF_INET6;
addr->pfra_net = 0x80;
memcpy(&(addr->pfra_ip6addr), &(ipaddr->addr), sizeof(struct in6_addr));
}
else
#endif
{
addr->pfra_af = AF_INET;
addr->pfra_net = 0x20;
addr->pfra_ip4addr.s_addr = ipaddr->addr.addr4.s_addr;
}
return 1;
}
/*****************************************************************************/
void ipset_init(void)
{
dev = open( pf_device, O_RDWR);
if (dev == -1)
{
err(1, "%s", pf_device);
die (_("failed to access pf devices: %s"), NULL, EC_MISC);
}
}
int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
int flags, int remove)
{
struct pfr_addr addr;
struct pfioc_table io;
struct pfr_table table;
int n = 0, rc = 0;
if ( dev == -1 )
{
my_syslog(LOG_ERR, _("warning: no opened pf devices %s"), pf_device);
return -1;
}
bzero(&table, sizeof(struct pfr_table));
table.pfrt_flags |= PFR_TFLAG_PERSIST;
if ( strlen(setname) >= PF_TABLE_NAME_SIZE )
{
my_syslog(LOG_ERR, _("error: cannot use table name %s"), setname);
errno = ENAMETOOLONG;
return -1;
}
if ( strlcpy(table.pfrt_name, setname,
sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name))
{
my_syslog(LOG_ERR, _("error: cannot strlcpy table name %s"), setname);
return -1;
}
if ((rc = pfr_add_tables(&table, 1, &n, 0)))
{
my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"),
pfr_strerror(errno),rc);
return -1;
}
table.pfrt_flags &= ~PFR_TFLAG_PERSIST;
if (n)
my_syslog(LOG_INFO, _("info: table created"));
fill_addr(ipaddr,flags,&addr);
bzero(&io, sizeof(io));
io.pfrio_flags = 0;
io.pfrio_table = table;
io.pfrio_buffer = &addr;
io.pfrio_esize = sizeof(addr);
io.pfrio_size = 1;
if (ioctl(dev, ( remove ? DIOCRDELADDRS : DIOCRADDADDRS ), &io))
{
my_syslog(LOG_WARNING, _("warning: DIOCR%sADDRS: %s"), ( remove ? "DEL" : "ADD" ), pfr_strerror(errno));
return -1;
}
my_syslog(LOG_INFO, _("%d addresses %s"),
io.pfrio_nadd, ( remove ? "removed" : "added" ));
return io.pfrio_nadd;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -49,9 +49,7 @@ void tftp_request(struct listener *listen, time_t now)
struct iovec iov;
struct ifreq ifr;
int is_err = 1, if_index = 0, mtu = 0;
#ifdef HAVE_DHCP
struct iname *tmp;
#endif
struct tftp_transfer *transfer;
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
@@ -62,7 +60,12 @@ void tftp_request(struct listener *listen, time_t now)
char *prefix = daemon->tftp_prefix;
struct tftp_prefix *pref;
struct all_addr addra;
#ifdef HAVE_IPV6
/* Can always get recvd interface for IPv6 */
int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
#else
int check_dest = !option_bool(OPT_NOWILD);
#endif
union {
struct cmsghdr align; /* this ensures alignment */
#ifdef HAVE_IPV6
@@ -93,8 +96,9 @@ void tftp_request(struct listener *listen, time_t now)
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
return;
if (option_bool(OPT_NOWILD))
/* Can always get recvd interface for IPv6 */
if (!check_dest)
{
if (listen->iface)
{
@@ -198,27 +202,41 @@ void tftp_request(struct listener *listen, time_t now)
addra.addr.addr6 = addr.in6.sin6_addr;
#endif
if (!iface_check(listen->family, &addra, name, NULL))
if (daemon->tftp_interfaces)
{
if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces();
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
!label_exception(if_index, listen->family, &addra) )
/* dedicated tftp interface list */
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
break;
if (!tmp)
return;
}
else
{
/* Do the same as DHCP */
if (!iface_check(listen->family, &addra, name, NULL))
{
if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces(0);
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
!label_exception(if_index, listen->family, &addra) )
return;
}
#ifdef HAVE_DHCP
/* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
return;
/* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
return;
#endif
}
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
}
if (name)
{
/* check for per-interface prefix */
@@ -484,7 +502,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
return NULL;
}
void check_tftp_listeners(fd_set *rset, time_t now)
void check_tftp_listeners(time_t now)
{
struct tftp_transfer *transfer, *tmp, **up;
ssize_t len;
@@ -500,7 +518,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
prettyprint_addr(&transfer->peer, daemon->addrbuff);
if (FD_ISSET(transfer->sockfd, rset))
if (poll_check(transfer->sockfd, POLLIN))
{
/* we overwrote the buffer... */
daemon->srv_save = NULL;
@@ -555,7 +573,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
}
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
else if (++transfer->backoff > 5 && len != 0)
else if (++transfer->backoff > 7 && len != 0)
{
endcon = 1;
len = 0;

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2015 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
@@ -28,24 +28,12 @@
#include <idna.h>
#endif
#ifdef HAVE_ARC4RANDOM
void rand_init(void)
{
return;
}
unsigned short rand16(void)
{
return (unsigned short) (arc4random() >> 15);
}
#else
/* SURF random number generator */
static u32 seed[32];
static u32 in[12];
static u32 out[8];
static int outleft = 0;
void rand_init()
{
@@ -83,18 +71,43 @@ static void surf(void)
unsigned short rand16(void)
{
static int outleft = 0;
if (!outleft) {
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
if (!outleft)
{
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
return (unsigned short) out[--outleft];
}
#endif
u32 rand32(void)
{
if (!outleft)
{
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
return out[--outleft];
}
u64 rand64(void)
{
static int outleft = 0;
if (outleft < 2)
{
if (!++in[0]) if (!++in[1]) if (!++in[2]) ++in[3];
surf();
outleft = 8;
}
outleft -= 2;
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
}
static int check_name(char *in)
{
@@ -108,10 +121,10 @@ static int check_name(char *in)
if (in[l-1] == '.')
{
if (l == 1) return 0;
in[l-1] = 0;
nowhite = 1;
}
for (; (c = *in); in++)
{
if (c == '.')
@@ -151,14 +164,13 @@ int legal_hostname(char *name)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9'))
continue;
if (!first &&
((c >= '0' && c <= '9') ||
c == '-' || c == '_'))
if (!first && (c == '-' || c == '_'))
continue;
/* end of hostname part */
if (c == '.')
return 1;
@@ -214,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
{
unsigned char *cp = p++;
for (j = 0; *sval && (*sval != '.'); sval++, j++)
*p++ = *sval;
{
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
*p++ = (*(++sval))-1;
else
#endif
*p++ = *sval;
}
*cp = j;
if (*sval)
sval++;
@@ -262,6 +281,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
#ifdef HAVE_IPV6
if (s1->sa.sa_family == AF_INET6 &&
s1->in6.sin6_port == s2->in6.sin6_port &&
s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
return 1;
#endif
@@ -319,6 +339,19 @@ time_t dnsmasq_time(void)
#endif
}
int netmask_length(struct in_addr mask)
{
int zero_count = 0;
while (0x0 == (mask.s_addr & 0x1) && zero_count < 32)
{
mask.s_addr >>= 1;
zero_count++;
}
return 32 - zero_count;
}
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
{
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
@@ -458,7 +491,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
int j, bytes = (1 + (r - in))/2;
for (j = 0; j < bytes; j++)
{
char sav;
char sav = sav;
if (j < bytes - 1)
{
sav = in[(j+1)*2];
@@ -537,27 +570,41 @@ char *print_mac(char *buff, unsigned char *mac, int len)
return buff;
}
void bump_maxfd(int fd, int *max)
/* rc is return from sendto and friends.
Return 1 if we should retry.
Set errno to zero if we succeeded. */
int retry_send(ssize_t rc)
{
if (fd > *max)
*max = fd;
}
static int retries = 0;
struct timespec waiter;
if (rc != -1)
{
retries = 0;
errno = 0;
return 0;
}
/* Linux kernels can return EAGAIN in perpetuity when calling
sendmsg() and the relevant interface has gone. Here we loop
retrying in EAGAIN for 1 second max, to avoid this hanging
dnsmasq. */
int retry_send(void)
{
struct timespec waiter;
if (errno == EAGAIN || errno == EWOULDBLOCK)
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
waiter.tv_sec = 0;
waiter.tv_nsec = 10000;
nanosleep(&waiter, NULL);
return 1;
if (retries++ < 1000)
return 1;
}
if (errno == EINTR)
return 1;
return 0;
retries = 0;
if (errno == EINTR)
return 1;
return 0;
}
int read_write(int fd, unsigned char *packet, int size, int rw)
@@ -566,22 +613,21 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
for (done = 0; done < size; done += n)
{
retry:
if (rw)
n = read(fd, &packet[done], (size_t)(size - done));
else
n = write(fd, &packet[done], (size_t)(size - done));
do {
if (rw)
n = read(fd, &packet[done], (size_t)(size - done));
else
n = write(fd, &packet[done], (size_t)(size - done));
if (n == 0)
return 0;
} while (retry_send(n) || errno == ENOMEM || errno == ENOBUFS);
if (n == 0)
return 0;
else if (n == -1)
{
if (retry_send() || errno == ENOMEM || errno == ENOBUFS)
goto retry;
else
return 0;
}
if (errno != 0)
return 0;
}
return 1;
}
@@ -602,3 +648,22 @@ int wildcard_match(const char* wildcard, const char* match)
return *wildcard == *match;
}
/* The same but comparing a maximum of NUM characters, like strncmp. */
int wildcard_matchn(const char* wildcard, const char* match, int num)
{
while (*wildcard && *match && num)
{
if (*wildcard == '*')
return 1;
if (*wildcard != *match)
return 0;
++wildcard;
++match;
--num;
}
return (!num) || (*wildcard == *match);
}

9
trust-anchors.conf Normal file
View File

@@ -0,0 +1,9 @@
# The root DNSSEC trust anchor, valid as at 30/01/2014
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5