Compare commits

...

701 Commits

Author SHA1 Message Date
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
Simon Kelley
3f2873d42c Handle IPv4 interface-address labels in Linux. 2013-05-14 11:28:47 +01:00
Simon Kelley
ab915f837c Only use ourselves as default DNS server for RA if we're doing DNS.
This makes RA the same as DHCP4/6
2013-04-30 10:43:09 +01:00
Simon Kelley
ddd9a6b499 replace inet_addr with inet_pton() in src/option.c 2013-04-29 17:00:21 +01:00
Simon Kelley
7abb69b5dc Tighten checks in legal_hostname(). 2013-04-29 10:52:16 +01:00
Simon Kelley
d5052fb24f Fix FTBFS in ipset.c with old kernel headers. 2013-04-25 12:44:20 +01:00
Simon Kelley
b5a7ff42bb Check length of synth-domain prefix. 2013-04-25 11:03:47 +01:00
Simon Kelley
48fd1c4dd6 Allow option prefix in --synth-domain. 2013-04-25 09:49:38 +01:00
Simon Kelley
2bb73af7d1 Add --synth-domain 2013-04-24 20:35:43 +01:00
Simon Kelley
86e92f9983 --dhcp-match et al now work with BOOTP as well as DHCP. 2013-04-23 11:31:39 +01:00
Simon Kelley
1c10b9de11 Note that dhcp_lease_time and dhcp_release only work for IPv4. 2013-04-23 10:58:35 +01:00
Tomas Hozza
a66d36ea11 Manpage typos. 2013-04-22 15:08:07 +01:00
Simon Kelley
aa63a21ce0 Fix regression in dhcp_lease_time utility. 2013-04-22 15:01:52 +01:00
Giacomo Tazzari
797a7afba4 Fix crash on SERVFAIL when --conntrack in use. 2013-04-22 13:16:37 +01:00
Simon Kelley
4b5ea12e90 Send TCP DNS messages in one write() call. Stops TCP stream fragmenting.
This is an optimisation, not a bugfix. Thanks to Jim Bos for spotting it.
2013-04-22 10:22:55 +01:00
Simon Kelley
2b6390fdc9 Bump Debian version number. 2013-04-19 10:23:50 +01:00
Simon Kelley
bd08ae67f9 Allow option number zero in encapsulated DHCP options. 2013-04-19 10:22:06 +01:00
Dave Reisner
4582c0efe7 Fix wrong size in memset() call.
Thanks to Dave Reisner.
2013-04-18 21:02:41 +01:00
Simon Kelley
834f36fe6d Update French translation. 2013-04-17 13:52:49 +01:00
Simon Kelley
6f130def07 Manpage typos.
Thanks to Gildas Le Nadan.
2013-04-15 14:58:56 +01:00
Simon Kelley
3931a7bd85 FAQ typos.
Thanks to Moritz Warning.
2013-04-15 14:31:52 +01:00
Simon Kelley
d9ee9c0872 Better error check on options parsing. 2013-04-12 11:17:55 +01:00
Simon Kelley
0b0a73c1c9 Fix crash on exceeding DHCP lease limit. 2013-04-11 14:07:02 +01:00
Simon Kelley
81925ab73a Manpage typos 2013-04-10 11:43:58 +01:00
Simon Kelley
9de1aa9b7f Fix parsing of IAID>MAXINT in leases file.
Thanks to Christof Meerwald for the bug report.
2013-04-10 11:17:12 +01:00
Simon Kelley
6f9aaa93e9 ->hwaddr_len must be zero always in DHCPv6 leases. 2013-04-10 10:25:26 +01:00
Simon Kelley
7e5664bdbc Fix trivial access of un-initialised memory.
Thanks to sven falpin for finding this.
2013-04-09 22:28:04 +01:00
Simon Kelley
83f28bef6c Manpage typos. 2013-04-03 14:46:46 +01:00
Simon Kelley
96c727fda6 Cope with duplicate dhcp-options with tags (last one wins). 2013-04-02 21:35:41 +01:00
Simon Kelley
49dc570a72 Manpage typo. 2013-04-02 20:27:07 +01:00
Simon Kelley
cd1e04a234 Polish translation. 2013-04-02 20:11:48 +01:00
Simon Kelley
27cb314e54 Fix endless loop when dhcp-range goes away. 2013-04-02 20:06:39 +01:00
Simon Kelley
56a1142f03 SO_REUSEPORT may be defined, but not supported. 2013-04-02 17:02:58 +01:00
Simon Kelley
5b37aa8c19 Trivial change: 0->NULL for pointer constant. 2013-04-02 16:32:25 +01:00
Simon Kelley
8ac9787350 Fix lease time calculation when using DHCPv6 relay. 2013-03-30 21:34:19 +00:00
Simon Kelley
9f9bd08af8 Merged messages. 2013-03-22 15:11:53 +00:00
Simon Kelley
4c985dac39 Indentation. 2013-03-22 14:07:38 +00:00
Simon Kelley
3d77c0460d Typos in CHANGELOG 2013-03-22 10:03:50 +00:00
Simon Kelley
3ddad24608 Compile-in IPSET by default. 2013-03-21 17:56:06 +00:00
Simon Kelley
6e37ab595c Send prefix-class in DHCPREPLY as well as DHCPADVERTISE. 2013-03-19 20:50:11 +00:00
Simon Kelley
a1a79edaea Bugfix for latest DHCPv6 update. 2013-03-15 21:19:57 +00:00
Simon Kelley
49333cbdbe Allow trailing '*' wildcard in interface names. 2013-03-15 20:30:51 +00:00
Simon Kelley
de92b479d9 Make wildcard-configured addresses work on multiple networks. 2013-03-15 18:26:23 +00:00
Simon Kelley
0f128eb58c Clarifications for DNS-auth in man-page. 2013-03-11 21:21:35 +00:00
Simon Kelley
c630924d66 Experimental support for DHCPv6 prefix-class option. 2013-03-07 20:59:28 +00:00
Simon Kelley
ff59fc82b3 Split out context-marking from add_address. 2013-03-07 11:00:26 +00:00
Simon Kelley
52a1ae72f0 Another logic problem in refactor. 2013-03-06 22:43:26 +00:00
Simon Kelley
3a654c506f Respect difference between no IA_{TN}A and no IA_ADDR options. 2013-03-06 22:17:48 +00:00
Simon Kelley
2763d4b51a Fix unused variable warning. 2013-03-06 21:24:56 +00:00
Simon Kelley
e28836bf45 Fix crash in DHCPv6 renew, introduced in refactor. 2013-03-06 21:22:22 +00:00
Simon Kelley
a6ebfacf7b Massive refactor of stateful DHCPv6. Lease multiple prefixes per client. 2013-03-06 20:54:27 +00:00
Simon Kelley
c7961075c4 Don't erroneously reject some option names in --dhcp-match 2013-02-28 15:17:58 +00:00
Simon Kelley
ab6ede7e04 Handle EINTR return from sendto() in ipset.c 2013-02-23 19:22:37 +00:00
Simon Kelley
b3538f1100 Add ipset.c to source files list in Android makefile. 2013-02-22 21:56:22 +00:00
Simon Kelley
3b323bda58 IPset support in debian build. 2013-02-22 21:55:29 +00:00
Jason A. Donenfeld
13d86c7372 Add --ipset option. 2013-02-22 21:44:08 +00:00
Simon Kelley
208fb610a6 Fix wrong DNSMASQ_LEASE_EXPIRES envar when luascript in use also. 2013-02-21 22:26:18 +00:00
Simon Kelley
4038ae2005 Fix crash in DHCPv6 information-request handler. 2013-02-19 16:47:07 +00:00
Simon Kelley
dd1721c799 DHCPv4 relay-agent options exposed to DHCP-script. 2013-02-18 21:04:04 +00:00
Simon Kelley
a21e27bc99 Support DHCP DNS server option if we're not doing DNS. 2013-02-17 16:41:35 +00:00
Simon Kelley
b0ff858e78 Fix FTBFS if HAVE_BROKEN_RTC defined. 2013-02-06 09:57:47 +00:00
Simon Kelley
54dae552b1 Fix previous commit. 2013-02-05 17:55:10 +00:00
Simon Kelley
25c4198f7c Fix use-after-free 2013-02-05 14:56:02 +00:00
Simon Kelley
4ead40cf67 Fix use-after-free 2013-02-05 14:51:14 +00:00
Simon Kelley
04a0612e8a Remove dead code. 2013-02-05 14:47:46 +00:00
Simon Kelley
aa608c84b4 Fix wrong syntax check. 2013-02-05 14:42:59 +00:00
Simon Kelley
38365ff040 Theoretical memory leak fix. 2013-02-05 14:35:54 +00:00
Simon Kelley
9c4270bcd9 Fix memory leak. 2013-02-04 22:07:57 +00:00
Simon Kelley
46b066565e Don't leak sockets when getsockname fails. 2013-02-04 21:47:59 +00:00
Simon Kelley
4dc9c657ad Memory leak. 2013-02-04 21:43:52 +00:00
Simon Kelley
39595cfe31 Fix memory leak. 2013-02-04 21:40:07 +00:00
Simon Kelley
ffa3d7d6a2 Copy-and-paste error 2013-02-04 21:35:43 +00:00
Simon Kelley
aa67fe7a8c Catch NULL pointer deref if qdcount == 0 2013-02-04 21:32:34 +00:00
Simon Kelley
bb2509fd2c Typo in filter_constructed_dhcp() 2013-02-04 21:25:21 +00:00
Simon Kelley
61744359de Change copyright messages to include 2013. 2013-01-31 14:34:40 +00:00
Simon Kelley
095f62551f Update manpage for --dhcp-authoritative DHCPv6 behaviour. 2013-01-30 11:31:02 +00:00
Simon Kelley
e25db1f273 Handle wrong interface for locally-routed packets. 2013-01-29 22:10:26 +00:00
Simon Kelley
79cb46c0e9 Man page typos. 2013-01-23 19:49:21 +00:00
Simon Kelley
22ce550e53 Correct behaviour for TCP queries to allowed address via banned interface. 2013-01-22 13:53:04 +00:00
Simon Kelley
30393100c1 Wildcard IPv6 addresses in --dhcp-host, for constructed ranges. 2013-01-17 16:34:16 +00:00
Simon Kelley
459380965a Fix last commit. 2013-01-15 21:57:42 +00:00
Simon Kelley
21bac1bccd Check IAID as well as CLID for lease identity. 2013-01-14 21:35:05 +00:00
Simon Kelley
b1a1b6def5 Tweak DHCP startup logging. 2013-01-11 16:28:50 +00:00
Simon Kelley
baeb3adf21 More IPv6 address allocation fixes. 2013-01-10 11:47:38 +00:00
Simon Kelley
39f6a04ca4 Better fix for interfaces without broadcast address on *BSD. 2013-01-09 19:57:47 +00:00
Simon Kelley
37c9ccebd1 DHCPv6 address allocation - same DUID, two IAIDs 2013-01-09 19:51:04 +00:00
Simon Kelley
71c73ac17c Fix crash on startup on Solaris 11 2013-01-08 21:22:24 +00:00
Simon Kelley
c6cb7407b3 Don't do AXFR unless auth-sec-servers is set. 2013-01-07 21:55:54 +00:00
Simon Kelley
333b2ceb97 Documentation updates for auth-DNS and constructed dhcp ranges. 2013-01-07 21:46:03 +00:00
Simon Kelley
b456b9fdfe Linked-list bug in new "use longest prefixes first" code. 2013-01-02 17:59:28 +00:00
Simon Kelley
34d0a36a1d Man page updates 2013-01-02 11:40:56 +00:00
Simon Kelley
355736f36f Fix auth-DNS filtering problems with contructed ranges. 2012-12-30 17:54:04 +00:00
Simon Kelley
771287be11 Wildcards in dhcp-range constructors 2012-12-30 17:38:09 +00:00
Simon Kelley
dc9476b670 Use RA_INTERVAL for lifetimes. 2012-12-29 22:08:26 +00:00
Simon Kelley
1e14cc0f48 Make it legal to have no subnet in --auth-zone, may be contructed instead. 2012-12-29 17:27:59 +00:00
Simon Kelley
55b548ae2b Add RA_INTERVAL parameter in config.h 2012-12-29 17:13:04 +00:00
Simon Kelley
3b43646a08 Use /proc/sys/net/ipv6/conf/<iface>/mtu for RA advertised MTU. 2012-12-28 11:55:45 +00:00
Simon Kelley
3bc0d932d0 More work on lease and router lifetime calculation. 2012-12-28 11:31:44 +00:00
Simon Kelley
60225f4e75 Allow constructed prefixes in auth zones. 2012-12-28 11:29:01 +00:00
Simon Kelley
1962446269 Join multicast groups only on IPv6 addresses! 2012-12-28 11:18:09 +00:00
Simon Kelley
be37986a0f Better error checking in DHCPv6 dhcp-range option parsing. 2012-12-23 12:01:39 +00:00
Simon Kelley
d7346a1e8c Tweak context-construct logic. 2012-12-22 22:45:54 +00:00
Simon Kelley
87d346f6a7 saner function name 2012-12-22 22:35:11 +00:00
Simon Kelley
f0dd7f807d Fix new-address logic and ordering for first address on new interface. 2012-12-22 22:31:58 +00:00
Simon Kelley
0c0502426f Check for new SLAAC addresses when we add new prefixes. 2012-12-22 22:13:19 +00:00
Simon Kelley
7f035f58c6 Don't cap prefx lifetimes below RA retransmit interval. 2012-12-22 21:27:08 +00:00
Simon Kelley
81e84f8dac preferred and valid times in bpf.c 2012-12-21 20:54:00 +00:00
Simon Kelley
55b42f6de3 Default to global, not link-local address in RA DNS field. 2012-12-21 16:53:15 +00:00
Simon Kelley
ed8b68ad06 Simplify and fix RA lifetime calculation. 2012-12-21 16:23:26 +00:00
Simon Kelley
bad7b875eb add general flag param to iface_enumerate IPv6 callback 2012-12-20 22:00:39 +00:00
Simon Kelley
5d162f20a9 Rationalise join_multicast() 2012-12-20 14:55:46 +00:00
Simon Kelley
9d29949440 typo 2012-12-18 21:48:15 +00:00
Simon Kelley
1b75c1e61f Per-context control over ra short period. 2012-12-18 19:55:25 +00:00
Simon Kelley
293fd0f700 Missed interface re-read path in netlink.c 2012-12-18 18:31:11 +00:00
Simon Kelley
c1be917782 DHCP context logging, more tweaks 2012-12-18 18:31:11 +00:00
Simon Kelley
bb86e858b6 Error dhcp constructors on platforms where no interface detection. 2012-12-18 18:31:11 +00:00
Simon Kelley
8445f5d2e2 Fix initialisation order. 2012-12-18 18:31:11 +00:00
Simon Kelley
72c9c3b11b complicated DHCP context logging. 2012-12-18 18:31:11 +00:00
Simon Kelley
6e3dba3fde Ignore template contexts where appropriate. 2012-12-18 18:31:11 +00:00
Simon Kelley
7558ecd9ac Fix periodic loop 2012-12-18 18:31:11 +00:00
Simon Kelley
1f776932a1 First checkin of interface-address constructor mode for DHCPv6 and RA. 2012-12-18 18:31:11 +00:00
Simon Kelley
4820dce97a Make authoritative stuff a compile-time option. 2012-12-18 18:30:30 +00:00
Simon Kelley
f8abe0c566 Fix crash in auth code for queries where class != C_IN 2012-12-15 11:59:25 +00:00
Simon Kelley
9def963c65 Bump debian version. 2012-12-14 11:58:56 +00:00
Simon Kelley
990123a937 Fix regexp foobar. 2012-12-14 11:56:15 +00:00
Simon Kelley
1d6c639310 Fix broken cache. 2012-12-14 11:19:36 +00:00
Simon Kelley
429798fd08 Allow addresses as well as interface names in --auth-server. 2012-12-10 20:45:53 +00:00
Simon Kelley
b5a8dd1dec Fix FTBFS with NO_DHCP. 2012-12-10 11:37:25 +00:00
Simon Kelley
95a0bd3701 Add .gitignore file. 2012-12-10 11:29:03 +00:00
Simon Kelley
8ff556739e SOA serial tweak. 2012-12-09 21:09:01 +00:00
Simon Kelley
496787677e Zone-transfer peer restriction option. 2012-12-09 18:31:10 +00:00
Simon Kelley
e1ff419cf9 Complete AXFR support 2012-12-09 17:08:47 +00:00
Simon Kelley
ee86ce68fc Fix TCP query forwarding to non-default servers. 2012-12-07 11:54:46 +00:00
Simon Kelley
b75e936372 First cut at zone transfer. 2012-12-07 11:50:41 +00:00
Simon Kelley
aa79235194 zero arcount. 2012-12-06 19:41:35 +00:00
Simon Kelley
7c305be1bd Bump Debian version. 2012-12-04 20:59:06 +00:00
Simon Kelley
f7fe362721 Tidy merge. 2012-12-04 20:55:54 +00:00
Simon Kelley
36bec089f7 Merge branch 'auth' 2012-12-04 20:50:38 +00:00
Simon Kelley
45dd1fece4 Correct NS and SOA records in auth mode for PTR queries. 2012-12-04 20:49:24 +00:00
Simon Kelley
29d28dda95 Don't send RAs to the wrong place when DAD in progress. 2012-12-03 14:05:59 +00:00
Simon Kelley
421594f83d Forgot --dhcp-except check in previous commit. 2012-12-02 12:17:35 +00:00
Simon Kelley
d89fb4ed4f Check interface for router advertisements. 2012-12-01 21:21:13 +00:00
Simon Kelley
295a54eed3 SetDomainServers Dbus method. 2012-12-01 21:02:15 +00:00
Simon Kelley
5c0bd5b112 CNAME auth support. 2012-12-01 16:42:47 +00:00
Simon Kelley
86e3b9a026 Post-test fixes. 2012-11-30 13:46:48 +00:00
Simon Kelley
2f38141f43 Don't elide code needed for --bind-dynamic if compiled without IPv6. 2012-11-29 21:16:44 +00:00
Simon Kelley
8273ea5a19 Add MX support. 2012-11-29 21:12:33 +00:00
Simon Kelley
4f7b304f53 Initial code to do authoritative DNS. 2012-11-28 21:27:02 +00:00
Simon Kelley
8e4b87918f Header-file dependency checking in Makefile. 2012-11-14 14:12:56 +00:00
Simon Kelley
83b2198e86 Add warning to man page, -d option 2012-11-12 21:07:44 +00:00
Simon Kelley
d1a5975f9b No lease-time in DHCPINFORM replies. 2012-11-05 16:50:30 +00:00
Simon Kelley
52002051ad Doc update for previous checkin. 2012-10-26 11:39:02 +01:00
Simon Kelley
b191a77901 trivial indent fix. 2012-10-24 14:16:00 +01:00
Simon Kelley
23780dd577 Set tag "dhcpv6" rather than "DHCPv6", hardwired tags in lower-case is consistent. 2012-10-23 17:04:37 +01:00
Simon Kelley
d1e9a582ad Use dhcp-range tags when replying to DHCPv6 information-request. 2012-10-23 17:00:57 +01:00
Simon Kelley
819ff4dd0f Wildcard IPv6 dhcp-range. 2012-10-21 18:25:12 +01:00
Simon Kelley
de604c18a0 Remove non-7-bit character from CHANGELOG 2012-10-19 09:50:01 +01:00
Simon Kelley
be6cfb42ab Fix DHCPv6 to do access control correctly when it's configured with --listen-address. 2012-10-16 20:38:31 +01:00
Simon Kelley
2022310f95 SO_REUSEADDR and SO_V6ONLY options on DHCPv6 socket. 2012-10-15 10:41:17 +01:00
Simon Kelley
657ed09693 Add contrib/dbus-test/dbus-test.py 2012-10-12 14:45:55 +01:00
Simon Kelley
c99df938d7 Fix compilation warnings. 2012-10-12 13:39:04 +01:00
Simon Kelley
cf568a3726 Fix typos in sample config file. 2012-10-09 20:51:31 +01:00
Simon Kelley
e4807d8bb2 Fix breakage of --host-record parsing. 2012-09-27 21:52:26 +01:00
Simon Kelley
35239a302a Tweak dhcp-config sanity checking. 2012-09-24 15:09:33 +01:00
Simon Kelley
db3946c358 Debian changelog update. 2012-09-21 17:21:05 +01:00
Simon Kelley
0d28af84d0 Set tag "DHCPv6" for v6 transactions. 2012-09-20 21:24:06 +01:00
Simon Kelley
42698cb7ab Log ignored DHCPv6 information-requests. 2012-09-20 21:19:35 +01:00
Simon Kelley
1d860415f2 Add --max-cache-ttl option. 2012-09-20 20:48:04 +01:00
Simon Kelley
289a253569 Fix build with later Lua libraries. 2012-09-20 15:29:35 +01:00
Simon Kelley
faafb3f7b7 Add SetServersEX method in DBus interface. 2012-09-20 14:17:39 +01:00
Simon Kelley
2b127a1eab Flag DHCP or DHCPv6 in starup logging. 2012-09-18 21:51:22 +01:00
Simon Kelley
dfb23b3f77 Don't report spurious netlink errors. 2012-09-18 21:44:47 +01:00
Simon Kelley
b269221c00 Address allocation tweaking - lease outside dhcp-range but in subnet. 2012-09-16 22:22:23 +01:00
Simon Kelley
8b46061e73 Fix DHCPv6 address allocation for some pathalogical cases. 2012-09-08 21:47:28 +01:00
Simon Kelley
4d0f5b4c44 Fix BOOTP option processing. 2012-09-05 23:29:30 +01:00
Simon Kelley
1dedeb87cc Fix Debian package adduser dependency. 2012-09-04 21:50:52 +01:00
Simon Kelley
79cfefd856 Make pid-file creation immune to symlink attack. 2012-09-02 13:29:51 +01:00
Simon Kelley
0c0d4793ac Tidy buffer use in DHCP startup logging. 2012-09-02 12:57:43 +01:00
Simon Kelley
12d71ed28c Finesse the check for /etc/hosts names which conflict with DHCP names. 2012-08-30 15:16:41 +01:00
Simon Kelley
9fed0f71c2 Further tweaks to DHCP FQDN option. 2012-08-30 11:43:35 +01:00
Simon Kelley
2e34ac1403 Handle DHCP FQDN option with all flags zero and --dhcp-client-update 2012-08-29 14:15:25 +01:00
Simon Kelley
bc54ae392b Debian packaging fixes. 2012-08-28 21:26:56 +01:00
Simon Kelley
00acd06340 Tweak get-version to do the right thing with multiple head tags. 2012-08-17 14:18:50 +01:00
Simon Kelley
476e4a03c1 Bump Debian version 2012-08-17 13:45:49 +01:00
Simon Kelley
5f11b3e5e0 Cope with --listen-address for not yet existent addr in bind-dynamic mode. 2012-08-16 14:04:05 +01:00
Simon Kelley
3169daad46 Fix TFTP access control, broken earlier in release. 2012-08-13 17:39:57 +01:00
Simon Kelley
fd05f12790 Set prefix on-link bit in RAs 2012-08-12 17:48:50 +01:00
Simon Kelley
ad094275b0 Alternate DBus service name via --enable-dbus 2012-08-10 17:10:54 +01:00
Simon Kelley
c740e4f342 Fix FTBFS when -DNO_DHCP - thanks Sung Pae. 2012-08-09 16:19:01 +01:00
Simon Kelley
132255b5da OpenBSD build fix. 2012-08-06 20:12:04 +01:00
Simon Kelley
c4c0488ac6 Update french translation. 2012-08-06 20:09:15 +01:00
Simon Kelley
a2ce6fcc91 Man page typos 2012-08-06 20:05:48 +01:00
Simon Kelley
12090548d2 Add debian/dnsmasq-base.conffiles 2012-08-06 20:00:58 +01:00
Simon Kelley
8223cb15e7 Update FAQ to cover --bind-dynamic. 2012-07-29 20:21:57 +01:00
Simon Kelley
4ba9b38cc5 Debian package: move /etc/dbus-1/system.d/dnsmasq.conf. 2012-07-29 17:07:48 +01:00
Simon Kelley
42243214b5 "w" multiplier in lease times. 2012-07-20 15:19:18 +01:00
Simon Kelley
23245c0cb2 RFC 4242 support. 2012-07-18 16:21:11 +01:00
Simon Kelley
b271446f82 Typo. 2012-07-17 12:09:26 +01:00
Simon Kelley
611ebc5f1e Fix broken caching of CNAME chains. 2012-07-16 16:23:46 +01:00
Simon Kelley
be0f45cdbc Typo fix. Thanks Wieland Hoffmann. 2012-07-16 13:35:25 +01:00
Simon Kelley
9b40cbf587 Fix FTBFS when TFTP disabled. 2012-07-13 19:58:26 +01:00
Simon Kelley
c4a7f90ebb Config parsing error-handling update. 2012-07-12 20:52:12 +01:00
Simon Kelley
9609baee41 Merge branch 'access_control' 2012-07-10 15:06:34 +01:00
Simon Kelley
395eb71931 Better log message when dhcp hosts|opts file cannot be read. 2012-07-06 22:07:05 +01:00
Simon Kelley
8bc4cecee6 Remove libvirt-inspired but never used access control features. 2012-07-03 21:04:11 +01:00
Simon Kelley
6b617c0d15 Logging library in Android build scaffold. 2012-06-29 22:11:26 +01:00
Simon Kelley
55d290a3bf Handle pid-file location in Android. 2012-06-29 20:58:32 +01:00
Simon Kelley
e17b4b3871 Fix build-failure with -DNO_DHCP6. 2012-06-28 21:44:30 +01:00
Simon Kelley
236e072cab Typo in BSD-only code. 2012-06-26 21:33:01 +01:00
Simon Kelley
05ff1ed7cc Man page update. 2012-06-26 16:58:12 +01:00
Simon Kelley
2b5bae9a8f Fall back from --bind-dynamic to --bind-interfaces in BSD, rather than quitting. 2012-06-26 16:55:23 +01:00
Simon Kelley
39f1b8e73d Better logging of socket-creation errors. 2012-06-20 20:04:27 +01:00
Simon Kelley
af576b56c2 Tidy up - no functional change. 2012-06-20 14:17:04 +01:00
Simon Kelley
54dd393f39 Add --bind-dynamic 2012-06-20 11:23:38 +01:00
Simon Kelley
4ce4f3779b Fix un-initialised "used" field in --listen-address structure.
Also remove unused "isloop" field.
2012-06-14 11:50:45 +01:00
Simon Kelley
8b3ae2fd43 Check tftp-root exists and is accessible at startup. 2012-06-13 13:43:49 +01:00
Simon Kelley
ed55cb66e6 Correct listener logic when no TFTP and no-interface listen address. 2012-06-12 21:56:29 +01:00
Simon Kelley
2cd9a0de1f Debian systemd startup fixes for resolvconf integration. 2012-06-11 21:56:10 +01:00
Simon Kelley
c514ab9907 Update Debian changelog. 2012-06-07 15:35:08 +01:00
Simon Kelley
078a630bba Do duplicate dhcp-host address check in --test mode. 2012-06-07 13:56:23 +01:00
Simon Kelley
43c271b07c Debian package build - pass calculated LDFLAGS to make. 2012-06-07 10:02:53 +01:00
Simon Kelley
24ce681e51 Add instructions/patches for dbus activation to contrib/systemd. 2012-06-04 21:40:11 +01:00
Simon Kelley
5ae34bf3c8 Fix RA when interface has more than one address on the same network. 2012-06-04 21:14:03 +01:00
Simon Kelley
51931b888a Fix access control when DHCPv6 but no RA in use. 2012-05-29 17:06:02 +01:00
Simon Kelley
9f7f3b1216 Add --dns-rr option. 2012-05-28 21:39:57 +01:00
Simon Kelley
97c83bb05b Use dpkg-buildflags in Debian rules file. 2012-05-28 18:21:59 +01:00
Simon Kelley
8767ceecd4 Make libvirt-style access control work when only doing RA. 2012-05-21 20:54:19 +01:00
Simon Kelley
18c63eff8f Fix non-response to router-solicitations when
router-advertisement configured, but DHCPv6 not
configured.
2012-05-21 14:34:15 +01:00
Simon Kelley
c64b7f6a78 Fix is_same_net6 - bugged if prefix length not divisible by 8. 2012-05-18 10:19:59 +01:00
Simon Kelley
068b4b51e3 Bump Debian version. 2012-05-12 15:25:33 +01:00
Simon Kelley
919dd7cf14 Fixed missing periodic-ras in some configurations. 2012-05-12 15:23:09 +01:00
Simon Kelley
f632e56793 Cope with router-solicit packets without valid source address. 2012-05-12 15:05:34 +01:00
Simon Kelley
2021c66251 code-size tweak 2012-05-07 16:43:21 +01:00
Simon Kelley
8358e0f4b2 Update German translation and fix CHANGELOG typos. Sorry, Conrad! 2012-04-29 21:53:09 +01:00
Simon Kelley
7f61b3ad59 Small SLAAC optimisation. 2012-04-29 16:01:28 +01:00
Simon Kelley
a9ab732e35 reconfirm SLAAC addresses when DHCPv4 leases go though INIT_REBOOT state. 2012-04-29 16:01:28 +01:00
Simon Kelley
11263a462c isprint cast. 2012-04-29 16:01:28 +01:00
Simon Kelley
231d061b45 Tidy TXT record sanitising 2012-04-29 16:01:28 +01:00
Simon Kelley
cdbee9a40b Find room to store key-id and digest-type in DS records.
->uid is now overloaded to store key length
2012-04-27 10:30:49 +01:00
Simon Kelley
7b4ad2eb34 Teach cache to store DS and DNSKEY records 2012-04-27 10:30:49 +01:00
Simon Kelley
19d69be220 CHANGELOG update. 2012-04-27 10:14:34 +01:00
Simon Kelley
04363607aa Fix tftp-over-IPv4 regression on OpenBSD. 2012-04-27 10:11:51 +01:00
Simon Kelley
dcffad2a86 Ensure that the DBus DhcpLeaseUpdated events are generated. 2012-04-24 15:25:18 +01:00
Simon Kelley
6a69ab5ebd Fix error-handling problem in TFTP server. 2012-04-24 14:42:26 +01:00
Simon Kelley
fc92ead0dd CHANGELOG typo. 2012-04-22 21:28:24 +01:00
Simon Kelley
61ce600b20 --tftp-lowercase option. 2012-04-20 21:28:49 +01:00
Simon Kelley
7a14dfebbb Tidy previous commit. 2012-04-20 20:50:42 +01:00
Simon Kelley
42fb8153ba Sanitise filenames logged by TFTP 2012-04-20 17:15:01 +01:00
Simon Kelley
6f13e53886 Tidy up malloc-failure handling. 2012-04-17 14:25:06 +01:00
Simon Kelley
d1c759c5c1 Answer CNAME queries correctly. 2012-04-16 17:26:19 +01:00
Simon Kelley
e46164e0bd Updated French translation. 2012-04-16 16:39:38 +01:00
Simon Kelley
7389ce7ff5 substitue non-portable tail command with sed. 2012-04-16 15:07:48 +01:00
Simon Kelley
2f77797b17 Add port option to example dnsmasq.conf 2012-04-16 14:58:53 +01:00
Simon Kelley
9380ba70d6 Set SO_BINDTODEVICE on DHCP sockets when doing DHCP on one interface
only. Fixes OpenSTack use-case.
2012-04-16 14:41:56 +01:00
Simon Kelley
1023dcbc9e Don't cache DNS data from non-recursive nameservers. 2012-04-09 18:00:08 +01:00
Simon Kelley
83e854e359 Typo. 2012-04-05 13:21:58 +01:00
Simon Kelley
50303b19d8 Remove redundant send_from logging code. 2012-04-04 22:13:17 +01:00
Simon Kelley
89382bacaa Tweak sending ICMP6 echo requests for slaac. 2012-04-04 20:48:16 +01:00
Simon Kelley
6c559c34df tweak favicon 2012-04-02 20:40:34 +01:00
Simon Kelley
adaa6888dd Move FIXME message to comment - having it emitted by the code is just confusing. 2012-04-02 10:02:12 +01:00
Simon Kelley
a813111379 Fix bug in tag-matching logic with negated tags. 2012-03-31 21:35:12 +01:00
Simon Kelley
18f0fb050b RDNSS and DNSSL data in router advertisements. 2012-03-31 21:18:55 +01:00
Simon Kelley
05e92e5afe More RA flag evolution. 2012-03-30 22:24:15 +01:00
Simon Kelley
4723d49dad Set managed RA flag always when doing DHCP. 2012-03-30 21:04:17 +01:00
Simon Kelley
fbbc14541a Fix off-by-one in DHCPv6 FQDN option decoding. 2012-03-30 20:48:20 +01:00
Simon Kelley
5ef33279f2 Tidying radv 2012-03-30 15:10:28 +01:00
Simon Kelley
1e02a85970 radv.c tidying. 2012-03-29 11:07:25 +01:00
Simon Kelley
0e88d53faa Fix preprocessor checks, IP_TOS -> IPV6_TCLASS 2012-03-28 22:22:05 +01:00
Simon Kelley
01d1b8ddf2 Changelog update. 2012-03-28 21:37:25 +01:00
Simon Kelley
c8257540bc "deprecated" lease-time keyword for IPv6 2012-03-28 21:15:41 +01:00
Simon Kelley
2240704863 DHCP start-up logging tweak 2012-03-27 14:42:48 +01:00
Simon Kelley
e8ca69ea16 Doc updates for latest RA changes. 2012-03-26 21:23:26 +01:00
Simon Kelley
da632e7cc1 Comment typo. 2012-03-26 11:14:05 +01:00
Simon Kelley
30cd96663f More flexible RA configuration. 2012-03-25 20:44:38 +01:00
Simon Kelley
7dbe98147d tweak ra timer code to avoid missing events. 2012-03-25 14:49:54 +01:00
Simon Kelley
5d71d83420 Listen on ICMP6 file decriptor even when on ra-only only in use. 2012-03-24 14:40:42 +00:00
Simon Kelley
38a59a9ff7 debian changelog untangle. 2012-03-23 10:08:12 +00:00
Simon Kelley
4b028ad612 Merge branch 'bind' 2012-03-23 10:02:30 +00:00
Simon Kelley
442560beb4 Debian changelog for preivious fix. 2012-03-23 10:01:13 +00:00
Simon Kelley
7d2b5c9583 Fix crash in DHCPINFORM without valid --dhcp-range. 2012-03-23 10:00:02 +00:00
Simon Kelley
29689cfa5a Handle errors when sending ICMP6 pings better. 2012-03-22 14:01:00 +00:00
Simon Kelley
52d4abf2f9 Make --listen-address work for all 127.0.0.0/8 addresses. 2012-03-21 21:39:48 +00:00
84 changed files with 25018 additions and 9821 deletions

14
.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
src/*.o
src/*.mo
src/dnsmasq.pot
src/dnsmasq
src/dnsmasq_baseline
src/.configured
contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release
debian/base/
debian/daemon/
debian/files
debian/substvars
debian/utils-substvars
debian/utils/

661
CHANGELOG
View File

@@ -1,18 +1,609 @@
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.
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
this and supplying the patch.
Repair regression in 2.64. That release stopped sending
lease-time information in the reply to DHCPINFORM
requests, on the correct grounds that it was a standards
violation. However, this broke the dnsmasq-specific
dhcp_lease_time utility. Now, DHCPINFORM returns
lease-time only if it's specifically requested
(maintaining standards) and the dhcp_lease_time utility
has been taught to ask for it (restoring functionality).
Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
to work with BOOTP and well as DHCP. Thanks to Peter
Korsgaard for spotting the problem.
Add --synth-domain. Thanks to Vishvananda Ishaya for
suggesting this.
Fix failure to compile ipset.c if old kernel headers are
in use. Thanks to Eugene Rudoy for pointing this out.
Handle IPv4 interface-address labels in Linux. These are
often used to emulate the old IP-alias addresses. Before,
using --interface=eth0 would service all the addresses of
eth0, including ones configured as aliases, which appear
in ifconfig as eth0:0. Now, only addresses with the label
eth0 are active. This is not backwards compatible: if you
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
with local data, as long as the correct NS records are set
up. Only local data is provided, to avoid creating an open
DNS relay. Zone transfer is supported, to allow secondary
servers to be configured.
Add "constructed DHCP ranges" for DHCPv6. This is intended
for IPv6 routers which get prefixes dynamically via prefix
delegation. With suitable configuration, stateful DHCPv6
and RA can happen automatically as prefixes are delegated
and then deprecated, without having to re-write the
dnsmasq configuration file or restart the daemon. Thanks to
Steven Barth for extensive testing and development work on
this idea.
Fix crash on startup on Solaris 11. Regression probably
introduced in 2.61. Thanks to Geoff Johnstone for the
patch.
Add code to make behaviour for TCP DNS requests that same
as for UDP requests, when a request arrives for an allowed
address, but via a banned interface. This change is only
active on Linux, since the relevant API is missing (AFAIK)
on other platforms. Many thanks to Tomas Hozza for
spotting the problem, and doing invaluable discovery of
the obscure and undocumented API required for the solution.
Don't send the default DHCP option advertising dnsmasq as
the local DNS server if dnsmasq is configured to not act
as DNS server, or it's configured to a non-standard port.
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
DNSMASQ_REMOTE_ID variables to the environment of the
lease-change script (and the corresponding Lua). These hold
information inserted into the DHCP request by a DHCP relay
agent. Thanks to Lakefield Communications for providing a
bounty for this addition.
Fixed crash, introduced in 2.64, whilst handling DHCPv6
information-requests with some common configurations.
Thanks to Robert M. Albrecht for the bug report and
chasing the problem.
Add --ipset option. Thanks to Jason A. Donenfeld for the
patch.
Don't erroneously reject some option names in --dhcp-match
options. Thanks to Benedikt Hochstrasser for the bug report.
Allow a trailing '*' wildcard in all interface-name
configurations. Thanks to Christian Parpart for the patch.
Handle the situation where libc headers define
SO_REUSEPORT, but the kernel in use doesn't, to cope with
the introduction of this option to Linux. Thanks to Rich
Felker for the bug report.
Update Polish translation. Thanks to Jan Psota.
Fix crash if the configured DHCP lease limit is
reached. Regression occurred in 2.61. Thanks to Tsachi for
the bug report.
Update the French translation. Thanks to Gildas le Nadan.
version 2.65
Fix regression which broke forwarding of queries sent via
TCP which are not for A and AAAA and which were directed to
non-default servers. Thanks to Niax for the bug report.
Fix failure to build with DHCP support excluded. Thanks to
Gustavo Zacarias for the patch.
Fix nasty regression in 2.64 which completely broke cacheing.
version 2.64
Handle DHCP FQDN options with all flag bits zero and
--dhcp-client-update set. Thanks to Bernd Krumbroeck for
spotting the problem.
Finesse the check for /etc/hosts names which conflict with
DHCP names. Previously a name/address pair in /etc/hosts
which didn't match the name/address of a DHCP lease would
generate a warning. Now that only happesn if there is not
also a match. This allows multiple addresses for a name in
/etc/hosts with one of them assigned via DHCP.
Fix broken vendor-option processing for BOOTP. Thanks to
Hans-Joachim Baader for the bug report.
Don't report spurious netlink errors, regression in
2.63. Thanks to Vladislav Grishenko for the patch.
Flag DHCP or DHCPv6 in starup logging. Thanks to
Vladislav Grishenko for the patch.
Add SetServersEx method in DBus interface. Thanks to Dan
Williams for the patch.
Add SetDomainServers method in DBus interface. Thanks to
Roy Marples for the patch.
Fix build with later Lua libraries. Thansk to Cristian
Rodriguez for the patch.
Add --max-cache-ttl option. Thanks to Dennis Kaarsemaker
for the patch.
Fix breakage of --host-record parsing, resulting in
infinte loop at startup. Regression in 2.63. Thanks to
Haim Gelfenbeyn for spotting this.
Set SO_REUSEADDRESS and SO_V6ONLY options on the DHCPv6
socket, this allows multiple instances of dnsmasq on a
single machine, in the same way as for DHCPv4. Thanks to
Gene Czarcinski and Vladislav Grishenko for work on this.
Fix DHCPv6 to do access control correctly when it's
configured with --listen-address. Thanks to
Gene Czarcinski for sorting this out.
Add a "wildcard" dhcp-range which works for any IPv6
subnet, --dhcp-range=::,static Useful for Stateless
DHCPv6. Thanks to Vladislav Grishenko for the patch.
Don't include lease-time in DHCPACK replies to DHCPINFORM
queries, since RFC-2131 says we shouldn't. Thanks to
Wouter Ibens for pointing this out.
Makefile tweak to do dependency checking on header files.
Thanks to Johan Peeters for the patch.
Check interface for outgoing unsolicited router
advertisements, rather than relying on interface address
configuration. Thanks to Gene Czarinski for the patch.
Handle better attempts to transmit on interfaces which are
still doing DAD, and specifically do not just transmit
without setting source address and interface, since this
can cause very puzzling effects when a router
advertisement goes astray. Thanks again to Gene Czarinski.
Get RA timers right when there is more than one
dhcp-range on a subnet.
version 2.63
Do duplicate dhcp-host address check in --test mode.
Check that tftp-root directories are accessible before
start-up. Thanks to Daniel Veillard for the initial patch.
Allow more than one --tfp-root flag. The per-interface
stuff is pointless without that.
Add --bind-dynamic. A hybrid mode between the default and
--bind-interfaces which copes with dynamically created
interfaces.
A couple of fixes to the build system for Android. Thanks
to Metin Kaya for the patches.
Remove the interface:<interface> argument in --dhcp-range, and
the interface argument to --enable-tftp. These were a
still-born attempt to allow automatic isolated
configuration by libvirt, but have never (to my knowledge)
been used, had very strange semantics, and have been
superceded by other mechanisms.
Fixed bug logging filenames when duplicate dhcp-host
addresses are found. Thanks to John Hanks for the patch.
Fix regression in 2.61 which broke caching of CNAME
chains. Thanks to Atul Gupta for the bug report.
Allow the target of a --cname flag to be another --cname.
Teach DHCPv6 about the RFC 4242 information-refresh-time
option, and add parsing if the minutes, hours and days
format for options. Thanks to Francois-Xavier Le Bail for
the suggestion.
Allow "w" (for week) as multiplier in lease times, as well
as seconds, minutes, hours and days. Álvaro Gámez Machado
spotted the ommission.
Update French translation. Thanks to Gildas Le Nadan.
Allow a DBus service name to be given with --enable-dbus
which overrides the default,
uk.org.thekelleys.dnsmasq. Thanks to Mathieu
Trudel-Lapierre for the patch.
Set the "prefix on-link" bit in Router
Advertisements. Thanks to Gui Iribarren for the patch.
version 2.62
Update German translation. Thanks to Conrad Kostecki.
Cope with router-solict packets wich don't have a valid
source address. Thanks to Vladislav Grishenko for the patch.
Fixed bug which caused missing periodic router
advertisements with some configurations. Thanks to
Vladislav Grishenko for the patch.
Fixed bug which broke DHCPv6/RA with prefix lengths
which are not divisible by 8. Thanks to Andre Coetzee
for spotting this.
Fix non-response to router-solicitations when
router-advertisement configured, but DHCPv6 not
configured. Thanks to Marien Zwart for the patch.
Add --dns-rr, to allow arbitrary DNS resource records.
Fixed bug which broke RA scheduling when an interface had
two addresses in the same network. Thanks to Jim Bos for
his help nailing this.
version 2.61
Re-write interface discovery code on *BSD to use
getifaddrs. This is more portable, more straightforward,
and allows us to find the prefix length for IPv6
addresses.
Add ra-names DHCPv6 keyword which adds AAAA records
for dual-stack hosts which get IPv6 addresses via SLAAC.
Add ra-names, ra-stateless and slaac keywords for DHCPv6.
Dnsmasq can now synthesise AAAA records for dual-stack
hosts which get IPv6 addresses via SLAAC. It is also now
possible to use SLAAC and stateless DHCPv6, and to
tell clients to use SLAAC addresses as well as DHCP ones.
Thanks to Dave Taht for help with this.
Add --dhcp-duid to allow DUID-EN uids to be used.
Explicity send DHCPv6 replies to the correct port, instead
of relying on clients to send requests with the correct
source address, since at least one client in the wild gets
this wrong. Thanks to Conrda Kostecki for help tracking
this wrong. Thanks to Conrad Kostecki for help tracking
this down.
Send a preference value of 255 in DHCPv6 replies when
@@ -40,9 +631,67 @@ version 2.61
Set the environment variable DNSMASQ_LOG_DHCP when running
the script id --log-dhcp is in effect, so that script can
taylor their logging verbosity. Suggestion from Malte Forkel.
taylor their logging verbosity. Suggestion from Malte
Forkel.
Arrange that addresses specified with --listen-address
work even if there is no interface carrying the
address. This is chiefly useful for IPv4 loopback
addresses, where any address in 127.0.0.0/8 is a valid
loopback address, but normally only 127.0.0.1 appears on
the lo interface. Thanks to Mathieu Trudel-Lapierre for
the idea and initial patch.
Fix crash, introduced in 2.60, when a DHCPINFORM is
received from a network which has no valid dhcp-range.
Thanks to Stephane Glondu for the bug report.
Add a new DHCP lease time keyword, "deprecated" for
--dhcp-range. This is only valid for IPv6, and sets the
preffered lease time for both DHCP and RA to zero. The
effect is that clients can continue to use the address
for existing connections, but new connections will use
other addresses, if they exist. This makes hitless
renumbering at least possible.
Fix bug in address6_available() which caused DHCPv6 lease
aquisition to fail if more than one dhcp-range in use.
Provide RDNSS and DNSSL data in router advertisements,
using the settings provided for DHCP options
option6:domain-search and option6:dns-server.
Tweak logo/favicon.ico to add some transparency. Thanks to
SamLT for work on this.
Don't cache data from non-recursive nameservers, since it
may erroneously look like a valid CNAME to a non-exitant
name. Thanks to Ben Winslow for finding this.
Call SO_BINDTODEVICE on the DHCP socket(s) when doing DHCP
on exactly one interface and --bind-interfaces is set. This
makes the OpenStack use-case of one dnsmasq per virtual
interface work. This is only available on Linux; it's not
supported on other platforms. Thanks to Vishvananda Ishaya
and the OpenStack team for the suggestion.
Updated French translation. Thanks to Gildas Le Nadan.
Give correct from-cache answers to explict CNAME queries.
Thanks to Rob Zwissler for spotting this.
Add --tftp-lowercase option. Thanks to Oliver Rath for the
patch.
Ensure that the DBus DhcpLeaseUpdated events are generated
when a lease goes through INIT_REBOOT state, even if the
dhcp-script is not in use. Thanks to Antoaneta-Ecaterina
Ene for the patch.
Fix failure of TFTP over IPv4 on OpenBSD platform. Thanks
to Brad Smith for spotting this.
version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
Flebbe for the patch.
@@ -222,7 +871,7 @@ version 2.58
Fix regression in TFTP server on *BSD platforms introduced
in version 2.56, due to confusion with sockaddr
length. Many thanks to Loïc Pefferkorn for finding this.
length. Many thanks to Loic Pefferkorn for finding this.
Support scope-ids in IPv6 addresses of nameservers from
/etc/resolv.conf and in --server options. Eg

109
FAQ
View File

@@ -22,7 +22,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
now uses a new, randomly selected, port for each query. The old
default behaviour (use one port allocated by the OS) is available by
setting --query-port=0, and setting the query port to a positive
value is still works. You should think hard and know what you are
value still works. You should think hard and know what you are
doing before using either of these options.
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
@@ -112,7 +112,7 @@ A: Resolver code sometime does strange things when given names without
hostname will fix things. (ie "ping myhost" fails, but "ping
myhost." works. The solution is to make sure that all your hosts
have a domain set ("domain" in resolv.conf, or set a domain in
your DHCP server, see below fr Windows XP and Mac OS X).
your DHCP server, see below for Windows XP and Mac OS X).
Any domain will do, but "localnet" is traditional. Now when you
resolve "myhost" the resolver will attempt to look up
"myhost.localnet" so you need to have dnsmasq reply to that name.
@@ -236,53 +236,70 @@ Q: What network types are supported by the DHCP server?
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
Linux all network types (including FireWire) are supported.
Q: What is this strange "bind-interface" option?
Q: What are these strange "bind-interface" and "bind-dynamic" options?
A: The DNS spec says that the reply to a DNS query must come from the
same address it was sent to. The traditional way to write an UDP
server to do this is to find all of the addresses belonging to the
machine (ie all the interfaces on the machine) and then create a
socket for each interface which is bound to the address of the
interface. Then when a packet is sent to address A, it is received
on the socket bound to address A and when the reply is also sent
via that socket, the source address is set to A by the kernel and
everything works. This is the how dnsmasq works when
"bind-interfaces" is set, with the obvious extension that is misses
out creating sockets for some interfaces depending on the
--interface, --address and --except-interface flags. The
disadvantage of this approach is that it breaks if interfaces don't
exist or are not configured when the daemon starts and does the
socket creation step. In a hotplug-aware world this is a real
problem.
A: Dnsmasq from v2.63 can operate in one of three different "networking
modes". This is unfortunate as it requires users configuring dnsmasq
to take into account some rather bizzare contraints and select the
mode which best fits the requirements of a particular installation.
The origin of these are deficiencies in the Unix networking
model and APIs and each mode has different advantages and
problems. Just to add to the confusion, not all modes are available on
all platforms (due the to lack of supporting network APIs).To further
add to the confusion, the rules for the DHCP subsystem on dnsmasq are
different to the rules for the DNS and TFTP subsystems.
The alternative approach is to have only one socket, which is bound
to the correct port and the wildcard IP address (0.0.0.0). That
socket will receive _all_ packets sent to port 53, no matter what
destination address they have. This solves the problem of
interfaces which are created or reconfigured after daemon
start-up. To make this work is more complicated because of the
"reply source address" problem. When a UDP packet is sent by a
socket bound to 0.0.0.0 its source address will be set to the
address of one of the machine's interfaces, but which one is not
determined and can vary depending on the OS being run. To get round
this it is neccessary to use a scary advanced API to determine the
address to which a query was sent, and force that to be the source
address in the reply. For IPv4 this stuff in non-portable and quite
often not even available (It's different between FreeBSD 5.x and
Linux, for instance, and FreeBSD 4.x, Linux 2.0.x and OpenBSD don't
have it at all.) Hence "bind-interfaces" has to always be available
as a fall back. For IPv6 the API is standard and universally
available.
The three modes are "wildcard", "bind-interfaces" and "bind-dynamic".
It could be argued that if the --interface or --address flags are
used then binding interfaces is more appropriate, but using
wildcard binding means that dnsmasq will quite happily start up
after being told to use interfaces which don't exist, but which are
created later. Wildcard binding breaks the scenario when dnsmasq is
listening on one interface and another server (most probably BIND)
is listening on another. It's not possible for BIND to bind to an
(address,port) pair when dnsmasq has bound (wildcard,port), hence
the ability to explicitly turn off wildcard binding.
In "wildcard" mode, dnsmasq binds the wildcard IP address (0.0.0.0 or
::). This allows it to recieve all the packets sent to the server on
the relevant port. Access control (--interface, --except-interface,
--listen-address, etc) is implemented by dnsmasq: it queries the
kernel to determine the interface on which a packet was recieved and
the address to which it was sent, and applies the configured
rules. Wildcard mode is the default if neither of the other modes are
specified.
In "bind-interfaces" mode, dnsmasq runs through all the network
interfaces available when it starts, finds the set of IP addresses on
those interfaces, filters that set using the access control
configuration, and then binds the set of IP addresses. Only packets
sent to the allowed addresses are delivered by the kernel to dnsmasq.
In "bind-dynamic" mode, access control filtering is done both by
binding individual IP addresses, as for bind-interfaces, and by
inspecting individual packets on arrival as for wildcard mode. In
addition, dnsmasq notices when new interfaces appear or new addresses
appear on existing interfaces, and the resulting IP addresses are
bound automatically without having to restart dnsmasq.
The mode chosen has four different effects: co-existence with other
servers, semantics of --interface access control, effect of new
interfaces, and legality of --interface specifications for
non-existent inferfaces. We will deal with these in order.
A dnsmasq instance running in wildcard mode precludes a machine from
running a second instance of dnsmasq or any other DNS, TFTP or DHCP
server. Attempts to do so will fail with an "address in use" error.
Dnsmasq running in --bind-interfaces or bind-dynamic mode allow other
instances of dnsmasq or other servers, as long as no two servers are
configured to listen on the same interface address.
The semantics of --interface varies subtly between wildcard or
bind-dynamic mode and bind-interfaces mode. The situation where this
matters is a request which arrives via one interface (A), but with a
destination address of a second interface (B) and when dnsmasq is
configured to listen only on B. In wildcard or bind-dynamic mode, such
a request will be ignored, in bind-interfaces mode, it will be
accepted.
The creation of new network interfaces after dnsmasq starts is ignored
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
mode, such interfaces are handled normally.
A --interface specification for a non-existent interface is a fatal
error at start-up when in --bind-interfaces mode, by just generates a
warning in wildcard or bind-dynamic mode.
Q: Why doesn't Kerberos work/why can't I get sensible answers to
queries for SRV records.

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
# dnsmasq is Copyright (c) 2000-2014 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,35 +51,44 @@ 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 $(PKG_CONFIG) --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)`\"'
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
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.c
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)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.configured $(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
@@ -92,8 +101,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; \
@@ -109,11 +118,30 @@ merge :
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
# rules below are targets in recusive makes with cwd=$(SRC)
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
@touch $@
$(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ .
@@ -121,7 +149,7 @@ $(objs:.o=.c) $(hdrs):
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(hdrs) $(objs)
dnsmasq : .configured $(hdrs) $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
@@ -130,5 +158,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,8 @@ 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
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c
LOCAL_MODULE := dnsmasq
@@ -17,4 +18,6 @@ LOCAL_C_INCLUDES := external/dnsmasq/src
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog
include $(BUILD_EXECUTABLE)

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

@@ -8,17 +8,19 @@
# which has a set of references substituted into it by git.
# If we can find one which matches $v[0-9].* then we assume it's
# a version-number tag, else we just use the whole string.
# 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
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
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | head -n 1 | tail -c +2
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
else
cat $1/VERSION
fi

View File

@@ -2,10 +2,34 @@
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
if [ $op = "--copy" ]; then
pkg="$*"
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

43
contrib/dbus-test/dbus-test.py Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/python
import dbus
bus = dbus.SystemBus()
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq")
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
# The new more flexible SetServersEx method
array = dbus.Array()
array.append(["1.2.3.5"])
array.append(["1.2.3.4#664", "foobar.com"])
array.append(["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"])
print l.SetServersEx(array)
# Must create a new object for dnsmasq as the introspection gives the wrong
# signature for SetServers (av) while the code only expects a bunch of arguments
# instead of an array of variants
p = bus.get_object("uk.org.thekelleys.dnsmasq", "/uk/org/thekelleys/dnsmasq", introspect=False)
l = dbus.Interface(p, dbus_interface="uk.org.thekelleys.dnsmasq")
# The previous method; all addresses in machine byte order
print l.SetServers(dbus.UInt32(16909060), # 1.2.3.5
dbus.UInt32(16909061), # 1.2.3.4
"foobar.com",
dbus.Byte(0x10), # 1003:1234:abcd::1
dbus.Byte(0x03),
dbus.Byte(0x12),
dbus.Byte(0x34),
dbus.Byte(0xab),
dbus.Byte(0xcd),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x00),
dbus.Byte(0x01),
"eng.mycorp.com",
"lab.mycorp.com")

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,57 @@
To: dnsmasq-discuss@lists.thekelleys.org.uk
From: Alex Elsayed <eternaleye+usenet@gmail.com>
Date: Tue, 15 May 2012 01:53:54 -0700
Subject: [Dnsmasq-discuss] [PATCH] Support dbus activation
Introduce dbus service file and turn dbus on in the systemd
unit.
Note to packagers:
To add support for dbus activation, you must install the dbus
service file (dbus/uk.org.thekelleys.dnsmasq.service) into
$DATADIR/dbus-1/system-services.
---
contrib/systemd/dnsmasq.service | 2 +-
dbus/uk.org.thekelleys.dnsmasq.service | 7 +++++++
2 files changed, 8 insertions(+), 1 deletion(-)
create mode 100644 dbus/uk.org.thekelleys.dnsmasq.service
diff --git a/contrib/systemd/dnsmasq.service
b/contrib/systemd/dnsmasq.service
index a27fe6d..4a784d3 100644
--- a/contrib/systemd/dnsmasq.service
+++ b/contrib/systemd/dnsmasq.service
@@ -5,7 +5,7 @@ Description=A lightweight DHCP and caching DNS server
Type=dbus
BusName=uk.org.thekelleys.dnsmasq
ExecStartPre=/usr/sbin/dnsmasq --test
-ExecStart=/usr/sbin/dnsmasq -k
+ExecStart=/usr/sbin/dnsmasq -k -1
ExecReload=/bin/kill -HUP $MAINPID
[Install]
diff --git a/dbus/uk.org.thekelleys.dnsmasq.service
b/dbus/uk.org.thekelleys.dnsmasq.service
new file mode 100644
index 0000000..f5fe98d
--- /dev/null
+++ b/dbus/uk.org.thekelleys.dnsmasq.service
@@ -0,0 +1,7 @@
+[D-BUS Service]
+Name=uk.org.thekelleys.dnsmasq
+Exec=/usr/sbin/dnsmasq -k -1
+User=root
+SystemdService=dnsmasq.service
+
+
--
1.7.10.2
_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss

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

@@ -12,9 +12,11 @@ If an error occurs or no lease exists for the given address,
nothing is sent to stdout a message is sent to stderr and a
non-zero error code is returned.
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
Requires dnsmasq 2.67 or later and may not work with other DHCP servers.
The address argument is a dotted-quad IP addresses and mandatory.
The address argument is a dotted-quad IP addresses and mandatory.
.SH LIMITATIONS
Only works with IPv4 addresses and DHCP leases.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR

View File

@@ -20,7 +20,7 @@
nothing is sent to stdout a message is sent to stderr and a
non-zero error code is returned.
Requires dnsmasq 2.40 or later.
This version requires dnsmasq 2.67 or later.
*/
#include <sys/types.h>
@@ -46,6 +46,7 @@
#define OPTION_LEASE_TIME 51
#define OPTION_OVERLOAD 52
#define OPTION_MESSAGE_TYPE 53
#define OPTION_REQUESTED_OPTIONS 55
#define OPTION_END 255
#define DHCPINFORM 8
#define DHCP_SERVER_PORT 67
@@ -167,6 +168,12 @@ int main(int argc, char **argv)
*(p++) = 1;
*(p++) = DHCPINFORM;
/* Explicity request the lease time, it won't be sent otherwise:
this is a dnsmasq extension, not standard. */
*(p++) = OPTION_REQUESTED_OPTIONS;
*(p++) = 1;
*(p++) = OPTION_LEASE_TIME;
*(p++) = OPTION_END;
dest.sin_family = AF_INET;

View File

@@ -27,6 +27,8 @@ for ethernet. This encoding is the one used in dnsmasq lease files.
The client-id is optional. If it is "*" then it treated as being missing.
.SH NOTES
MUST be run as root - will fail otherwise.
.SH LIMITATIONS
Only usable on IPv4 DHCP leases.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR

View File

@@ -255,10 +255,6 @@ int main(int argc, char **argv)
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
struct iovec iov;
iov.iov_len = 200;
iov.iov_base = malloc(iov.iov_len);
if (argc < 4 || argc > 5)
{

View File

@@ -19,7 +19,8 @@ and avoids startup races with the provider of nameserver information.
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
and a single object: /uk/org/thekelleys/dnsmasq
and a single object: /uk/org/thekelleys/dnsmasq
The name of the service may be changed by giving an argument to --enable-dbus.
1. METHODS
----------
@@ -94,6 +95,65 @@ Each call to SetServers completely replaces the set of servers
specified by via the DBus, but it leaves any servers specified via the
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
SetServersEx
------------
This function is more flexible and the SetServers function, in that it can
handle address scoping, port numbers, and is easier for clients to use.
Returns nothing. Takes a set of arguments representing the new
upstream DNS servers to be used by dnsmasq. All addresses (both IPv4 and IPv6)
are represented as STRINGS. Each server address may be followed by one or more
STRINGS, which are the domains for which the preceding server should be used.
This function takes an array of STRING arrays, where each inner array represents
a set of DNS servers and domains for which those servers may be used. Each
string represents a list of upstream DNS servers first, and domains second.
Mixing of domains and servers within a the string array is not allowed.
Examples.
[
["1.2.3.4", "foobar.com"],
["1003:1234:abcd::1%eth0", "eng.mycorp.com", "lab.mycorp.com"]
]
is equivalent to
--server=/foobar.com/1.2.3.4 \
--server=/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0
An IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
so
[ ["0.0.0.0", "local.domain"] ]
is equivalent to
--local=/local.domain/
Each call to SetServersEx completely replaces the set of servers
specified by via the DBus, but it leaves any servers specified via the
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
SetDomainServers
----------------
Yes another variation for setting DNS servers, with the capability of
SetServersEx, but without using arrays of arrays, which are not
sendable with dbus-send. The arguments are an array of strings which
are identical to the equivalent arguments --server, so the example
for SetServersEx is represented as
[
"/foobar.com/1.2.3.4"
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
]
2. SIGNALS
----------

162
debian/changelog vendored
View File

@@ -1,12 +1,172 @@
dnsmasq (2.72-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 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> 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
* New upstream.
* Add support for noipset in DEB_BUILD_OPTIONS.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 22 Feb 2013 21:52:13 +0000
dnsmasq (2.65-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:34:12 +0000
dnsmasq (2.64-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:17:22 +0000
dnsmasq (2.63-4) unstable; urgency=low
* Make pid-file creation immune to symlink attacks. (closes: #686484)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 21 Sep 2012 17:16:34 +0000
dnsmasq (2.63-3) unstable; urgency=low
* Move adduser dependency to dnsmasq-base. (closes: #686694)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Sep 2012 21:44:15 +0000
dnsmasq (2.63-2) unstable; urgency=low
* Fix version script to report correct version.
* Unbotch move of dbus config file by using correct versions in
Replaces: and Breaks: lines. (closes: #685204)
* Create dnsmasq user in dnsmasq-base so that Dbus doesn't complain if
only dnsmasq-base is installed. (closes: #685987)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 Aug 2012 16:18:35 +0000
dnsmasq (2.63-1) unstable; urgency=low
* New upstream.
* Move /etc/dbus-1/system.d/dnsmasq.conf from dnsmasq to dnsmasq-base.
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 11 Jun 2012 21:55:35 +0000
dnsmasq (2.62-3) unstable; urgency=low
* Do resolvconf and /etc/default startup logic when
starting with systemd. (closes: #675854)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 11 Jun 2012 21:50:11 +0000
dnsmasq (2.62-2) unstable; urgency=low
* Pass LDFLAGS to make to get hardening in linker.
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 7 Jun 2012 09:53:43 +0000
dnsmasq (2.62-1) unstable; urgency=low
* New upstream.
* Use dpkg-buildflags. (Enables hardening).
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 12 May 2012 15:25:23 +0000
dnsmasq (2.61-1) unstable; urgency=low
* New upstream.
* Provide "dump-stats" initscript method. (closes: #654656)
* Add (empty) build-indep and build-arch rules targets.
* Bump standards-version to 3.9.3
* Add port option to example dnsmasq.conf (closes: #668386)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Mar 2012 19:45:43 +0000
dnsmasq (2.60-2) unstable; urgency=high
* Fix DHCPv4 segfault. (closes: #665008)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 23 Mar 2012 09:37:23 +0000
dnsmasq (2.60-1) unstable; urgency=low
* New upstream.

1
debian/conffiles vendored
View File

@@ -2,5 +2,4 @@
/etc/default/dnsmasq
/etc/dnsmasq.conf
/etc/resolvconf/update.d/dnsmasq
/etc/dbus-1/system.d/dnsmasq.conf
/etc/insserv.conf.d/dnsmasq

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)
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.3
Package: dnsmasq
Architecture: all
Depends: netbase, adduser, 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
@@ -22,8 +25,9 @@ Description: Small caching DNS proxy and DHCP/TFTP server
Package: dnsmasq-base
Architecture: any
Depends: ${shlibs:Depends}
Conflicts: dnsmasq (<<2.41)
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~)
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

2
debian/copyright vendored
View File

@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
dnsmasq is Copyright (c) 2000-2013 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

1
debian/dnsmasq-base.conffiles vendored Normal file
View File

@@ -0,0 +1 @@
/etc/dbus-1/system.d/dnsmasq.conf

24
debian/dnsmasq-base.postinst vendored Normal file
View File

@@ -0,0 +1,24 @@
#!/bin/sh
set -e
# Create the dnsmasq user in dnsmasq-base, so that Dbus doesn't complain.
# create a user to run as (code stolen from dovecot-common)
if [ "$1" = "configure" ]; then
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
--no-create-home --disabled-password \
--quiet dnsmasq || true
fi
# Make the directory where we keep the pid file - this
# has to be owned by "dnsmasq" so that the file can be unlinked.
# This is only actually used by the dnsmasq binary package, not
# dnsmasq-base, but it's much easier to create it here so that
# we don't have synchronisation issues with the creation of the
# dnsmasq user.
if [ ! -d /var/run/dnsmasq ]; then
mkdir /var/run/dnsmasq
chown dnsmasq:nogroup /var/run/dnsmasq
fi
fi

11
debian/dnsmasq-base.postrm vendored Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
set -e
if [ purge = "$1" ]; then
if [ -x "$(command -v deluser)" ]; then
deluser --quiet --system dnsmasq > /dev/null || true
else
echo >&2 "not removing dnsmasq system account because deluser command was not found"
fi
rm -rf /var/run/dnsmasq
fi

44
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,14 @@ 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"
start()
{
# Return
@@ -144,9 +158,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()
@@ -259,6 +270,33 @@ case "$1" in
dump-stats)
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
;;
systemd-start-resolvconf)
start_resolvconf
;;
systemd-stop-resolvconf)
stop_resolvconf
;;
systemd-exec)
# /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
# Enable DBus by default because we use DBus activation with systemd.
exec $DAEMON --keep-in-foreground --enable-dbus \
-x /var/run/dnsmasq/$NAME.pid \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
${DHCP_LEASE:+ -l $DHCP_LEASE} \
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${CACHESIZE:+ -c $CACHESIZE} \
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3

37
debian/postinst vendored
View File

@@ -1,26 +1,21 @@
#!/bin/sh
set -e
# create a user to run as (code stolen from dovecot-common)
if [ "$1" = "configure" ]; then
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
--no-create-home --disabled-password \
--quiet dnsmasq || true
fi
# 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
# Make the directory where we keep the pid file - this
# has to be owned by "dnsmasq" do that the file can be unlinked.
if [ ! -d /var/run/dnsmasq ]; then
mkdir /var/run/dnsmasq
chown dnsmasq:nogroup /var/run/dnsmasq
fi
# handle new location of pidfile during an upgrade
if [ -e /var/run/dnsmasq.pid ]; then
mv /var/run/dnsmasq.pid /var/run/dnsmasq
fi
# 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
@@ -40,10 +35,4 @@ if [ -x /etc/init.d/dnsmasq ]; then
fi
fi
# dpkg can botch the change of /usr/share/doc/dnsmasq from
# directory to symlink. Fix up here.
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
cd /usr/share/doc/
ln -s /usr/share/doc/dnsmasq-base dnsmasq
fi

22
debian/postrm vendored
View File

@@ -3,10 +3,20 @@ set -e
if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null
if [ -x "$(command -v deluser)" ]; then
deluser --quiet --system dnsmasq > /dev/null || true
else
echo >&2 "not removing dnsmasq system account because deluser command was not found"
fi
rm -rf /var/run/dnsmasq
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 ------------------

5
debian/readme vendored
View File

@@ -59,11 +59,14 @@ Notes on configuring dnsmasq as packaged for Debian.
noipv6 : omit IPv6 support.
nodbus : omit DBus support.
noconntrack : omit connection tracking support.
noipset : omit IPset support.
nortc : compile alternate mode suitable for systems without an RTC.
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

70
debian/rules vendored
View File

@@ -11,61 +11,76 @@
package=dnsmasq-base
# policy manual, section 10.1
ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS = -g -O0 -Wall -W
else
CFLAGS = -g -O2 -Wall -W
endif
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)
DEB_COPTS = $(COPTS)
COPTS =
TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
# 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
DEB_COPTS += -DHAVE_CONNTRACK
endif
endif
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
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
clean:
@@ -85,7 +100,6 @@ binary-indep: checkroot
-d debian/daemon/etc/resolvconf/update.d \
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/daemon/etc/default \
-d debian/daemon/etc/dbus-1/system.d \
-d debian/daemon/lib/systemd/system \
-d debian/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/daemon/DEBIAN
@@ -96,12 +110,11 @@ binary-indep: checkroot
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
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
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
@@ -111,15 +124,18 @@ binary-arch: checkroot
rm -rf debian/base
install -m 755 \
-d debian/base/DEBIAN \
-d debian/base/etc/dbus-1/system.d \
-d debian/base/usr/share/doc/$(package) \
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/var/run \
-d debian/base/usr/share/$(package) \
-d debian/base/var/lib/misc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" 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)/.
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
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
@@ -129,10 +145,14 @@ ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
gzip -9 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
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
for f in debian/base/usr/share/man/*; do \
if [ -f $$f/man8/dnsmasq.8 ]; then \
@@ -143,8 +163,8 @@ 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
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
@@ -155,7 +175,7 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
-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)" 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
@@ -171,7 +191,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | 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
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..

View File

@@ -8,22 +8,23 @@ BusName=uk.org.thekelleys.dnsmasq
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/usr/sbin/dnsmasq --test
# Enable DBus by default because we use DBus activation.
# 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.
#
# Drop privileges and become the 'dnsmasq' user. It is recommended by dnsmasq
# upstream to run dnsmasq as an isolated user that does not run any other
# processes, owns no files and has no shell. The default 'nobody' user has a
# shell and might be used for other processes.
# It also adds the command-line flags
# --keep-in-foreground --enable-dbus
# to enable DBus by default because we use DBus activation.
#
# Debian-specific: add /etc/dnsmasq.d to config search path (with the exception
# of .dpkg-*). Packages such as libvirt leave config files there.
#
# --pid-file without argument disables writing a PIDfile, we don't need one.
ExecStart=/usr/sbin/dnsmasq -k \
--enable-dbus \
--user=dnsmasq \
-7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new \
--pid-file
ExecStart=/etc/init.d/dnsmasq systemd-exec
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called liek
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start.
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf
ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf
ExecReload=/bin/kill -HUP $MAINPID

View File

@@ -4,6 +4,11 @@
# as the long options legal on the command line. See
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
# Listen on this specific port instead of the standard DNS port
# (53). Setting this to zero completely disables DNS function,
# leaving only DHCP and/or TFTP.
#port=5353
# The following two options make you a better netizen, since they
# tell dnsmasq to filter out queries which the public DNS cannot
# answer, and which load the servers (especially the root servers)
@@ -15,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.
@@ -64,6 +81,10 @@
# --address (and --server) work with IPv6 addresses too.
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
# Add the IPs of all queries to yahoo.com, google.com, and their
# subdomains to the vpn and search ipsets:
#ipset=/yahoo.com/google.com/vpn,search
# You can control how dnsmasq talks to a server: this forces
# queries to 10.1.2.3 to be routed via eth1
# server=10.1.2.3@eth1
@@ -169,14 +190,32 @@
# hosts. Use the DHCPv4 lease to derive the name, network segment and
# MAC address and assume that the host will also have an
# IPv6 address calculated using the SLAAC alogrithm.
# This will generate an erroneous AAAA record if a host is using privacy
# extensions or does not support IPv6. Use with care.
#dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet.
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
#dhcp-range=1234::, ra-only, 48h
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
# so that clients can use SLAAC addresses as well as DHCP ones.
#dhcp-range=1234::2, 1234::500, slaac
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
# not get addresses from DHCP, but they will get other configuration information.
# They will use SLAAC for addresses.
#dhcp-range=1234::, ra-stateless
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
# from DHCPv4 leases.
#dhcp-range=1234::, ra-stateless, ra-names
# Do router advertisements for all subnets where we're doing DHCPv6
# Unless overriden by ra-stateless, ra-names, et al, the router
# advertisements will have the M and O bits set, so that the clients
# get addresses and configuration from DHCPv6, and the A bit reset, so the
# clients don't use SLAAC addresses.
#enable-ra
# Supply parameters for specified hosts using DHCP. There are lots
# of valid alternatives, so we will give examples of each. Note that
# IP addresses DO NOT have to be in the range given above, they just
@@ -303,6 +342,9 @@
# dnsmasq and another.
#dhcp-option=option6:dns-server,[::],[1234::88]
# Ask client to poll for option changes every six hours. (RFC4242)
#dhcp-option=option6:information-refresh-time,6h
# Set the NTP time server address to be the same machine as
# is running dnsmasq
#dhcp-option=42,0.0.0.0
@@ -454,7 +496,7 @@
#tftp-no-blocksize
# Set the boot file name only when the "red" tag is set.
#dhcp-boot=net:red,pxelinux.red-net
#dhcp-boot=tag:red,pxelinux.red-net
# An example of dhcp-boot with an external TFTP server: the name and IP
# address of the server are given after the filename.
@@ -499,7 +541,7 @@
# If you want to disable negative caching, uncomment this.
#no-negcache
# Normally responses which come form /etc/hosts and the DHCP lease
# Normally responses which come from /etc/hosts and the DHCP lease
# file have Time-To-Live set as zero, which conventionally means
# do not cache further. If you are happy to trade lower load on the
# server for potentially stale date, you can set a time-to-live (in
@@ -595,6 +637,6 @@
# Log lots of extra information about DHCP transactions.
#log-dhcp
# Include a another lot of configuration options.
# Include another lot of configuration options.
#conf-file=/etc/dnsmasq.more.conf
#conf-dir=/etc/dnsmasq.d

130
doc.html
View File

@@ -1,6 +1,6 @@
<HTML>
<HEAD>
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
<TITLE> Dnsmasq - network services for small networks.</TITLE>
<link rel="icon"
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
</HEAD>
@@ -11,82 +11,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,7 +68,7 @@ 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>
@@ -110,7 +76,21 @@ 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
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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -6,23 +6,40 @@ Dnsmasq \- Un serveur DHCP et cache DNS poids-plume.
.I [OPTION]...
.SH "DESCRIPTION"
.BR dnsmasq
est un serveur DHCP et DNS à faible empreinte mémoire. Il offre à la fois les
services DNS et DHCP pour un réseau local (LAN).
est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
local (LAN).
.PP
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
local, soit en effectuant une requête à un serveur DNS récursif externe (par
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
globaux soient tout de même résolus, et assure également la résolution de nom
pour les hôtes présents dans le service DHCP.
pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
noms locaux d'apparaitre dans le DNS global.
.PP
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
réseaux multiples. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
peut être configuré pour envoyer n'importe quel option DHCP.
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
et peut être configuré pour fournir n'importe quelle option DHCP.
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
support PXE est complet, et comprend un mode proxy permettant de fournir des
informations PXE aux clients alors que l'allocation DHCP est effectuée par un
autre serveur.
.PP
Dnsmasq supporte IPv6 pour le DNS et TFTP mais pas pour le DHCP.
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
qu'une fonctionalité permettant l'addition de ressources AAAA pour des
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
autoconfiguration).
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
une délégation de préfixe DHCPv6.
.PP
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
l'empreinte mémoire la plus faible possible pour les fonctions supportées,
et permet d'exclure les fonctions inutiles du binaire compilé.
.SH OPTIONS
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
@@ -75,9 +92,16 @@ l'absence d'enregistrement SOA.
.TP
.B --max-ttl=<durée>
Définie la valeur de TTL maximum qui sera fournie aux clients. La valeur maximum
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de TTL
si cette dernière est supérieure. La valeur réelle de TTL est cependant conservée dans
le cache afin d'éviter de saturer les serveurs DNS en amont.
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de
TTL si cette dernière est supérieure. La valeur réelle de TTL est cependant
conservée dans le cache afin d'éviter de saturer les serveurs DNS en amont.
.TP
.B --max-cache-ttl=<durée>
Définie la valeur de TTL maximum pour les entrées dans le cache
.TP
.B --auth-ttl=<durée>
Définie la valeur de TTL retournée pour les réponses du serveur faisant
autorité.
.TP
.B \-k, --keep-in-foreground
Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
@@ -89,7 +113,10 @@ Mode debug (déverminage) : ne pas aller en tâche de fond, ne pas écrire de
fichier pid, ne pas changer d'identifiant utilisateur, générer un état complet
du cache lors de la réception d'un signal SIGUSR1, envoyer les logs sur la
sortie standard d'erreur ("stderr") de même que dans le syslog, ne pas créer de
processus fils pour traiter les requêtes TCP.
processus fils pour traiter les requêtes TCP. A noter que cette option est à
user pour du déverminage seulement : pour empêcher dnsmasq se fonctionner en
mode démon en production, utiliser
.B -k.
.TP
.B \-q, --log-queries
Enregistrer les résultats des requêtes DNS traitées par Dnsmasq dans un fichier
@@ -184,7 +211,11 @@ ni
.B \--except-interface.
Utiliser l'option
.B --listen-address
à la place.
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
les options
.B \--interface
et
.B \--except-interface
.TP
.B \-I, --except-interface=<interface name>
Ne pas écouter sur l'interface spécifiée. Notez que l'ordre dans lesquelles les
@@ -197,6 +228,21 @@ et
sont fournies n'importe pas, et que l'option
.B --except-interface
l'emporte toujours sur les autres.
.TP
.B --auth-server=<domaine>,<interface>|<addresse IP>
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
pas besoin d'être mentionées ni dans
.B --interface
ni dans
.B --listen-address
En effet,
.B --auth-server
va passer outre ceux-ci et fournir un service DNS différent sur l'interface
spécifiée. La valeur de <domaine> est l'enregistrement de type "colle"
("glue record"). Il doit correspondre dans le service DNS global avec un
enregistrement de type A et/ou AAAA pointant sur l'adresse sur laquelle dnsmasq
écoute pour le mode DNS faisant autorité.
.TP
.B \-2, --no-dhcp-interface=<nom d'interface>
Ne pas fournir de service DHCP sur l'interface spécifiée, mais fournir tout de
@@ -231,6 +277,18 @@ autre serveur de nom (ou une autre instance de Dnsmasq) tourne sur la même
machine. Utiliser cette option permet également d'avoir plusieurs instances de
Dnsmasq fournissant un service DHCP sur la même machine.
.TP
.B --bind-dynamic
Autorise un mode réseau intermédiaire entre
.B --bind-interfaces
et le mode par défaut. Dnsmasq s'associe à une seule interface, ce qui permet
plusieurs instances de dnsmasq, mais si une interface ou adresse apparaissent,
il se mettra automatiquement à écouter sur celles-ci (les règles de contrôle
d'accès s'appliquent).
De fait, les interfaces créées dynamiquement fonctionnent de la même façon que
dans le comportement par défaut. Ce fonctionnement nécessite des APIs réseau
non standard et n'est disponible que sous Linux. Sur les autres plateformes,
le fonctionnement est celui du mode --bind-interfaces.
.TP
.B \-y, --localise-queries
Retourne des réponses aux requêtes DNS dépendantes de l'interface sur laquelle
la requête a été reçue, à partir du fichier /etc/hosts. Si un nom dans
@@ -299,11 +357,14 @@ Ne pas lire le contenu du fichier /etc/resolv.conf. N'obtenir l'adresse des
serveurs de nom amont que depuis la ligne de commande ou le fichier de
configuration de Dnsmasq.
.TP
.B \-1, --enable-dbus
.B \-1, --enable-dbus[=<nom de service>]
Autoriser la mise à jour de la configuration de Dnsmasq par le biais d'appel de
méthodes DBus. Il est possible par ce biais de mettre à jour l'adresse de
serveurs DNS amont (et les domaines correspondants) et de vider le cache. Cette
option nécessite que Dnsmasq soit compilé avec le support DBus.
option nécessite que Dnsmasq soit compilé avec le support DBus. Si un nom de
service est fourni, dnsmasq fourni un service à ce nom, plutôt qu'avec la
valeur par défaut :
.B uk.org.thekelleys.dnsmasq
.TP
.B \-o, --strict-order
Par défaut, Dnsmasq envoie les requêtes à n'importe lequel des serveurs amonts
@@ -342,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
@@ -442,6 +504,12 @@ n'ayant de réponse ni dans /etc/hosts, ni dans les baux DHCP, et n'étant pas
transmise à un serveur spécifique par le biais d'une directive
.B --server.
.TP
.B --ipset=/<domaine>/[domaine/]<ipset>[,<ipset>]
Obtient les adresses IP des domaines spécifiés et les place dans les groupes
d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
ipset(8) pour plus de détails.
.TP
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
@@ -492,6 +560,27 @@ dans un ordre différents. Pour un service/domaine donné, plus d'un
enregistrement SRV est autorisé et tous les enregistrements qui coïncident sont
retournés dans la réponse.
.TP
.B --host-record=<nom>[,<nom>....][<adresse IPv4>],[<adresse IPv6>]
Ajoute des enregistrements A, AAAA et PTR dans le DNS. Ceci permet d'ajouter
un ou plusieurs noms dans le DNS et de les associer à des enregistrements IPv4
(A) ou IPv6 (AAAA). Un nom peut apparaître dans plus d'une entrée
.B host-record
et de fait être associé à plus d'une adresse. Seule la première entrée créée
l'enregistrement PTR associée au nom. Ceci correspond à la même règle que celle
utilisée lors de la lecture du fichier hosts.
Les options
.B host-record
sont considérées lues avant le fichier hosts, ainsi un nom apparaissant dans
une option host-record et dans le fichier hosts n'aura pas d'enregistrement
PTR associé à l'entrée dans le fichier hosts. A l'inverse du fichier hosts, les
noms ne sont pas étendus, même lorsque l'option
.B expand-hosts
est activée. Les noms longs et les noms courts peuvent apparaitre dans la même
entrée
.B host-record,
c-à-d
.B --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
.TP
.B \-Y, --txt-record=<nom>[[,<texte>],<texte>]
Définit un enregistrement DNS de type TXT. La valeur de l'enregistrement TXT est
un ensemble de chaînes de caractères, donc un nombre variable de chaînes de
@@ -508,11 +597,19 @@ 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. 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 vers la même cible.
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
vers la même cible.
.TP
.B --dns-rr=<nom>,<numéro-RR>,[<données hexadécimales>]
Retourne un enregistrement DNS arbitraire. Le numéro correspond au type
d'enregistrement (qui est toujours de la classe C_IN). La valeur de
l'enregistrement est donnée dans les données hexadécimales, qui peuvent
être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
.TP
.B --interface-name=<nom>,<interface>
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
@@ -526,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
@@ -534,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.
@@ -569,6 +697,39 @@ 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>[/<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. 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)
associé à une zone pour laquelle le serveur fait autorité. A noter que cela est
optionnel, les valeurs par défaut devant convenir à la majorité des cas.
.TP
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
transfert de zone, et répondre aux requêtes pour toutes les zones pour
lesquelles dnsmasq fait autorité.
.TP
.B --auth-peer=<adresse IP>[,<adresse IP>[,<adresse IP>...]]
Spécifie la ou les adresses de serveurs secondaires autorisés à initier des
requêtes de transfert de zone (AXFR) pour les zones pour lesquelles
dnsmasq fait autorité. Si cette option n'est pas fournie, les requêtes AXFR
seront acceptées pour tous les serveurs secondaires.
.TP
.B --conntrack
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
et positionne la même marque au trafic amont utilisé pour répondre à ces
@@ -577,11 +738,12 @@ l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
avec le support conntrack, le noyau doit également inclure conntrack et être
configuré pour cela. Cette option ne peut pas être combinée avec
--query-port.
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>,<adresse IPv6 de fin>[,<longueur de préfixe>][,<durée de bail>]
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies
statiquement dans l'option
@@ -592,6 +754,13 @@ en heures (exemple : 1h) ou être la chaine de caractère "infinite" pour une
durée indéterminée. Si aucune valeur n'est donnée, une durée de bail par défaut
de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2
minutes.
Pour les plages IPv6, la durée de bail peut-être égale au mot-clef "deprecated"
(obsolète); Cela positionne la durée de vie préférée envoyée dans les baux DHCP
ou les annonces routeurs à zéro, ce qui incite les clients à utiliser d'autres
adresses autant que possible, pour toute nouvelle connexion, en préalable à
la renumérotation.
Cette option peut être répétée, avec différentes adresses,
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
@@ -614,6 +783,43 @@ d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
configuration de l'interface. La taille minimale pour la longueur de préfixe
est 64.
Pour IPv6 (et IPv6 uniquement), il est possible de définir les plages d'une
autre façon. Dans ce cas, l'adresse de départ et l'adresse de fin optionnelle
contiennent uniquement la partie réseau (par exemple ::1) et sont suivies par
.B constructor:<interface>.
Cela forme un modèle décrivant comment construire la plage, à partir des
adresses assignées à l'interface. Par exemple
.B --dhcp-range=::1,::400,constructor:eth0
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
plus d'un réseau, les plages correspondantes seront automatiquement créées,
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
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
@@ -622,33 +828,66 @@ Lorsque préfixé par 'tag:', la signification change, et au lieu de définir un
label, il définit le label pour laquelle la règle s'applique. Un seul label peut-
être défini mais plusieurs labels peuvent coïncider.
L'adresse de fin peut être remplacée par le mot-clef
Le mot clef optionnel <mode> peut être égal à
.B static
("statique") qui indique à Dnsmasq d'activer le service DHCP pour le réseau
("statique") ce qui indique à Dnsmasq d'activer le service DHCP pour le réseau
spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
les hôtes possédant des adresses IP statiques fournies via
.B dhcp-host
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP.
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. Il est
possible d'activer un mode "fourre-tout" en définissant un réseau statique
comportant uniquement des zéros, c'est à dire :
.B --dhcp=range=::,static
Cela permet de retourner des réponses à tous les paquets de type
Information-request (requête d'information) en mode DHCPv6 sans état sur le
sous-réseau configuré.
L'adresse de fin peut-être remplacée par le mot-clef
Pour IPv4, le <mode> peut est égal à
.B proxy
, auquel cas Dnsmasq fournira un service de DHCP proxy pour le sous-réseau
spécifié. (voir
.B pxe-prompt
et
.B pxe-service
pour plus de détails, s'applique à IPv4 seulement).
pour plus de détails).
Pour IPv6, le mode peut-être une combinaison des valeurs
.B ra-only, slaac, ra-names, ra-stateless.
L'adresse de fin peut être remplacée par le mot-clef
.B ra-only
qui indique à dnsmasq de n'effectuer que des annonces de routeur (Router
Advertisement, RA) sur ce sous-réseau, et de ne pas faire de DHCP. Ceci
s'applique uniquement à IPv6, voir
.B enable-ra
pour plus de détails.
indique à dnsmasq de n'effectuer que des annonces de routeur (Router
Advertisement, RA) sur ce sous-réseau, et de ne pas faire de DHCP.
.B slaac
indique à dnsmasq d'effectuer des annonces de routeur sur ce sous-réseau
et de positionner dans celles-ci le bit A, afin que les clients utilisent
des adresses SLAAC. Lorsqu'utilisé conjointement avec une plage DHCP ou des
affectations statiques d'adresses DHCP, les clients disposeront à la fois
d'adresses DHCP assignées et d'adresses SLAAC.
.B ra-stateless
indique à dnsmasq d'effectuer des annonces de routeur avec les bits 0 et A
positionnés, et de fournir un service DHCP sans état ("stateless"). Les clients
utiliseront des adresses SLAAC, et utiliseront DHCP pour toutes les autres
informations de configuration.
.B ra-names
active un mode qui fourni des noms DNS aux hôtes fonctionnant en double pile
("dual stack") et configurés pour faire du SLAAC en IPv6. Dnsmasq utilise le
bail IPv4 de l'hôte afin de dériver le nom, le segment de réseau et l'adresse
MAC et assume que l'hôte disposera d'une adresse IPv6 calculée via l'algorithme
SLAAC, sur le même segment de réseau. Un ping est envoyé à l'adresse, et si une
réponse est obtenue, un enregistrement AAAA est rajouté dans le DNS pour cette
adresse IPv6. Veuillez-noter que cela n'arrive que pour les réseaux directement
connectés (et non ceux pour lesquels DHCP se fait via relai), et ne
fonctionnera pas si un hôte utilise les "extensions de vie privée"
("privacy extensions").
.B ra-names
peut-être combiné avec
.B ra-stateless
et
.B slaac.
La section interface:<nom d'interface> n'est normalement pas utilisée. Se
référer aux indications de la section NOTES pour plus de détail à ce sujet.
.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
@@ -672,9 +911,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
@@ -686,11 +925,17 @@ Un seul
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
Les adresses IPv6 doivent-être mises entre crochets comme suit :
.B --dhcp-host=laptop,[1234::56]
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.
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.
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.
@@ -894,6 +1139,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
@@ -928,7 +1207,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
@@ -1128,14 +1407,16 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
Dnsmasq.
.TP
.B \-K, --dhcp-authoritative
(IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
Doit être spécifié lorsque dnsmasq est réellement le seul serveur DHCP
sur le réseau. Pour DHCPv4, cela change le comportement par défaut qui est
celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
sa base de données contenant les baux sans que les clients n'aient besoin de
redemander un bail, si celle-ci est perdue.
Dans le cas de DHCPv6, cela positionne la priorité des réponses à 255 (le
maximum) au lieu de 0 (le minimum).
.TP
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
@@ -1167,12 +1448,29 @@ 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.
.TP
.TP
.B --dhcp-duid=<ID d'entreprise>,<uid>
(IPv6 seulement) Spécifie le numéro d'UID de serveur persistant que le serveur
DHCPv6 doit utiliser. Cette option n'est normalement pas requise, Dnsmasq
créant un DUID automatiquement lorsque cela est nécessaire. Lorsque cette
option est positionnée, elle fournit à Dnsmasq les données nécessaires à la
création d'un DUID de type DUID-EN. Veuillez noter qu'une fois créé, le DUID
est stocké dans la base des baux, aussi changer entre un DUID créé
automatiquement et un DUID-EN et vice-versa impose de réinitialiser la base de
baux. Le numéro d'ID d'entreprise est assigné par l'IANA, et l'uid est une
chaine hexadécimale unique à chaque serveur.
.TP
.B \-6 --dhcp-script=<chemin de fichier>
Lorsqu'un bail DHCP est créé, ou qu'un ancien est supprimé, le fichier dont le
Lorsqu'un bail DHCP est créé, qu'un ancien est supprimé, ou qu'un transfert
TFTP est terminé, le fichier dont le
chemin est spécifié est exécuté. Le <chemin de fichier> doit être un chemin
absolu, aucune recherche n'est effectuée via la variable d'environnement PATH.
Les arguments fournis à celui-ci sont soit
@@ -1223,10 +1521,17 @@ relai DHCP pour contacter Dnsmasq, si l'adresse IP du relai est connue.
DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP,
séparés par des espaces.
DNSMASQ_LOG_DHCP est positionné si
.B --log-dhcp
est activé.
Pour IPv4 seulement :
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID si un relai DHCP a
rajouté l'une de ces options.
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
Pour IPv6 seulement :
@@ -1241,6 +1546,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
@@ -1262,6 +1569,16 @@ Au démarrage de Dnsmasq, le script sera invoqué pour chacun des baux existants
dans le fichier des baux. Le script sera lancé avec l'action "del" pour les
baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP,
le script sera invoqué avec une action "old" pour tous les baux existants.
Il existe deux autres actions pouvant apparaître comme argument au script :
"init" et "tftp". D'autres sont susceptibles d'être rajoutées dans le futur,
aussi les scripts devraient-être écrits de sorte à ignorer les actions
inconnues. "init" est décrite ci-dessous dans
.B --leasefile-ro.
L'action "tftp" est invoquée lorsqu'un transfert de fichier TFTP s'est
terminé. Ses arguments sont la taille du fichier en octets, l'adresse à
laquelle le fichier a été envoyé, ainsi que le chemin complet du fichier.
.TP
.B --dhcp-luascript=<chemin>
Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
@@ -1276,8 +1593,10 @@ et peut fournir des fonctions
et
.B shutdown
qui sont appellées, sans arguments, lorsque dnsmasq démarre ou s'arrête.
Il peut également fournir une fonction
.B tftp.
La méthode
La fonction
.B lease
reçoit les informations détaillées dans
.B --dhcp-script.
@@ -1301,6 +1620,16 @@ et
ainsi que
.B hostname
(le nom d'hôte) dans le cas d'IPv6.
La fonction
.B tftp
est appelée de la même façon que la fonction "lease", et la table contient les
labels
.B destination_address,
.B file_name
et
.B file_size
(respectivement "adresse de destination", "nom de fichier" et "taille de fichier").
.TP
.B --dhcp-scriptuser
Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
@@ -1367,7 +1696,7 @@ Si la gamme d'adresse est fournie sous la forme
qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et
inverses. C-à-d
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
est indentique à
est identique à
.B --domain=thekelleys.org.uk,192.168.0.0/24
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
La taille de réseau doit-être de 8, 16 ou 24 pour être valide.
@@ -1411,17 +1740,40 @@ Advertisement") sont activées, dnsmasq va annoncer un préfixe pour chaque
dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
la valeur d'adresse link-local appropriée parmi celles de la machine sur
laquelle tourne dnsmasq.
Les bits "managed address" sont positionnés, sauf pour un dhcp-range marqué
comme "ra-only" (annonce routeur uniquement). Dans ce cas le service d'annonce
routeur est rendu mais aucun service DHCPv6 n'est assuré, et les bits "managed
address" ne sont pas positionnés.
Par défaut, les bits "managed address" sont positionnés, et le bit "use SLAAC"
("utiliser SLAAC") est réinitialisé. Cela peut-être changé pour des
sous-réseaux donnés par le biais du mot clef de mode décris dans
.B --dhcp-range.
Les paramètres DNS du RFC6106 sont inclus dans les annonces. Par défaut,
l'adresse link-local appropriée parmi celles de la machine sur laquelle tourne
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[=<interface>]
.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). Voir dans la section NOTES les
informations relatives à la spécification de l'interface.
(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
@@ -1459,6 +1811,13 @@ Sans cela, en effet, l'accès de tous les fichiers du serveur pour lequel le
droit de lecture pour tout le monde est positionné ("world-readable") devient
possible par n'importe quel hôte sur le réseau.
.TP
.B --tftp-lowercase
Converti les noms de fichiers des requêtes TFTP en minuscules. Cela est utile
pour les requêtes effectuées depuis les machines Windows, dont les systèmes
de fichiers sont insensibles à la casse et pour lesquels la détermination
de la casse est parfois un peu aléatoire. A noter que le serveur tftp de
dnsmasq converti systématiquement les "\\" en "/" dans les noms de fichiers.
.TP
.B --tftp-max=<connexions>
Définit le nombre maximum de connexions TFTP simultanées autorisées. La valeur
par défaut est de 50. Lorsqu'un grand nombre de connexions TFTP est spécifié,
@@ -1722,50 +2081,166 @@ supprime la nécessité des associations statiques). Le paramètre
que le label "bootp", permettant un certain contrôle sur les options retournées
aux différentes classes d'hôtes.
Il est possible de spécifier un nom d'interface à
.B dhcp-range
sous la forme "interface:<nom d'interface>". La sémantique est comme suit :
Pour le DHCP, s'il existe une autre valeur de dhcp-range pour laquelle
_aucun_ nom d'interface n'est donné, alors le nom d'interface est ignoré
et dnsmasq se comporte comme si la partie spécifiant l'interface n'existait
pas, sinon le service DHCP n'est fourni qu'aux interfaces mentionnées dans
les déclarations dhcp-range. Pour le DNS, si il n'y a pas d'option
.B --interface
ou
.B --listen-address
, alors le comportement n'est pas impacté par la spécification d'interface. Si
l'une ou l'autre de ces options est présente, alors les interfaces mentionnées
dans les plages d'adresses dhcp-range sont rajoutées à la liste de celles
où le service DNS est assuré.
De manière similaire,
.B enable-tftp
peut prendre un nom d'interface, ce qui active le TFTP pour cette seule
interface, en ignorant les options
.B --interface
ou
.B --listen-address
De plus,
.B --tftp-secure
,
.B --tftp-unique-root
.SH CONFIGURATION EN TEMPS QUE SERVEUR FAISANT AUTORITÉ
.PP
Configurer dnsmasq pour agir en temps que serveur DNS faisant autorité est
compliqué par le fait que cela implique la configuration de serveurs DNS
externes pour mettre en place la délégation. Seront présentés ci-dessous trois
scénarios de complexité croissante. Le pré-requis pour chacun de ces scénarios
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
capable d'effectuer la délégation de la zone en question. Pour la première
partie de ces explications, nous allons appeller serveur.exemple.com
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
notre.zone.com la zone pour laquelle dnsmasq fait autorité.
La configuration la plus simple consiste en deux lignes de configuration,
sous la forme :
.nf
.B auth-server=serveur.exemple.com,eth0
.B auth-zone=notre.zone.com,1.2.3.0/24
.fi
ainsi que deux enregistrements dans le DNS externe :
.nf
serveur.exemple.com A 192.0.43.10
notre.zone.com NS serveur.exemple.com
.fi
eth0 est l'interface réseau externe sur laquelle dnsmasq écoute, dont l'adresse
IP (globalement accessible) est 192.0.43.10.
A noter que l'adresse IP externe peut parfaitement être dynamique (par exemple
attribuée par un FAI via DHCP ou PPP). Dans ce cas, l'enregistrement de type A
doit être lié à cet enregistrement dynamique par l'une ou l'autre des techniques
habituelles de système DNS dynamique.
Un exemple plus complexe mais en pratique plus utile correspond au cas où
l'adresse IP globalement accessible se trouve dans la zone pour laquelle
dnsmasq fait autorité, le plus souvent à la racine. Dans ce cas nous avons :
.nf
.B auth-server=notre.zone.com,eth0
.B auth-zone=notre.zone.com,1.2.3.0/24
.fi
.nf
notre.zone.com A 1.2.3.4
notre.zone.com NS our.zone.com
.fi
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
fait désormais autorité pour notre.zone.com, il doit également fournir cet
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
le biais d'une entrée dans
.B /etc/hosts
ou via un
.B --host-record.
.nf
.B auth-server=notre.zone.com,eth0
.B host-record=notre.zone.com,1.2.3.4
.B auth-zone=notre.zone.com,1.2.3.0/24
.fi
Si l'adresse externe est dynamique, l'adresse associée à notre.zone.com doit
être dérivée de l'interface correspondante. Cela peut être fait en utilisant
.B interface-name
Sous la forme :
.nf
.B auth-server=notre.zone.com,eth0
.B interface-name=notre.zone.com,eth0
.B auth-zone=notre.zone.com,1.2.3.0/24
.fi
La configuration finale rajoute à cette base un serveur DNS secondaire. Il
s'agit d'un autre serveur DNS qui apprend les données DNS de la zone en
effectuant un transfert de zone, et qui joue le rôle de serveur de secours
au cas où le serveur principal devenait inaccessible. La configuration
de ce serveur secondaire sort du cadre de cette page de manuel. Les éléments
de configuration à rajouter dans dnsmasq sont les simples :
.nf
.B auth-sec-servers=secondaire.monfai.com
.fi
et
.B --tftp-no-blocksize
sont ignorées pour les requêtes sur de telles interfaces. (une directive
.B --tftp-root
donnant le chemin de la racine et une interface doit-être fournie).
Ces règles peuvent paraître étrange à première vue, mais elles permettent
d'ajouter à la configuration de dnsmasq des lignes de configuration de la
forme "dhcp-range=interface:virt0,192.168.0.4,192.168.0.200" afin de fournir
un service DHCP et DNS sur cette interface, sans pour autant affecter les
services fournis sur d'autres interfaces, malgré l'absence de paramètres
"interface=<interface>" sur les autres lignes de configuration.
"enable-tftp=virt0" et "tftp-root=<root>,virt0" effectuent la même chose pour
TFTP.
L'idée de tout cela est de permettre l'addition de telles lignes
automatiquement par libvirt ou un système équivalent, sans perturbation
d'une configuration manuelle existant par ailleurs.
.nf
notre.zone.com NS secondaire.monfai.com
.fi
L'addition d'une option auth-sec-servers active les transferts de zone dans
dnsmasq, ce qui permet au serveur secondaire de venir collecter les données
DNS. Si vous souhaitez restreindre l'accès à ces données à des hôtes
spécifiques, vous pouvez le faire via :
.nf
.B auth-peer=<adresse IP du serveur secondaire>
.fi
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
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
1.2.3.0/24 :
.nf
3.2.1.in-addr.arpa NS notre.zone.com
.fi
Veuillez noter que pour l'instant, les zones inverses ne sont pas
disponibles dans les transferts de zone, donc il est inutile de configurer
de serveur secondaire pour la résolution inverse.
.PP
Lorsque dnsmasq est configuré en temps que serveur faisant autorité,
les données suivantes sont utilisées pour peupler la zone considérée :
.PP
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
, pour autant que les noms des enregistrements se trouvent dans la zone en
question.
.PP
.B --cname
pour peu que le nom soit dans le domaine. Si la cible du CNAME n'est
pas pleinement qualifiée, alors elle est qualifiée avec le nom de la
zone pour laquelle le serveur fait autorité.
.PP
Les adresses IPv4 et IPv6 extraites de /etc/hosts (et
.B --addn-hosts
) ainsi que les options
.B --host-record
fournissant des adresses situées dans l'un des sous-réseaux spécifiés dans
.B --auth-zone.
.PP
Adresses spécifiées par
.B --interface-name.
Dans ce cas, l'adresse n'est pas limitée à l'un des sous-réseaux donné dans
.B --auth-zone.
.PP
Les adresses de baux DHCP, si l'adresse est située dans l'un des sous-réseaux de
.B --auth-zone
OU dans une plage DHCP construite. Dans le mode par défaut, où le bail
DHCP a un nom non qualifié, et éventuellement pour un nom qualifié construit
via
.B --domain
, alors le nom dans la zone faisant autorité est construit à partir du nom
non qualifié et du nom de domaine de la zone. Cela peut on non être égal
celui fourni par
.B --domain.
Si l'option
.B --dhcp-fqdn
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
à la zone.
.SH CODES DE SORTIE
.PP

1430
po/de.po

File diff suppressed because it is too large Load Diff

1406
po/es.po

File diff suppressed because it is too large Load Diff

1474
po/fi.po

File diff suppressed because it is too large Load Diff

1271
po/fr.po

File diff suppressed because it is too large Load Diff

1338
po/id.po

File diff suppressed because it is too large Load Diff

1474
po/it.po

File diff suppressed because it is too large Load Diff

1266
po/no.po

File diff suppressed because it is too large Load Diff

1187
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1266
po/ro.po

File diff suppressed because it is too large Load Diff

810
src/auth.c Normal file
View File

@@ -0,0 +1,810 @@
/* dnsmasq is Copyright (c) 2000-2014 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_AUTH
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
struct addrlist *subnet;
for (subnet = zone->subnet; subnet; subnet = subnet->next)
{
if (!(subnet->flags & ADDRLIST_IPV6))
{
struct in_addr netmask, addr = addr_u->addr.addr4;
if (!(flag & F_IPV4))
continue;
netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
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->addr.addr.addr6, subnet->prefixlen))
return subnet;
#endif
}
return NULL;
}
static int filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
/* No zones specified, no filter */
if (!zone->subnet)
return 1;
return find_subnet(zone, flag, addr_u) != NULL;
}
int in_zone(struct auth_zone *zone, char *name, char **cut)
{
size_t namelen = strlen(name);
size_t domainlen = strlen(zone->domain);
if (cut)
*cut = NULL;
if (namelen >= domainlen &&
hostname_isequal(zone->domain, &name[namelen - domainlen]))
{
if (namelen == domainlen)
return 1;
if (name[namelen - domainlen - 1] == '.')
{
if (cut)
*cut = &name[namelen - domainlen - 1];
return 1;
}
}
return 0;
}
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;
int qtype, qclass;
int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0;
struct crec *crecp;
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
struct auth_zone *zone = NULL;
struct addrlist *subnet = NULL;
char *cut;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
struct interface_name *intr;
struct naptr *na;
struct all_addr addr;
struct cname *a;
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 */
/* now process each question, answers go in RRs after the question */
p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--)
{
unsigned short flag = 0;
int found = 0;
/* save pointer to name for copying into answers */
nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
if (qclass != C_IN)
{
auth = 0;
continue;
}
if (qtype == T_PTR)
{
if (!(flag = in_arpa_name_2_addr(name, &addr)))
continue;
if (!local_query)
{
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = find_subnet(zone, flag, &addr)))
break;
if (!zone)
{
auth = 0;
continue;
}
}
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 (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));
if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
{
char *p = strchr(name, '.');
if (p)
*p = 0; /* must be bare name */
/* add external domain */
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,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
{
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else
continue;
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
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)
{
auth = 0;
continue;
}
for (rec = daemon->mxnames; rec; rec = rec->next)
if (!rec->issrv && hostname_isequal(name, rec->name))
{
nxdomain = 0;
if (qtype == T_MX)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
anscount++;
}
}
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
if (rec->issrv && hostname_isequal(name, rec->name))
{
nxdomain = 0;
if (qtype == T_SRV)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
/* unlink first SRV record found */
if (!move)
{
move = rec;
*up = rec->next;
}
else
up = &rec->next;
}
else
up = &rec->next;
/* put first SRV record back at the end. */
if (move)
{
*up = move;
move->next = NULL;
}
for (txt = daemon->rr; txt; txt = txt->next)
if (hostname_isequal(name, txt->name))
{
nxdomain = 0;
if (txt->class == qtype)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && hostname_isequal(name, txt->name))
{
nxdomain = 0;
if (qtype == T_TXT)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (na = daemon->naptr; na; na = na->next)
if (hostname_isequal(name, na->name))
{
nxdomain = 0;
if (qtype == T_NAPTR)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
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 (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)))
{
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) )
{
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, &nameoffset,
T_CNAME, C_IN, "d", name))
anscount++;
goto cname_restart;
}
if (!cut)
{
nxdomain = 0;
if (qtype == T_SOA)
{
auth = soa = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
}
else if (qtype == T_AXFR)
{
struct iname *peers;
if (peer_addr->sa.sa_family == AF_INET)
peer_addr->in.sin_port = 0;
#ifdef HAVE_IPV6
else
peer_addr->in6.sin6_port = 0;
#endif
for (peers = daemon->auth_peers; peers; peers = peers->next)
if (sockaddr_isequal(peer_addr, &peers->addr))
break;
/* Refuse all AXFR unless --auth-sec-servers is set */
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
{
if (peer_addr->sa.sa_family == AF_INET)
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_IPV6
else
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
#endif
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
return 0;
}
auth = 1;
soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1;
found = 1;
axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
}
else if (qtype == T_NS)
{
auth = 1;
ns = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
}
}
if (!option_bool(OPT_DHCP_FQDN) && cut)
{
*cut = 0; /* remove domain part */
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if (crecp->flags & F_DHCP)
do
{
nxdomain = 0;
if ((crecp->flags & flag) &&
(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));
*cut = 0; /* remove domain part */
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
*cut = '.'; /* restore domain part */
}
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
do
{
nxdomain = 0;
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;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
if (!found)
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
}
/* Add auth section */
if (auth && zone)
{
char *authname;
int newoffset, offset = 0;
if (!subnet)
authname = zone->domain;
else
{
/* handle NS and SOA for PTR records */
authname = name;
if (!(subnet->flags & ADDRLIST_IPV6))
{
in_addr_t a = ntohl(subnet->addr.addr.addr4.s_addr) >> 8;
char *p = name;
if (subnet->prefixlen >= 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
}
#ifdef HAVE_IPV6
else
{
char *p = name;
int i;
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
{
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");
}
#endif
}
/* handle NS and SOA in auth section or for explicit queries */
newoffset = ansp - (unsigned char *)header;
if (((anscount == 0 && !ns) || soa) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
authname, daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{
offset = newoffset;
if (soa)
anscount++;
else
authcount++;
}
if (anscount != 0 || ns)
{
struct name_list *secondary;
newoffset = ansp - (unsigned char *)header;
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
{
if (offset == 0)
offset = newoffset;
if (ns)
anscount++;
else
authcount++;
}
if (!subnet)
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
if (add_resource_record(header, limit, &trunc, offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
{
if (ns)
anscount++;
else
authcount++;
}
}
if (axfr)
{
for (rec = daemon->mxnames; rec; rec = rec->next)
if (in_zone(zone, rec->name, &cut))
{
if (cut)
*cut = 0;
if (rec->issrv)
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
else
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
anscount++;
}
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->rr; txt; txt = txt->next)
if (in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (na = daemon->naptr; na; na = na->next)
if (in_zone(zone, na->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (in_zone(zone, intr->name, &cut))
{
struct addrlist *addrlist;
if (cut)
*cut = 0;
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))
{
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL,
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
anscount++;
}
cache_enumerate(1);
while ((crecp = cache_enumerate(0)))
{
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
(crecp->flags & F_FORWARD))
{
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
{
char *cache_name = cache_get_name(crecp);
if (!strchr(cache_name, '.') &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
{
qtype = T_A;
#ifdef HAVE_IPV6
if (crecp->flags & F_IPV6)
qtype = T_AAAA;
#endif
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
anscount++;
}
}
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) &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr))))
{
qtype = T_A;
#ifdef HAVE_IPV6
if (crecp->flags & F_IPV6)
qtype = T_AAAA;
#endif
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
anscount++;
}
}
}
}
/* repeat SOA as last record */
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
anscount++;
}
}
/* 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;
if (local_query)
{
/* set RA flag */
header->hb4 |= HB4_RA;
}
else
{
/* clear RA flag */
header->hb4 &= ~HB4_RA;
}
/* authoritive */
if (auth)
header->hb3 |= HB3_AA;
/* truncation */
if (trunc)
header->hb3 |= HB3_TC;
if ((auth || local_query) && nxdomain)
SET_RCODE(header, NXDOMAIN);
else
SET_RCODE(header, NOERROR); /* no error */
header->ancount = htons(anscount);
header->nscount = htons(authcount);
header->arcount = htons(0);
return ansp - (unsigned char *)header;
}
#endif

151
src/blockdata.c Normal file
View File

@@ -0,0 +1,151 @@
/* dnsmasq is Copyright (c) 2000-2014 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

184
src/bpf.c
View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,11 +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) \
@@ -32,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];
@@ -82,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__)
@@ -104,22 +119,35 @@ 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)
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;
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
if (addrs->ifa_broadaddr)
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
else
broadcast.s_addr = 0;
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
goto err;
}
#ifdef HAVE_IPV6
@@ -129,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)
@@ -144,12 +211,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, 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)
{
@@ -167,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)
@@ -291,6 +362,87 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
}
#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(time_t now)
{
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;
newaddress(now);
}
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));
}
newaddress(now);
}
}
#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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,6 +18,8 @@
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#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 */
@@ -29,20 +31,23 @@
#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 RUNFILE "/var/run/dnsmasq.pid"
#define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody"
#define CHGRP "dip"
#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" /* DBUS interface specifics */
#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 */
/* compile-time options: uncomment below to enable or do eg.
make COPTS=-DHAVE_BROKEN_RTC
@@ -92,12 +97,22 @@ HAVE_CONNTRACK
a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support.
HAVE_IPSET
define this to include the ability to selectively add resolved ip addresses
to given ipsets.
HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
NO_IPV6
NO_TFTP
NO_DHCP
NO_DHCP6
NO_SCRIPT
NO_LARGEFILE
NO_AUTH
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
@@ -111,6 +126,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 */
@@ -119,12 +139,21 @@ RESOLVFILE
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_SCRIPT
#define HAVE_AUTH
#define HAVE_IPSET
/* 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. */
@@ -157,7 +186,13 @@ RESOLVFILE
# endif
#endif
#ifndef RUNFILE
# if defined(__ANDROID__)
# define RUNFILE "/data/dnsmasq.pid"
# else
# define RUNFILE "/var/run/dnsmasq.pid"
# endif
#endif
/* platform dependent options: these are determined automatically below
@@ -167,11 +202,7 @@ HAVE_SOLARIS_NETWORK
define exactly one of these to alter interaction with kernel networking.
HAVE_GETOPT_LONG
defined when GNU-sty;e getopt_long available.
HAVE_ARC4RANDOM
defined if arc4random() available to get better security from DNS spoofs
by using really random ids (OpenBSD)
defined when GNU-style getopt_long available.
HAVE_SOCKADDR_SA_LEN
defined if struct sockaddr has sa_len field (*BSD)
@@ -181,7 +212,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
@@ -195,7 +225,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
@@ -210,7 +239,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__) || \
@@ -222,29 +250,26 @@ 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
#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
@@ -257,12 +282,12 @@ HAVE_SOCKADDR_SA_LEN
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
# define HAVE_IPV6
# define ADDRSTRLEN INET6_ADDRSTRLEN
#elif defined(INET_ADDRSTRLEN)
#else
# if !defined(INET_ADDRSTRLEN)
# define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
# endif
# undef HAVE_IPV6
# define ADDRSTRLEN INET_ADDRSTRLEN
#else
# undef HAVE_IPV6
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
#endif
@@ -301,6 +326,13 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_SCRIPT
#endif
#ifdef NO_AUTH
#undef HAVE_AUTH
#endif
#if defined(NO_IPSET)
#undef HAVE_IPSET
#endif
/* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
@@ -359,7 +391,20 @@ static char *compile_opts =
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack";
"conntrack "
#ifndef HAVE_IPSET
"no-"
#endif
"ipset "
#ifndef HAVE_AUTH
"no-"
#endif
"auth "
#ifndef HAVE_DNSSEC
"no-"
#endif
"DNSSEC";
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
#include <dbus/dbus.h>
const char* introspection_xml =
const char* introspection_xml_template =
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name=\"" DNSMASQ_PATH "\">\n"
@@ -29,7 +29,7 @@ const char* introspection_xml =
" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" </interface>\n"
" <interface name=\"" DNSMASQ_SERVICE "\">\n"
" <interface name=\"%s\">\n"
" <method name=\"ClearCache\">\n"
" </method>\n"
" <method name=\"GetVersion\">\n"
@@ -38,6 +38,12 @@ const char* introspection_xml =
" <method name=\"SetServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
" </method>\n"
" <method name=\"SetDomainServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"as\"/>\n"
" </method>\n"
" <method name=\"SetServersEx\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
" </method>\n"
" <signal name=\"DhcpLeaseAdded\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
@@ -56,6 +62,8 @@ const char* introspection_xml =
" </interface>\n"
"</node>\n";
static char *introspection_xml = NULL;
struct watch {
DBusWatch *watch;
struct watch *next;
@@ -83,33 +91,32 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
static void remove_watch(DBusWatch *watch, void *data)
{
struct watch **up, *w;
struct watch **up, *w, *tmp;
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
if (w->watch == watch)
{
*up = w->next;
free(w);
}
else
up = &(w->next);
for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
{
tmp = w->next;
if (w->watch == watch)
{
*up = tmp;
free(w);
}
else
up = &(w->next);
}
w = data; /* no warning */
}
static void dbus_read_servers(DBusMessage *message)
{
struct server *serv, *tmp, **up;
DBusMessageIter iter;
union mysockaddr addr, source_addr;
char *domain;
dbus_message_iter_init(message, &iter);
/* mark everything from DBUS */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_FROM_DBUS)
serv->flags |= SERV_MARK;
mark_servers(SERV_FROM_DBUS);
while (1)
{
@@ -169,6 +176,7 @@ static void dbus_read_servers(DBusMessage *message)
/* At the end */
break;
/* process each domain */
do {
if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
{
@@ -179,83 +187,189 @@ static void dbus_read_servers(DBusMessage *message)
domain = NULL;
if (!skip)
{
/* See if this is already there, and unmark */
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_FROM_DBUS) &&
(serv->flags & SERV_MARK))
{
if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
{
serv->flags &= ~SERV_MARK;
break;
}
if ((serv->flags & SERV_HAS_DOMAIN) &&
domain &&
hostname_isequal(domain, serv->domain))
{
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);
if (domain && !serv->domain)
{
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 (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;
}
}
}
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
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. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
cleanup_servers();
}
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
{
DBusMessageIter iter, array_iter, string_iter;
DBusMessage *error = NULL;
const char *addr_err;
char *dup = NULL;
if (!dbus_message_iter_init(message, &iter))
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
server_gone(serv);
*up = serv->next;
free(serv);
}
else
up = &serv->next;
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
}
/* check that the message contains an array of arrays */
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&iter) != (strings ? DBUS_TYPE_STRING : DBUS_TYPE_ARRAY)))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
strings ? "Expected array of string" : "Expected array of string arrays");
}
mark_servers(SERV_FROM_DBUS);
/* array_iter points to each "as" element in the outer array */
dbus_message_iter_recurse(&iter, &array_iter);
while (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_INVALID)
{
const char *str = NULL;
union mysockaddr addr, source_addr;
int flags = 0;
char interface[IF_NAMESIZE];
char *str_addr, *str_domain = NULL;
if (strings)
{
dbus_message_iter_get_basic(&array_iter, &str);
if (!str || !strlen (str))
{
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Empty string");
break;
}
/* dup the string because it gets modified during parsing */
if (dup)
free(dup);
if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
break;
strcpy(str_domain, str);
/* point to address part of old string for error message */
if ((str_addr = strrchr(str, '/')))
str = str_addr+1;
if ((str_addr = strrchr(str_domain, '/')))
{
if (*str_domain != '/' || str_addr == str_domain)
{
error = dbus_message_new_error_printf(message,
DBUS_ERROR_INVALID_ARGS,
"No domain terminator '%s'",
str);
break;
}
*str_addr++ = 0;
str_domain++;
}
else
{
str_addr = str_domain;
str_domain = NULL;
}
}
else
{
/* check the types of the struct and its elements */
if ((dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_STRING))
{
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected inner array of strings");
break;
}
/* string_iter points to each "s" element in the inner array */
dbus_message_iter_recurse(&array_iter, &string_iter);
if (dbus_message_iter_get_arg_type(&string_iter) != DBUS_TYPE_STRING)
{
/* no IP address given */
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected IP address");
break;
}
dbus_message_iter_get_basic(&string_iter, &str);
if (!str || !strlen (str))
{
error = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Empty IP address");
break;
}
/* dup the string because it gets modified during parsing */
if (dup)
free(dup);
if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
break;
strcpy(str_addr, str);
}
memset(&addr, 0, sizeof(addr));
memset(&source_addr, 0, sizeof(source_addr));
memset(&interface, 0, sizeof(interface));
/* parse the IP address */
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;
do {
if (str_domain)
{
if ((p = strchr(str_domain, '/')))
*p++ = 0;
}
else
p = NULL;
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
} while ((str_domain = p));
}
else
{
/* jump past the address to the domain list (if any) */
dbus_message_iter_next (&string_iter);
/* parse domains and add each server/domain pair to the list */
do {
str = NULL;
if (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING)
dbus_message_iter_get_basic(&string_iter, &str);
dbus_message_iter_next (&string_iter);
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
}
/* jump to next element in outer array */
dbus_message_iter_next(&array_iter);
}
cleanup_servers();
if (dup)
free(dup);
return error;
}
DBusHandlerResult message_handler(DBusConnection *connection,
@@ -263,39 +377,73 @@ DBusHandlerResult message_handler(DBusConnection *connection,
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"))
{
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
/* string length: "%s" provides space for termination zero */
if (!introspection_xml &&
(introspection_xml = whine_malloc(strlen(introspection_xml_template) + strlen(daemon->dbus_name))))
sprintf(introspection_xml, introspection_xml_template, daemon->dbus_name);
if (introspection_xml)
{
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
}
}
else if (strcmp(method, "GetVersion") == 0)
{
char *v = VERSION;
DBusMessage *reply = dbus_message_new_method_return(message);
reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
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);
new_servers = 1;
}
else if (strcmp(method, "SetDomainServers") == 0)
{
reply = dbus_read_servers_ex(message, 1);
new_servers = 1;
}
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 */
/* If no reply or no error, return nothing */
if (!reply)
reply = dbus_message_new_method_return(message);
if (reply)
{
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
return (DBUS_HANDLER_RESULT_HANDLED);
}
@@ -315,7 +463,7 @@ char *dbus_init(void)
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
NULL, NULL, NULL);
dbus_error_init (&dbus_error);
dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
dbus_bus_request_name (connection, daemon->dbus_name, 0, &dbus_error);
if (dbus_error_is_set (&dbus_error))
return (char *)dbus_error.message;
@@ -325,7 +473,7 @@ char *dbus_init(void)
daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
if ((message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, "Up")))
{
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
@@ -430,7 +578,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
else
return;
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, daemon->dbus_name, action_str)))
return;
dbus_message_iter_init_append(message, &args);

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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
@@ -91,6 +91,7 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
{
struct dhcp_netid *tagif = run_tag_if(tags);
struct dhcp_opt *opt;
struct dhcp_opt *tmp;
/* flag options which are valid with the current tag set (sans context tags) */
for (opt = opts; opt; opt = opt->next)
@@ -111,6 +112,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
last_tag->next = tags;
tagif = run_tag_if(context_tags);
/* reset stuff with tag:!<tag> which now matches. */
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
(opt->flags & DHOPT_TAGOK) &&
!match_netid(opt->netid, tagif, 0))
opt->flags &= ~DHOPT_TAGOK;
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
@@ -128,7 +136,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
@@ -138,6 +145,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
/* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
for (opt = opts; opt; opt = opt->next)
if (opt->flags & DHOPT_TAGOK)
for (tmp = opt->next; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt)
tmp->flags &= ~DHOPT_TAGOK;
return tagif;
}
@@ -239,38 +253,108 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
return 0;
}
void check_dhcp_hosts(int fatal)
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop.
Also check that FQDNs match the domain we are using. */
struct hwaddr_config *conf_addr;
struct dhcp_config *configs, *cp;
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
{
char *domain;
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;
}
if ((configs->flags & DHOPT_BANK) || fatal)
{
for (cp = configs->next; cp; cp = cp->next)
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
{
if (fatal)
die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF);
else
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR;
}
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
configs->domain = domain;
}
}
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)
@@ -282,7 +366,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
restore the status-quo ante first. */
struct dhcp_config *config;
struct dhcp_config *config, *conf_tmp;
struct crec *crec;
int prot = AF_INET;
@@ -315,16 +399,17 @@ 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 && !config_find_by_address(configs, crec->addr.addr.addr.addr4))
if (prot == AF_INET &&
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
{
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
@@ -332,7 +417,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0))
if (prot == AF_INET6 &&
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
{
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
@@ -358,93 +444,57 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct dhcp_context *context;
struct iname *tmp;
/* 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.
(void)prefix;
(void)scope;
(void)dad;
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.
*/
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
struct irec *iface, *found;
struct iname *if_tmp;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!daemon->if_names)
return NULL;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
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;
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
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)
return NULL; /* more than one. */
}
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
if (found)
return found->name;
if (!context)
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
return NULL;
}
void join_multicast(void)
void bindtodevice(char *device, int fd)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
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
static const struct opttab_t {
char *name;
u16 val, size;
@@ -488,15 +538,15 @@ static const struct opttab_t {
{ "x-windows-fs", 48, OT_ADDR_LIST },
{ "x-windows-dm", 49, OT_ADDR_LIST },
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
{ "lease-time", 51, OT_INTERNAL | OT_DEC },
{ "lease-time", 51, OT_INTERNAL | OT_TIME },
{ "option-overload", 52, OT_INTERNAL },
{ "message-type", 53, OT_INTERNAL | OT_DEC },
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_INTERNAL | OT_DEC},
{ "T2", 59, OT_INTERNAL | OT_DEC},
{ "T1", 58, OT_INTERNAL | OT_TIME},
{ "T2", 59, OT_INTERNAL | OT_TIME},
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
@@ -547,6 +597,7 @@ static const struct opttab_t opttab6[] = {
{ "nis-domain", 29, OT_RFC1035_NAME },
{ "nis+-domain", 30, OT_RFC1035_NAME },
{ "sntp-server", 31, OT_ADDR_LIST },
{ "information-refresh-time", 32, OT_TIME },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
@@ -580,11 +631,13 @@ void display_opts6(void)
}
#endif
u16 lookup_dhcp_opt(int prot, char *name)
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;
@@ -593,18 +646,19 @@ u16 lookup_dhcp_opt(int prot, char *name)
t = opttab;
for (i = 0; t[i].name; i++)
if (!(t[i].size & OT_INTERNAL) &&
strcasecmp(t[i].name, name) == 0)
if (strcasecmp(t[i].name, name) == 0)
return t[i].val;
return 0;
return -1;
}
u16 lookup_dhcp_len(int prot, u16 val)
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;
@@ -614,14 +668,9 @@ u16 lookup_dhcp_len(int prot, u16 val)
for (i = 0; t[i].name; i++)
if (val == t[i].val)
{
if (t[i].size & OT_INTERNAL)
return 0;
return t[i].size & ~OT_DEC;
}
return 0;
return t[i].size & ~OT_DEC;
return 0;
}
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
@@ -711,14 +760,17 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
}
}
#endif
else if ((ot[o].size & OT_DEC) && opt_len != 0)
else if ((ot[o].size & (OT_DEC | OT_TIME)) && opt_len != 0)
{
unsigned int dec = 0;
for (i = 0; i < opt_len; i++)
dec = (dec << 8) | val[i];
sprintf(buf, "%u", dec);
if (ot[o].size & OT_TIME)
prettyprint_time(buf, dec);
else
sprintf(buf, "%u", dec);
}
else
nodecode = 1;
@@ -745,4 +797,109 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
}
void log_context(int family, struct dhcp_context *context)
{
/* Cannot use dhcp_buff* for RA contexts */
void *start = &context->start;
void *end = &context->end;
char *template = "", *p = daemon->namebuff;
*p = 0;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
struct in6_addr subnet = context->start6;
if (!(context->flags & CONTEXT_TEMPLATE))
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
start = &context->start6;
end = &context->end6;
}
#endif
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _(", prefix deprecated"));
else
{
p += sprintf(p, _(", lease time "));
prettyprint_time(p, context->lease_time);
p += strlen(p);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_CONSTRUCTED)
{
char ifrn_name[IFNAMSIZ];
template = p;
p += sprintf(p, ", ");
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 && !(context->flags & CONTEXT_RA_STATELESS))
{
template = p;
p += sprintf(p, ", ");
sprintf(p, "template for %s", context->template_interface);
}
#endif
if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET))
{
#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",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
}
#ifdef HAVE_DHCP6
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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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;
};
@@ -28,10 +30,12 @@ struct match_param {
struct in_addr netmask, broadcast, addr;
};
static int complete_context(struct in_addr local, int if_index,
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,
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)
{
@@ -65,14 +69,22 @@ static int make_fd(int port)
/* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 67. That's OK if they serve different networks.
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
if (option_bool(OPT_NOWILD))
Need to set REUSEADDR|REUSEPORT to make this posible.
Handle the case that REUSEPORT is defined, but the kernel doesn't
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = 0;
#ifdef SO_REUSEPORT
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
#else
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
}
@@ -116,9 +128,7 @@ void dhcp_init(void)
/* Make BPF raw send socket */
init_bpf();
#endif
check_dhcp_hosts(1);
#endif
}
void dhcp_packet(time_t now, int pxe_fd)
@@ -126,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;
@@ -244,65 +256,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 && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
break;
if (!context)
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))
{
/* 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;
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;
}
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
/* 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, 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);
@@ -323,7 +356,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);
@@ -336,7 +369,7 @@ 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;
@@ -371,7 +404,8 @@ void dhcp_packet(time_t now, int pxe_fd)
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);
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)
@@ -413,12 +447,14 @@ void dhcp_packet(time_t now, int pxe_fd)
}
/* check against secondary interface addresses */
static int check_listen_addrs(struct in_addr local, int if_index,
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct match_param *param = vparam;
struct iname *tmp;
(void) label;
if (if_index == param->ind)
{
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
@@ -446,11 +482,14 @@ static int check_listen_addrs(struct in_addr local, int if_index,
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
static int complete_context(struct in_addr local, int if_index,
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;
for (context = daemon->dhcp; context; context = context->next)
{
@@ -493,6 +532,15 @@ static int complete_context(struct in_addr local, int if_index,
}
}
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;
}
@@ -702,89 +750,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");
@@ -986,5 +951,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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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
@@ -54,9 +54,17 @@
#define OPTION6_RECONFIGURE_MSG 19
#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. */
/* #define OPTION6_PREFIX_CLASS 99 */
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,33 +18,68 @@
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct iface_param {
struct dhcp_context *current;
struct in6_addr fallback;
int ind;
struct dhcp_relay *relay;
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
int ind, addr_match;
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
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)
{
int fd;
struct sockaddr_in6 saddr;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
int oneopt = 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
!fix_fd(fd) ||
!set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
/* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 547. That's OK if they serve different networks.
Need to set REUSEADDR|REUSEPORT to make this posible.
Handle the case that REUSEPORT is defined, but the kernel doesn't
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
}
memset(&saddr, 0, sizeof(saddr));
#ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin6_len = sizeof(struct sockaddr_in6);
@@ -62,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;
@@ -71,11 +107,13 @@ void dhcp6_packet(time_t now)
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
struct sockaddr_in6 from;
struct all_addr dest;
ssize_t sz;
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);
@@ -98,49 +136,88 @@ void dhcp6_packet(time_t now)
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
dest.addr.addr6 = p.p->ipi6_addr;
dst_addr = p.p->ipi6_addr;
}
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
break;
if (!context)
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp6; context; context = context->next)
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
{
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
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.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);
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);
}
parm.current = NULL;
parm.ind = if_index;
memset(&parm.fallback, 0, IN6ADDRSZ);
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
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
@@ -154,43 +231,161 @@ void dhcp6_packet(time_t now)
}
}
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;
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 dad, void *vparam)
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 */
(void)dad;
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)
{
/* 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 (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))
{
context->current = param->current;
param->current = context;
context->local6 = *local;
/* 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)
@@ -206,8 +401,8 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
return NULL;
}
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
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
a particular hwaddr/clientid/hostname in our configuration.
@@ -223,23 +418,27 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
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 = 0, 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 <= 1; pass++)
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
continue;
else if (!match_netid(c->filter, netids, pass))
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
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */
addr = start;
@@ -256,7 +455,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
{
*ans = c->start6;
setaddr6part (ans, addr);
return 1;
return c;
}
addr++;
@@ -266,13 +465,15 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
} while (addr != start);
}
return 0;
return NULL;
}
/* can dynamically allocate addr */
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
struct dhcp_netid *netids,
int plain_range)
{
u64 start, end, addr = addr6part(taddr);
struct dhcp_context *tmp;
@@ -282,98 +483,59 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
start = addr6part(&tmp->start6);
end = addr6part(&tmp->end6);
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
is_same_net6(&context->start6, taddr, context->prefix) &&
is_same_net6(&context->end6, taddr, context->prefix) &&
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, 1))
match_netid(tmp->filter, netids, plain_range))
return tmp;
}
return NULL;
}
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
/* address OK if configured */
struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
int plain_range)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
if (!(tmp = address6_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
!(tmp->flags & CONTEXT_PROXY))
break;
}
/* Only one context allowed now */
if (tmp)
tmp->current = NULL;
return tmp;
}
static int is_addr_in_context6(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_ADDR6))
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_addr_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_addr_in_context6(context, config))
return config;
for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
match_netid(tmp->filter, netids, plain_range))
return tmp;
return NULL;
}
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
{
if (!config || !(config->flags & CONFIG_ADDR6))
return 0;
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
{
*addr = context->start6;
setaddr6part(addr, addr6part(&config->addr6));
return 1;
}
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
{
*addr = config->addr6;
return 1;
}
return 0;
}
void make_duid(time_t now)
{
(void)now;
if (daemon->duid_config)
{
unsigned char *p;
@@ -386,8 +548,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);
@@ -405,27 +573,216 @@ 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;
}
struct cparam {
time_t now;
int newone, newname;
};
static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct in6_addr start6, end6;
struct dhcp_context *template, *context;
(void)scope;
(void)flags;
(void)valid;
(void)preferred;
struct cparam *param = vparam;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
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, template->prefix) &&
is_same_net6(local, &template->end6, template->prefix))
{
template->if_index = if_index;
template->local6 = *local;
}
}
else if (wildcard_match(template->template_interface, ifrn_name) &&
template->prefix >= prefix)
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
end6 = *local;
setaddr6part(&end6, addr6part(&template->end6));
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
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;
}
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
{
*context = *template;
context->start6 = start6;
context->end6 = end6;
context->flags &= ~CONTEXT_TEMPLATE;
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->saved_valid = 0;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
ra_start_unsolicted(param->now, context);
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
/* Will need to add new putative SLAAC addresses to existing leases */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
log_context(AF_INET6, context);
}
}
return 1;
}
void dhcp_construct_contexts(time_t now)
{
static int active = 0;
struct dhcp_context *context, *tmp, **up;
struct cparam param;
param.newone = 0;
param.newname = 0;
param.now = now;
/* Various calls that we make may end up calling iface_enumerate(), which can then
call us again, We're NOT re-entrant, so ignore a second invokation. */
if (active)
return;
active = 1;
for (context = daemon->dhcp6; context; context = context->next)
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 && !(context->flags & CONTEXT_OLD))
{
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;
}
if (param.newone)
{
if (daemon->dhcp || daemon->doing_dhcp6)
{
if (param.newname)
lease_update_slaac(now);
lease_update_file(now);
}
else
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
}
active = 0;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,25 +36,48 @@
#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;
@@ -73,6 +96,8 @@ struct dns_header {
#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
@@ -112,3 +137,8 @@ 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))

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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
@@ -50,7 +50,13 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
char *bound_device = NULL;
int did_bind = 0;
#endif
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
struct dhcp_context *context;
struct dhcp_relay *relay;
#endif
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -75,14 +81,28 @@ int main (int argc, char **argv)
umask(022); /* known umask, create leases and pid files as 0644 */
read_opts(argc, argv, compile_opts);
if (daemon->edns_pktsz < PACKETSZ)
daemon->edns_pktsz = PACKETSZ;
#ifdef HAVE_DNSSEC
/* Enforce min packet big enough for DNSSEC */
if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
daemon->edns_pktsz = EDNS_PKTSZ;
#endif
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
daemon->packet = safe_malloc(daemon->packet_buff_sz);
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
daemon->keyname = safe_malloc(MAXDNAME);
daemon->workspacename = safe_malloc(MAXDNAME);
}
#endif
#ifdef HAVE_DHCP
if (!daemon->lease_file)
@@ -114,10 +134,31 @@ int main (int argc, char **argv)
set_option_bool(OPT_NOWILD);
}
# endif
/* -- bind-dynamic not supported on !Linux, fall back to --bind-interfaces */
if (option_bool(OPT_CLEVERBIND))
{
bind_fallback = 1;
set_option_bool(OPT_NOWILD);
reset_option_bool(OPT_CLEVERBIND);
}
#endif
if (option_bool(OPT_DNSSEC_VALID))
{
#ifdef HAVE_DNSSEC
if (!daemon->ds)
die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
if (daemon->cachesize < CACHESIZ)
die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
#else
die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
#endif
}
#ifndef HAVE_TFTP
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
if (option_bool(OPT_TFTP))
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
#endif
@@ -139,89 +180,139 @@ int main (int argc, char **argv)
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
#endif
#ifndef HAVE_AUTH
if (daemon->authserver)
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
/* Create a serial at startup if not configured. */
if (daemon->authinterface && daemon->soa_sn == 0)
#ifdef HAVE_BROKEN_RTC
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
#else
daemon->soa_sn = now;
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
daemon->doing_ra = option_bool(OPT_RA);
for (context = daemon->dhcp6; context; context = context->next)
{
if (context->flags & CONTEXT_DHCP)
daemon->doing_dhcp6 = 1;
if (context->flags & CONTEXT_RA)
daemon->doing_ra = 1;
#if !defined(HAVE_LINUX_NETWORK) && !defined(HAVE_BSD_NETWORK)
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
#endif
}
}
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
{
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now);
if (daemon->dhcp)
dhcp_init();
if (daemon->dhcp || daemon->doing_dhcp6)
lease_init(now);
}
if (daemon->dhcp || daemon->relay4)
dhcp_init();
# ifdef HAVE_DHCP6
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
if (daemon->ra_contexts || option_bool(OPT_RA))
{
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
struct dhcp_context *context;
if (!daemon->ra_contexts)
daemon->ra_contexts = daemon->dhcp6;
else
{
for (context = daemon->ra_contexts; context->next; context = context->next);
context->next = daemon->dhcp6;
}
ra_init(now);
}
if (daemon->dhcp6)
if (daemon->doing_ra || daemon->doing_dhcp6 || daemon->relay6)
ra_init(now);
if (daemon->doing_dhcp6 || daemon->relay6)
dhcp6_init();
# endif
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
#ifdef HAVE_IPSET
if (daemon->ipsets)
ipset_init();
#endif
#if defined(HAVE_LINUX_NETWORK)
netlink_init();
#elif defined(HAVE_BSD_NETWORK)
route_init();
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces(now);
#endif
if (!enumerate_interfaces())
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
if (option_bool(OPT_NOWILD))
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
create_bound_listeners(1);
if (!option_bool(OPT_CLEVERBIND))
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
if (!if_tmp->used)
{
prettyprint_addr(&if_tmp->addr, daemon->namebuff);
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
}
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
/* after enumerate_interfaces() */
bound_device = whichdevice();
if (daemon->dhcp)
{
if (!daemon->relay4 && bound_device)
{
bindtodevice(bound_device, daemon->dhcpfd);
did_bind = 1;
}
if (daemon->enable_pxe && bound_device)
{
bindtodevice(bound_device, daemon->pxefd);
did_bind = 1;
}
}
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
{
bindtodevice(bound_device, daemon->dhcp6fd);
did_bind = 1;
}
#endif
}
else
create_wildcard_listeners();
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
join_multicast(1);
/* After netlink_init() and before create_helper() */
lease_make_duid(now);
#endif
if (daemon->port != 0)
cache_init();
{
cache_init();
#ifdef HAVE_DNSSEC
blockdata_init();
#endif
}
if (option_bool(OPT_DBUS))
#ifdef HAVE_DBUS
@@ -306,7 +397,7 @@ int main (int argc, char **argv)
piperead = pipefd[0];
pipewrite = pipefd[1];
/* prime the pipe to load stuff first time. */
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
send_event(pipewrite, EVENT_INIT, 0, NULL);
err_pipe[1] = -1;
@@ -363,15 +454,48 @@ int main (int argc, char **argv)
/* write pidfile _after_ forking ! */
if (daemon->runfile)
{
FILE *pidfile;
int fd, err = 0;
sprintf(daemon->namebuff, "%d\n", (int) getpid());
/* Explanation: Some installations of dnsmasq (eg Debian/Ubuntu) locate the pid-file
in a directory which is writable by the non-privileged user that dnsmasq runs as. This
allows the daemon to delete the file as part of its shutdown. This is a security hole to the
extent that an attacker running as the unprivileged user could replace the pidfile with a
symlink, and have the target of that symlink overwritten as root next time dnsmasq starts.
The folowing code first deletes any existing file, and then opens it with the O_EXCL flag,
ensuring that the open() fails should there be any existing file (because the unlink() failed,
or an attacker exploited the race between unlink() and open()). This ensures that no symlink
attack can succeed.
Any compromise of the non-privileged user still theoretically allows the pid-file to be
replaced whilst dnsmasq is running. The worst that could allow is that the usual
"shutdown dnsmasq" shell command could be tricked into stopping any other process.
Note that if dnsmasq is started as non-root (eg for testing) it silently ignores
failure to write the pid-file.
*/
unlink(daemon->runfile);
/* only complain if started as root */
if ((pidfile = fopen(daemon->runfile, "w")))
if ((fd = open(daemon->runfile, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH)) == -1)
{
fprintf(pidfile, "%d\n", (int) getpid());
fclose(pidfile);
/* only complain if started as root */
if (getuid() == 0)
err = 1;
}
else if (getuid() == 0)
else
{
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
err = 1;
while (!err && close(fd) == -1)
if (!retry_send())
err = 1;
}
if (err)
{
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
_exit(0);
@@ -417,8 +541,9 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK)
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
if (is_dad_listeners())
ports because of DAD, or we're doing it dynamically,
we need CAP_NET_BIND_SERVICE too. */
if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
data->effective = data->permitted = data->inheritable =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
@@ -466,7 +591,7 @@ int main (int argc, char **argv)
}
#ifdef HAVE_LINUX_NETWORK
if (is_dad_listeners())
if (is_dad_listeners() || option_bool(OPT_CLEVERBIND))
data->effective = data->permitted =
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
else
@@ -490,6 +615,34 @@ int main (int argc, char **argv)
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
#endif
#ifdef HAVE_TFTP
if (option_bool(OPT_TFTP))
{
DIR *dir;
struct tftp_prefix *p;
if (daemon->tftp_prefix)
{
if (!((dir = opendir(daemon->tftp_prefix))))
{
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
_exit(0);
}
closedir(dir);
}
for (p = daemon->if_prefix; p; p = p->next)
{
if (!((dir = opendir(p->prefix))))
{
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
_exit(0);
}
closedir(dir);
}
}
#endif
if (daemon->port == 0)
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
else if (daemon->cachesize != 0)
@@ -509,12 +662,29 @@ int main (int argc, char **argv)
}
#endif
if (option_bool(OPT_LOCAL_SERVICE))
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
if (option_bool(OPT_DNSSEC_TIME))
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
}
#endif
if (log_err != 0)
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
daemon->log_file, strerror(log_err));
if (bind_fallback)
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
if (option_bool(OPT_NOWILD))
warn_bound_listeners();
warn_int_names();
if (!option_bool(OPT_NOWILD))
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
@@ -532,67 +702,41 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
if (daemon->ra_contexts)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
{
struct dhcp_context *dhcp_tmp;
int family = AF_INET;
dhcp_tmp = daemon->dhcp;
#ifdef HAVE_DHCP6
again:
#endif
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6;
}
#endif
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_RA_NAME) ?
_("router advertisement with DHCPv4-derived names on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
_("router advertisement only on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"),
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
}
#ifdef HAVE_DHCP6
if (family == AF_INET)
{
family = AF_INET6;
if (daemon->ra_contexts)
dhcp_tmp = daemon->ra_contexts;
else
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
for (context = daemon->dhcp; context; context = context->next)
log_context(AF_INET, context);
}
#endif
for (relay = daemon->relay4; relay; relay = relay->next)
log_relay(AF_INET, relay);
# ifdef HAVE_DHCP6
for (context = daemon->dhcp6; context; context = context->next)
log_context(AF_INET6, context);
for (relay = daemon->relay6; relay; relay = relay->next)
log_relay(AF_INET6, relay);
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (option_bool(OPT_RA))
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
# endif
# ifdef HAVE_LINUX_NETWORK
if (did_bind)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
# endif
/* after dhcp_contruct_contexts */
if (daemon->dhcp || daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
#ifdef HAVE_TFTP
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
if (option_bool(OPT_TFTP))
{
#ifdef FD_SETSIZE
if (FD_SETSIZE < (unsigned)max_fd)
@@ -683,7 +827,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->relay4)
{
FD_SET(daemon->dhcpfd, &rset);
bump_maxfd(daemon->dhcpfd, &maxfd);
@@ -696,24 +840,27 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
if (daemon->doing_dhcp6 || daemon->relay6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
if (daemon->ra_contexts)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
}
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
#endif
#ifdef HAVE_LINUX_NETWORK
#if defined(HAVE_LINUX_NETWORK)
FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd);
#elif defined(HAVE_BSD_NETWORK)
FD_SET(daemon->routefd, &rset);
bump_maxfd(daemon->routefd, &maxfd);
#endif
FD_SET(piperead, &rset);
bump_maxfd(piperead, &maxfd);
@@ -754,19 +901,26 @@ int main (int argc, char **argv)
now = dnsmasq_time();
check_log_writer(&wset);
/* prime. */
enumerate_interfaces(1);
/* Check the interfaces to see if any have exited DAD state
and if so, bind the address. */
if (is_dad_listeners())
{
enumerate_interfaces();
enumerate_interfaces(0);
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
create_bound_listeners(0);
warn_bound_listeners();
}
#ifdef HAVE_LINUX_NETWORK
#if defined(HAVE_LINUX_NETWORK)
if (FD_ISSET(daemon->netlinkfd, &rset))
netlink_multicast();
netlink_multicast(now);
#elif defined(HAVE_BSD_NETWORK)
if (FD_ISSET(daemon->routefd, &rset))
route_sock(now);
#endif
/* Check for changes to resolv files once per second max. */
@@ -805,7 +959,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->relay4)
{
if (FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now, 0);
@@ -814,14 +968,11 @@ int main (int argc, char **argv)
}
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
if (FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
}
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
# ifdef HAVE_SCRIPT
@@ -963,6 +1114,9 @@ static void fatal_event(struct event_desc *ev, char *msg)
case EVENT_LUA_ERR:
die(_("failed to load Lua script: %s"), msg, EC_MISC);
case EVENT_TFTP_ERR:
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
}
}
@@ -970,7 +1124,7 @@ static void async_event(int pipe, time_t now)
{
pid_t p;
struct event_desc ev;
int i;
int i, check = 0;
char *msg;
/* NOTE: the memory used to return msg is leaked: use msgs in events only
@@ -980,12 +1134,36 @@ static void async_event(int pipe, time_t now)
switch (ev.event)
{
case EVENT_RELOAD:
clear_cache_and_reload(now);
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
reload_servers(daemon->resolv_files->name);
check_servers();
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
reset_option_bool(OPT_DNSSEC_TIME);
}
#endif
/* fall through */
case EVENT_INIT:
clear_cache_and_reload(now);
if (daemon->port != 0)
{
if (daemon->resolv_files && option_bool(OPT_NO_POLL))
{
reload_servers(daemon->resolv_files->name);
check = 1;
}
if (daemon->servers_file)
{
read_servers_file();
check = 1;
}
if (check)
check_servers();
}
#ifdef HAVE_DHCP
rerun_scripts();
#endif
@@ -998,13 +1176,13 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
lease_prune(NULL, now);
lease_update_file(now);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
#endif
@@ -1157,30 +1335,27 @@ void poll_resolv(int force, int do_reload, time_t now)
void clear_cache_and_reload(time_t now)
{
(void)now;
if (daemon->port != 0)
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();
reread_dhcp();
dhcp_update_configs(daemon->dhcp_conf);
check_dhcp_hosts(0);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
send_alarm(periodic_ra(now), now);
#endif
#endif
}
@@ -1204,7 +1379,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
/* will we be able to get memory? */
if (daemon->port != 0)
get_new_frec(now, &wait);
get_new_frec(now, &wait, 0);
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
{
@@ -1281,36 +1456,82 @@ static void check_dns_listeners(fd_set *set, time_t now)
if (listener->tcpfd != -1 && FD_ISSET(listener->tcpfd, set))
{
int confd;
int confd, client_ok = 1;
struct irec *iface = NULL;
pid_t p;
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
if (confd == -1)
continue;
if (option_bool(OPT_NOWILD))
iface = listener->iface;
else
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
{
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
/* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as
the local address of the TCP connection, then looking to see if that's
an allowed interface. As a side effect, we get the netmask of the
interface too, for localisation. */
/* interface may be new since startup */
if (enumerate_interfaces() &&
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr))
break;
close(confd);
continue;
}
if (!iface)
/* Make sure that the interface list is up-to-date.
We do this here as we may need the results below, and
the DNS code needs them for --interface-name stuff.
Multiple calls to enumerate_interfaces() per select loop are
inhibited, so calls to it in the child process (which doesn't select())
have no effect. This avoids two processes reading from the same
netlink fd and screwing the pooch entirely.
*/
enumerate_interfaces(0);
if (option_bool(OPT_NOWILD))
iface = listener->iface; /* May be NULL */
else
{
int if_index;
char intr_name[IF_NAMESIZE];
/* if we can find the arrival interface, check it's one that's allowed */
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
indextoname(listener->tcpfd, if_index, intr_name))
{
struct all_addr addr;
addr.addr.addr4 = tcp_addr.in.sin_addr;
#ifdef HAVE_IPV6
if (tcp_addr.sa.sa_family == AF_INET6)
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
#endif
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->index == if_index)
break;
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
client_ok = 0;
}
if (option_bool(OPT_CLEVERBIND))
iface = listener->iface; /* May be NULL */
else
{
/* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as
the local address of the TCP connection, then looking to see if that's
an allowed interface. As a side effect, we get the netmask of the
interface too, for localisation. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr))
break;
if (!iface)
client_ok = 0;
}
}
if (!client_ok)
{
shutdown(confd, SHUT_RDWR);
close(confd);
@@ -1336,7 +1557,20 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff;
struct server *s;
int flags;
struct in_addr netmask;
int auth_dns;
if (iface)
{
netmask = iface->netmask;
auth_dns = iface->dns_auth;
}
else
{
netmask.s_addr = 0;
auth_dns = 0;
}
#ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
terminate the process. */
@@ -1354,7 +1588,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
shutdown(confd, SHUT_RDWR);
close(confd);
@@ -1467,7 +1701,7 @@ int icmp_ping(struct in_addr addr)
set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
@@ -1486,8 +1720,8 @@ int icmp_ping(struct in_addr addr)
check_dns_listeners(&rset, now);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
#ifdef HAVE_TFTP

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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-2012 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2014 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
@@ -159,6 +163,8 @@ struct event_desc {
#define EVENT_LOG_ERR 17
#define EVENT_FORK_ERR 18
#define EVENT_LUA_ERR 19
#define EVENT_TFTP_ERR 20
#define EVENT_INIT 21
/* Exit codes. */
#define EC_GOOD 0
@@ -212,12 +218,24 @@ 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
#define OPT_RA 37
#define OPT_LAST 38
#define OPT_TFTP_LC 38
#define OPT_CLEVERBIND 39
#define OPT_TFTP 40
#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_LAST 50
/* 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. */
@@ -230,6 +248,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;
};
@@ -257,10 +281,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;
};
@@ -272,8 +305,38 @@ 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
struct addrlist {
struct all_addr addr;
int flags, prefixlen;
struct addrlist *next;
};
#define AUTH6 1
#define AUTH4 2
struct auth_zone {
char *domain;
struct auth_name_list {
char *name;
int flags;
struct auth_name_list *next;
} *interface_names;
struct addrlist *subnet;
struct auth_zone *next;
};
struct host_record {
struct name_list {
char *name;
@@ -289,6 +352,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;
};
@@ -297,17 +362,43 @@ union bigname {
union bigname *next; /* freelist */
};
struct blockdata {
struct blockdata *next;
unsigned char key[KEYBLOCK_LEN];
};
struct crec {
struct crec *next, *prev, *hash_next;
time_t ttd; /* time to die */
int uid;
/* union is 16 bytes when doing IPv6, 8 bytes on 32 bit machines without IPv6 */
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 blockdata *keydata;
unsigned short keylen, flags, keytag;
unsigned char algo;
} 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 class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
unsigned int uid;
unsigned short flags;
union {
char sname[SMALLDNAME];
@@ -328,14 +419,30 @@ struct crec {
#define F_BIGNAME (1u<<9)
#define F_NXDOMAIN (1u<<10)
#define F_CNAME (1u<<11)
#define F_NOERR (1u<<12)
#define F_DNSKEY (1u<<12)
#define F_CONFIG (1u<<13)
#define F_DS (1u<<14)
#define F_DNSSECOK (1u<<15)
/* below here are only valid as args to log_query: cache
entries are limited to 16 bits */
#define F_UPSTREAM (1u<<16)
#define F_RRNAME (1u<<17)
#define F_SERVER (1u<<18)
#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)
/* 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,
@@ -349,6 +456,12 @@ union mysockaddr {
#endif
};
/* 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. */
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
@@ -362,6 +475,7 @@ 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 */
struct serverfd {
int fd;
@@ -385,17 +499,23 @@ struct server {
struct server *next;
};
struct ipsets {
char **sets;
char *domain;
struct ipsets *next;
};
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, mtu, done, dad;
char *name;
int tftp_ok, dhcp_ok, mtu, done, warned, dad, dns_auth, index, multicast_done, found;
char *name;
struct irec *next;
};
struct listener {
int fd, tcpfd, tftpfd, family;
struct irec *iface; /* only valid for non-wildcard */
struct irec *iface; /* only sometimes valid for non-wildcard */
struct listener *next;
};
@@ -403,7 +523,7 @@ struct listener {
struct iname {
char *name;
union mysockaddr addr;
int isloop, used;
int used;
struct iname *next;
};
@@ -422,11 +542,38 @@ struct hostsfile {
struct hostsfile *next;
int flags;
char *fname;
int index; /* matches to cache entries for logging */
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_NEED_DS_NEG 10
#define STAT_CHASE_CNAME 11
#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
#ifdef HAVE_DNSSEC
#define HASH_SIZE 20 /* SHA-1 digest size */
#else
#define HASH_SIZE sizeof(int)
#endif
struct frec {
union mysockaddr source;
@@ -439,8 +586,15 @@ struct frec {
unsigned int iface;
unsigned short orig_id, new_id;
int fd, forwardall, flags;
unsigned int crc;
time_t time;
unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC
int class, work_counter;
struct blockdata *stash; /* Saved reply, whilst we validate */
size_t stash_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;
};
@@ -451,7 +605,7 @@ struct frec {
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
#define OT_DEC 0x0400
#define OT_TIME 0x0200
/* actions in the daemon->helper RPC */
#define ACTION_DEL 1
@@ -479,19 +633,22 @@ 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;
#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;
} *slaac_address;
int vendorclass_count;
#endif
struct dhcp_lease *next;
};
@@ -548,6 +705,7 @@ struct dhcp_config {
#define CONFIG_DECLINED 1024 /* address declined by client */
#define CONFIG_BANK 2048 /* from dhcp hosts file */
#define CONFIG_ADDR6 4096
#define CONFIG_WILDCARD 8192
struct dhcp_opt {
int opt, len, flags;
@@ -620,13 +778,27 @@ struct dhcp_bridge {
};
struct cond_domain {
char *domain;
char *domain, *prefix;
struct in_addr start, end;
#ifdef HAVE_IPV6
struct in6_addr start6, end6;
#endif
int is6;
struct cond_domain *next;
};
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class {
int class;
struct dhcp_netid tag;
struct prefix_class *next;
};
#endif
struct ra_interface {
char *name;
int interval, lifetime, prio;
struct ra_interface *next;
};
struct dhcp_context {
@@ -638,21 +810,33 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
time_t ra_time;
unsigned int valid, preferred, saved_valid;
time_t ra_time, ra_short_period_start, address_lost_time;
char *template_interface;
#endif
int flags;
char *interface;
struct dhcp_netid netid, *filter;
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_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)
struct ping_result {
struct in_addr addr;
@@ -686,17 +870,18 @@ struct addr_list {
struct addr_list *next;
};
struct interface_list {
char *interface;
struct interface_list *next;
};
struct tftp_prefix {
char *interface;
char *prefix;
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
@@ -706,33 +891,42 @@ 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;
struct txt_record *txt, *rr;
struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail;
struct cname *cnames;
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;
char *authserver, *hostmaster;
struct iname *authinterface;
struct name_list *secondary_forward_server;
int group_set, osport;
char *domain_suffix;
struct cond_domain *cond_domain;
struct cond_domain *cond_domain, *synth_domains;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr;
struct server *servers;
struct ipsets *ipsets;
int log_fac; /* log facility */
char *log_file; /* optional log file */
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
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;
@@ -741,8 +935,10 @@ 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;
@@ -754,16 +950,26 @@ extern struct daemon {
unsigned short edns_pktsz;
char *tftp_prefix;
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */
int tftp_unlimited;
unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config;
char *dbus_name;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
#ifdef OPTION6_PREFIX_CLASS
struct prefix_class *prefix_classes;
#endif
#ifdef HAVE_DNSSEC
struct ds_config *ds;
#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;
@@ -777,13 +983,14 @@ 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 */
/* DHCP state */
int dhcpfd, helperfd, pxefd;
#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;
@@ -814,13 +1021,13 @@ extern struct 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 *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,
@@ -830,22 +1037,45 @@ 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);
/* blockdata.c */
#ifdef HAVE_DNSSEC
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 */
char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
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,
struct all_addr *addrp, unsigned int flags,
unsigned long local_ttl);
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
time_t now, int is_sign, int checkrebind, int checking_disabled);
time_t now, char **ipsets, int is_sign, int checkrebind,
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);
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
@@ -855,10 +1085,41 @@ 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, ...);
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, 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 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 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);
/* util.c */
void rand_init(void);
unsigned short rand16(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);
@@ -867,7 +1128,7 @@ void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
int hostname_isequal(char *a, char *b);
int hostname_isequal(const char *a, const char *b);
time_t dnsmasq_time(void);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6
@@ -887,6 +1148,8 @@ 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);
/* log.c */
void die(char *message, char *arg1, int exit_code);
int log_start(struct passwd *ent_pw, int errfd);
@@ -901,17 +1164,21 @@ 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);
/* forward.c */
void reply_query(int fd, int family, time_t now);
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);
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);
void send_from(int fd, int nowild, char *packet, size_t len,
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);
@@ -921,17 +1188,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 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);
struct in_addr get_ifaddr(char *intr);
int tcp_interface(int fd, int af);
#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
@@ -946,12 +1231,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);
@@ -967,12 +1246,17 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr);
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr);
void lease6_reset(void);
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
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);
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_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
@@ -1012,7 +1296,7 @@ void poll_resolv(int force, int do_reload, time_t now);
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
void netlink_multicast(void);
void netlink_multicast(time_t now);
#endif
/* bpf.c */
@@ -1020,6 +1304,8 @@ void netlink_multicast(void);
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(time_t now);
#endif
/* bpf.c or netlink.c */
@@ -1035,6 +1321,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif
#endif
/* ipset.c */
#ifdef HAVE_IPSET
void ipset_init(void);
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove);
#endif
/* helper.c */
#if defined(HAVE_SCRIPT)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
@@ -1064,27 +1356,33 @@ 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);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans);
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,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname);
struct dhcp_netid *netids,
int plain_range);
struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
int plain_range);
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 */
@@ -1099,16 +1397,26 @@ char *strip_hostname(char *hostname);
void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
void dhcp_update_configs(struct dhcp_config *configs);
void check_dhcp_hosts(int fatal);
void display_opts(void);
u16 lookup_dhcp_opt(int prot, char *name);
u16 lookup_dhcp_len(int prot, u16 val);
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
char *whichdevice(void);
void bindtodevice(char *device, int fd);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
void join_multicast(void);
# endif
void log_context(int family, struct dhcp_context *context);
void log_relay(int family, struct dhcp_relay *relay);
#endif
/* outpacket.c */
@@ -1127,16 +1435,14 @@ void put_opt6_string(char *s);
/* radv.c */
#ifdef HAVE_DHCP6
void ra_init(time_t now);
void icmp6_packet(void);
void icmp6_packet(time_t now);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
#endif
/* slaac.c */
#ifdef HAVE_DHCP6
void build_subnet_map(void);
void slaac_add_addrs(struct dhcp_lease *lease, time_t now);
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);
void schedule_subnet_map(void);
#endif

2309
src/dnssec.c Normal file

File diff suppressed because it is too large Load Diff

232
src/domain.c Normal file
View File

@@ -0,0 +1,232 @@
/* dnsmasq is Copyright (c) 2000-2014 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"
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
#ifdef HAVE_IPV6
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
#endif
int is_name_synthetic(int flags, char *name, struct all_addr *addr)
{
char *p;
struct cond_domain *c = NULL;
int prot = AF_INET;
#ifdef HAVE_IPV6
if (flags & F_IPV6)
prot = AF_INET6;
#endif
for (c = daemon->synth_domains; c; c = c->next)
{
int found = 0;
char *tail, *pref;
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
{
unsigned int c1 = (unsigned char) *pref;
unsigned int c2 = (unsigned char) *tail;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
break;
}
if (pref && *pref != 0)
continue; /* prefix match fail */
/* NB, must not alter name if we return zero */
for (p = tail; *p; p++)
{
char c = *p;
if ((c >='0' && c <= '9') || c == '-')
continue;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
#endif
break;
}
if (*p != '.')
continue;
*p = 0;
/* swap . or : for - */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
#ifdef HAVE_IPV6
else
*p = ':';
#endif
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
found = 1;
}
#ifdef HAVE_IPV6
else
{
u64 addrpart = addr6part(&addr->addr.addr6);
if (c->is6 &&
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
found = 1;
}
#endif
}
/* restore name */
for (p = tail; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
if (found)
return 1;
}
return 0;
}
int is_rev_synth(int flag, struct all_addr *addr, char *name)
{
struct cond_domain *c;
if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains)))
{
char *p;
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
#ifdef HAVE_IPV6
if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains)))
{
char *p;
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (!c->prefix && *name == ':')
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
}
for (p = name; *p; p++)
if (*p == ':')
*p = '-';
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
#endif
return 0;
}
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
{
for (; c; c = c->next)
if (!c->is6 &&
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c;
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
if ((c = search_domain(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}
#ifdef HAVE_IPV6
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
{
u64 addrpart = addr6part(addr);
for (; c; c = c->next)
if (c->is6 &&
is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return c;
return NULL;
}
char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,10 +34,15 @@ static void my_setenv(const char *name, const char *value, int *error);
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
#ifdef HAVE_LUASCRIPT
#define LUA_COMPAT_ALL
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#ifndef lua_open
#define lua_open() luaL_newstate()
#endif
lua_State *lua;
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
@@ -55,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;
@@ -210,27 +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, ":");
}
/* expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u", data.length);
#else
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
#endif
/* 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)))
@@ -241,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
@@ -295,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)
{
@@ -318,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 */
}
@@ -331,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");
@@ -377,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");
@@ -392,6 +394,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial");
buf = grab_extradata_lua(buf, end, "cpewan_class");
buf = grab_extradata_lua(buf, end, "circuit_id");
buf = grab_extradata_lua(buf, end, "subscriber_id");
buf = grab_extradata_lua(buf, end, "remote_id");
}
buf = grab_extradata_lua(buf, end, "tags");
@@ -422,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");
@@ -475,26 +480,24 @@ 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);
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
#else
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
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;
@@ -504,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);
@@ -523,14 +526,17 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
}
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
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++)
{
@@ -538,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);
@@ -564,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 */
@@ -575,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
@@ -649,8 +663,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
unsigned char *p;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6
#ifdef HAVE_DHCP6
if (!daemon->dhcp)
fd = daemon->dhcp6fd;
#endif
@@ -670,6 +683,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
buf->vendorclass_count = lease->vendorclass_count;
buf->addr6 = lease->addr6;
buf->iaid = lease->iaid;
#endif
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len;
@@ -727,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);

34
src/ip6addr.h Normal file
View File

@@ -0,0 +1,34 @@
/* dnsmasq is Copyright (c) 2000-2014 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)

229
src/ipset.c Normal file
View File

@@ -0,0 +1,229 @@
/* ipset.c is Copyright (c) 2013 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
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_LINUX_NETWORK)
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <linux/version.h>
#include <linux/netlink.h>
/* We want to be able to compile against old header files
Kernel version is handled at run-time. */
#define NFNL_SUBSYS_IPSET 6
#define IPSET_ATTR_DATA 7
#define IPSET_ATTR_IP 1
#define IPSET_ATTR_IPADDR_IPV4 1
#define IPSET_ATTR_IPADDR_IPV6 2
#define IPSET_ATTR_PROTOCOL 1
#define IPSET_ATTR_SETNAME 2
#define IPSET_CMD_ADD 9
#define IPSET_CMD_DEL 10
#define IPSET_MAXNAMELEN 32
#define IPSET_PROTOCOL 6
#ifndef NFNETLINK_V0
#define NFNETLINK_V0 0
#endif
#ifndef NLA_F_NESTED
#define NLA_F_NESTED (1 << 15)
#endif
#ifndef NLA_F_NET_BYTEORDER
#define NLA_F_NET_BYTEORDER (1 << 14)
#endif
struct my_nlattr {
__u16 nla_len;
__u16 nla_type;
};
struct my_nfgenmsg {
__u8 nfgen_family; /* AF_xxx */
__u8 version; /* nfnetlink version */
__be16 res_id; /* resource id */
};
/* data structure size in here is fixed */
#define BUFF_SZ 256
#define NL_ALIGN(len) (((len)+3) & ~(3))
static const struct sockaddr_nl snl = { .nl_family = AF_NETLINK };
static int ipset_sock, old_kernel;
static char *buffer;
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
{
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
nlh->nlmsg_len += NL_ALIGN(payload_len);
}
void ipset_init(void)
{
struct utsname utsname;
int version;
char *split;
if (uname(&utsname) < 0)
die(_("failed to find kernel version: %s"), NULL, EC_MISC);
split = strtok(utsname.release, ".");
version = (split ? atoi(split) : 0);
split = strtok(NULL, ".");
version = version * 256 + (split ? atoi(split) : 0);
split = strtok(NULL, ".");
version = version * 256 + (split ? atoi(split) : 0);
old_kernel = (version < KERNEL_VERSION(2,6,32));
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
return;
if (!old_kernel &&
(buffer = safe_malloc(BUFF_SZ)) &&
(ipset_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER)) != -1 &&
(bind(ipset_sock, (struct sockaddr *)&snl, sizeof(snl)) != -1))
return;
die (_("failed to create IPset control socket: %s"), NULL, EC_MISC);
}
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
{
struct nlmsghdr *nlh;
struct my_nfgenmsg *nfg;
struct my_nlattr *nested[2];
uint8_t proto;
int addrsz = INADDRSZ;
ssize_t rc;
#ifdef HAVE_IPV6
if (af == AF_INET6)
addrsz = IN6ADDRSZ;
#endif
if (strlen(setname) >= IPSET_MAXNAMELEN)
{
errno = ENAMETOOLONG;
return -1;
}
memset(buffer, 0, BUFF_SZ);
nlh = (struct nlmsghdr *)buffer;
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
nlh->nlmsg_flags = NLM_F_REQUEST;
nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
nfg->nfgen_family = af;
nfg->version = NFNETLINK_V0;
nfg->res_id = htons(0);
proto = IPSET_PROTOCOL;
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
add_attr(nlh,
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
addrsz, &ipaddr->addr);
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;
}
static int old_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int remove)
{
socklen_t size;
struct ip_set_req_adt_get {
unsigned op;
unsigned version;
union {
char name[IPSET_MAXNAMELEN];
uint16_t index;
} set;
char typename[IPSET_MAXNAMELEN];
} req_adt_get;
struct ip_set_req_adt {
unsigned op;
uint16_t index;
uint32_t ip;
} req_adt;
if (strlen(setname) >= sizeof(req_adt_get.set.name))
{
errno = ENAMETOOLONG;
return -1;
}
req_adt_get.op = 0x10;
req_adt_get.version = 3;
strcpy(req_adt_get.set.name, setname);
size = sizeof(req_adt_get);
if (getsockopt(ipset_sock, SOL_IP, 83, &req_adt_get, &size) < 0)
return -1;
req_adt.op = remove ? 0x102 : 0x101;
req_adt.index = req_adt_get.set.index;
req_adt.ip = ntohl(ipaddr->addr.addr4.s_addr);
if (setsockopt(ipset_sock, SOL_IP, 83, &req_adt, sizeof(req_adt)) < 0)
return -1;
return 0;
}
int add_to_ipset(const char *setname, const struct all_addr *ipaddr, int flags, int remove)
{
int af = AF_INET;
#ifdef HAVE_IPV6
if (flags & F_IPV6)
{
af = AF_INET6;
/* old method only supports IPv4 */
if (old_kernel)
return -1;
}
#endif
return old_kernel ? old_add_to_ipset(setname, ipaddr, remove) : new_add_to_ipset(setname, ipaddr, af, remove);
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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
@@ -98,7 +98,7 @@ void lease_init(time_t now)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
hw_len, hw_type, clid_len, now);
hw_len, hw_type, clid_len, now, 0);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
@@ -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 = atoi(s);
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);
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,26 +306,33 @@ 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
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
time_t ra_event = periodic_slaac(now, leases);
time_t event;
next_event = periodic_ra(now);
if ((event = periodic_slaac(now, leases)) != 0)
{
if (next_event == 0 || difftime(next_event, event) > 0.0)
next_event = event;
}
if (next_event == 0 || difftime(next_event, ra_event) > 0.0)
next_event = ra_event;
if ((event = periodic_ra(now)) != 0)
{
if (next_event == 0 || difftime(next_event, event) > 0.0)
next_event = event;
}
}
#endif
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)
{
@@ -338,11 +348,12 @@ void lease_update_file(time_t now)
}
static int find_interface_v4(struct in_addr local, int if_index,
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;
(void) label;
(void) broadcast;
(void) vparam;
@@ -356,16 +367,19 @@ static int find_interface_v4(struct in_addr local, int if_index,
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct dhcp_lease *lease;
(void)scope;
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
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))
if (is_same_net6(local, &lease->addr6, prefix))
lease_set_interface(lease, if_index, *((time_t *)vparam));
return 1;
@@ -373,7 +387,22 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
{
slaac_ping_reply(sender, packet, interface, leases);
/* We may be doing RA but not DHCPv4, in which case the lease
database may not exist and we have nothing to do anyway */
if (daemon->dhcp)
slaac_ping_reply(sender, packet, interface, leases);
}
void lease_update_slaac(time_t now)
{
/* Called when we contruct a new RA-names context, to add putative
new SLAAC addresses to existing leases. */
struct dhcp_lease *lease;
if (daemon->dhcp)
for (lease = leases; lease; lease = lease->next)
slaac_add_addrs(lease, now, 0);
}
#endif
@@ -385,22 +414,24 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
start-time. */
void lease_find_interfaces(time_t now)
{
#ifdef HAVE_DHCP6
build_subnet_map();
#endif
iface_enumerate(AF_INET, &now, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);
#endif
}
#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
@@ -410,6 +441,11 @@ void lease_update_dns(int force)
if (daemon->port != 0 && (dns_dirty || force))
{
#ifndef HAVE_BROKEN_RTC
/* force transfer to authoritative secondaries */
daemon->soa_sn++;
#endif
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
@@ -432,17 +468,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;
@@ -529,8 +572,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
}
#ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
/* find address for {CLID, IAID, address} */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr)
{
@@ -538,27 +580,54 @@ 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 (clid && addr && (lease->flags & LEASE_USED))
if (!IN6_ARE_ADDR_EQUAL(&lease->addr6, addr))
continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue;
if (clid &&
(clid_len != lease->clid_len ||
if ((clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
if (clid || addr)
{
lease->flags |= LEASE_USED;
return lease;
}
else
lease->flags &= ~LEASE_USED;
return lease;
}
return NULL;
}
/* reset "USED flags */
void lease6_reset(void)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
lease->flags &= ~LEASE_USED;
}
/* enumerate all leases belonging to {CLID, IAID} */
struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_type, unsigned char *clid, int clid_len, int iaid)
{
struct dhcp_lease *lease;
if (!first)
first = leases;
else
first = first->next;
for (lease = first; lease; lease = lease->next)
{
if (lease->flags & LEASE_USED)
continue;
if (!(lease->flags & lease_type) || lease->iaid != iaid)
continue;
if ((clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
return lease;
}
return NULL;
@@ -573,8 +642,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;
}
@@ -593,11 +662,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;
@@ -639,6 +708,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;
@@ -651,9 +721,9 @@ static struct dhcp_lease *lease_allocate(void)
struct dhcp_lease *lease4_allocate(struct in_addr addr)
{
struct dhcp_lease *lease = lease_allocate();
lease->addr = addr;
lease->hwaddr_len = 256; /* illegal value */
if (lease)
lease->addr = addr;
return lease;
}
@@ -661,8 +731,13 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
{
struct dhcp_lease *lease = lease_allocate();
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->flags |= lease_type;
if (lease)
{
lease->addr6 = *addrp;
lease->flags |= lease_type;
lease->iaid = 0;
}
return lease;
}
@@ -670,14 +745,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;
@@ -698,14 +782,29 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
#endif
}
#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, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now)
unsigned char *clid, int hw_len, int hw_type, int clid_len,
time_t now, int force)
{
#ifdef HAVE_DHCP6
int change = 0;
int change = force;
lease->flags |= LEASE_HAVE_HWADDR;
#endif
(void)force;
(void)now;
if (hw_len != lease->hwaddr_len ||
hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
@@ -716,9 +815,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
@@ -755,7 +851,7 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
#ifdef HAVE_DHCP6
if (change)
slaac_add_addrs(lease, now);
slaac_add_addrs(lease, now, force);
#endif
}
@@ -876,6 +972,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;
@@ -883,7 +981,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
lease->flags |= LEASE_CHANGED;
#ifdef HAVE_DHCP6
slaac_add_addrs(lease, now);
slaac_add_addrs(lease, now, 0);
#endif
}
@@ -904,6 +1002,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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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 void nl_err(struct nlmsghdr *h);
static void nl_routechange(struct nlmsghdr *h);
static int nl_async(struct nlmsghdr *h);
void netlink_init(void)
{
@@ -49,10 +48,17 @@ void netlink_init(void)
addr.nl_family = AF_NETLINK;
addr.nl_pad = 0;
addr.nl_pid = 0; /* autobind */
#ifdef HAVE_IPV6
addr.nl_groups = RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
#else
addr.nl_groups = RTMGRP_IPV4_ROUTE;
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
#ifdef HAVE_IPV6
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
#ifdef HAVE_DHCP6
if (daemon->doing_ra || daemon->doing_dhcp6)
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
/* May not be able to have permission to set multicast groups don't die in that case */
@@ -136,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;
int callback_ok = 1, newaddr = 0;
struct {
struct nlmsghdr nlh;
@@ -182,12 +188,24 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid)
nl_routechange(h); /* May be multicast arriving async */
else if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
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;
enumerate_interfaces(1); /* reset */
}
}
else if (h->nlmsg_type == NLMSG_DONE)
return callback_ok;
{
/* handle async new interface address arrivals, these have to be done
after we complete as we're not re-entrant */
if (newaddr)
newaddress(dnsmasq_time());
return callback_ok;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
@@ -199,7 +217,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifa->ifa_family == AF_INET)
{
struct in_addr netmask, addr, broadcast;
char *label = NULL;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
broadcast.s_addr = 0;
@@ -210,29 +229,49 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_BROADCAST)
broadcast = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_LABEL)
label = RTA_DATA(rta);
rta = RTA_NEXT(rta, len1);
}
if (addr.s_addr && callback_ok)
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
callback_ok = 0;
}
#ifdef HAVE_IPV6
else if (ifa->ifa_family == AF_INET6)
{
struct in6_addr *addrp = NULL;
u32 valid = 0, preferred = 0;
int flags = 0;
while (RTA_OK(rta, len1))
{
if (rta->rta_type == IFA_ADDRESS)
addrp = ((struct in6_addr *)(rta+1));
else if (rta->rta_type == IFA_CACHEINFO)
{
struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
preferred = ifc->ifa_prefered;
valid = ifc->ifa_valid;
}
rta = RTA_NEXT(rta, len1);
}
if (ifa->ifa_flags & IFA_F_TENTATIVE)
flags |= IFACE_TENTATIVE;
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), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
(int)(ifa->ifa_index), flags,
(int) preferred, (int)valid, parm)))
callback_ok = 0;
}
#endif
@@ -291,11 +330,11 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
}
void netlink_multicast(void)
void netlink_multicast(time_t now)
{
ssize_t len;
struct nlmsghdr *h;
int flags;
int flags, newaddr = 0;
/* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
@@ -303,71 +342,62 @@ void netlink_multicast(void)
return;
if ((len = netlink_recv()) != -1)
{
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
else
nl_routechange(h);
}
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
}
static void nl_err(struct nlmsghdr *h)
{
struct nlmsgerr *err = NLMSG_DATA(h);
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (nl_async(h))
newaddr = 1;
if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
newaddress(now);
}
/* We arrange to receive netlink multicast messages whenever the network route is added.
If this happens and we still have a DNS packet in the buffer, we re-send it.
This helps on DoD links, where frequently the packet which triggers dialling is
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
failing. Note that we only accept these messages from the kernel (pid == 0) */
static void nl_routechange(struct nlmsghdr *h)
static int nl_async(struct nlmsghdr *h)
{
if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
if (h->nlmsg_type == NLMSG_ERROR)
{
struct rtmsg *rtm = NLMSG_DATA(h);
int fd;
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
return;
/* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0;
#ifdef HAVE_DHCP6
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
schedule_subnet_map();
ra_start_unsolicted(dnsmasq_time(), NULL);
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm(0, 0);
}
#endif
if (daemon->srv_save)
{
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;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
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)
{
/* We arrange to receive netlink multicast messages whenever the network route is added.
If this happens and we still have a DNS packet in the buffer, we re-send it.
This helps on DoD links, where frequently the packet which triggers dialling is
a DNS query, which then gets lost. By re-sending, we can avoid the lookup
failing. */
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;
}
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
return 1; /* clever bind mode - rescan */
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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;
}

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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 ALL_HOSTS "FF02::1"
#define ALL_NODES "FF02::1"
#define ALL_ROUTERS "FF02::2"
struct ping_packet {
@@ -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,7 +49,9 @@ 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_RDNSS 25
#define ICMP6_OPT_DNSSL 31

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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
@@ -27,30 +27,40 @@
#include <netinet/icmp6.h>
struct ra_param {
int ind, managed, found_context, first;
time_t now;
int ind, managed, other, found_context, first, adv_router;
char *if_name;
struct in6_addr link_local;
struct dhcp_netid *tags;
struct in6_addr link_local, link_global, ula;
unsigned int glob_pref_time, link_pref_time, ula_pref_time, adv_interval;
};
struct search_param {
time_t now; int iface;
char name[IF_NAMESIZE+1];
};
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
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;
static time_t ra_short_period_start;
void ra_init(time_t now)
{
struct icmp6_filter filter;
int fd;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
int val = 255; /* radvd uses this value */
@@ -61,18 +71,23 @@ void ra_init(time_t now)
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
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) ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
#if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) ||
@@ -84,7 +99,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)
@@ -93,18 +109,20 @@ void ra_start_unsolicted(time_t now, struct dhcp_context *context)
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
if (context)
context->ra_time = now;
context->ra_short_period_start = context->ra_time = now;
else
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE))
{
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
context->ra_short_period_start = now;
}
}
void icmp6_packet(void)
void icmp6_packet(time_t now)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
@@ -116,10 +134,8 @@ void icmp6_packet(void)
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
struct sockaddr_in6 from;
unsigned char *p;
char *mac = "";
unsigned char *packet;
struct iname *tmp;
struct dhcp_context *context;
/* Note: use outpacket for input buffer */
msg.msg_control = control_u.control6;
@@ -132,6 +148,8 @@ void icmp6_packet(void)
if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
return;
packet = (unsigned char *)daemon->outpacket.iov_base;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
@@ -148,57 +166,50 @@ void icmp6_packet(void)
if (!indextoname(daemon->icmp6fd, if_index, interface))
return;
if (!iface_check(AF_LOCAL, NULL, interface))
if (!iface_check(AF_LOCAL, NULL, interface, NULL))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0))
if (tmp->name && wildcard_match(tmp->name, interface))
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, interface) == 0)
break;
if (!context)
if (packet[1] != 0)
return;
p = (unsigned char *)daemon->outpacket.iov_base;
if (p[1] != 0)
return;
if (p[0] == ICMP6_ECHO_REPLY)
if (packet[0] == ICMP6_ECHO_REPLY)
lease_ping_reply(&from.sin6_addr, packet, interface);
else if (packet[0] == ND_ROUTER_SOLICIT)
{
/* We may be doing RA but not DHCPv4, in which case the lease
database may not exist and we have nothing to do anyway */
if (daemon->dhcp)
lease_ping_reply(&from.sin6_addr, p, interface);
return;
char *mac = "";
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
mac = daemon->namebuff;
}
if (!option_bool(OPT_QUIET_RA))
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 (p[0] != ND_ROUTER_SOLICIT)
return;
/* look for link-layer address option for logging */
if (sz >= 16 && p[8] == ICMP6_OPT_SOURCE_MAC && (p[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &p[10], (p[9] * 8) - 2);
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
send_ra(if_index, interface, &from.sin6_addr);
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
{
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;
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
save_counter(0);
ra = expand(sizeof(struct ra_packet));
@@ -206,48 +217,247 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0x00;
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
ra->flags = calc_prio(ra_param);
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.adv_router = 0;
parm.if_name = iface_name;
parm.first = 1;
for (context = daemon->ra_contexts; context; context = context->next)
context->flags &= ~CONTEXT_RA_DONE;
parm.now = now;
parm.glob_pref_time = parm.link_pref_time = parm.ula_pref_time = 0;
parm.adv_interval = calc_interval(ra_param);
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
parm.tags = &iface_id;
for (context = daemon->dhcp6; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
context->netid.next = &context->netid;
}
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 (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
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)
{
put_opt6_char(ICMP6_OPT_MTU);
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, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 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);
put_opt6_long(ifr.ifr_mtu);
/* 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
available from SIOCGIFMTU */
sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
if ((f = fopen(daemon->namebuff, "r")))
{
if (fgets(daemon->namebuff, MAXDNAME, f))
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(atoi(daemon->namebuff));
}
fclose(f);
}
#endif
iface_enumerate(AF_LOCAL, &iface, add_lla);
/* RDNSS, RFC 6106, use relevant DHCP6 options */
(void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
/* RDNSS, RFC 6106 */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
{
int i;
/* netids match and not encapsulated? */
if (!(opt_cfg->flags & DHOPT_TAGOK))
continue;
if (opt_cfg->opt == OPTION6_DNS_SERVER)
{
struct in6_addr *a;
int len;
done_dns = 1;
if (opt_cfg->len == 0)
continue;
/* 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)
{
int len = ((opt_cfg->len+7)/8);
put_opt6_char(ICMP6_OPT_DNSSL);
put_opt6_char(len + 1);
put_opt6_short(0);
put_opt6_long(min_pref_time);
put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */
for (i = opt_cfg->len; i < len * 8; i++)
put_opt6_char(0);
}
}
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(min_pref_time);
put_opt6(&parm.link_local, IN6ADDRSZ);
}
/* set managed bits unless we're providing only RA on this link */
if (parm.managed)
ra->flags = 0xc0; /* M flag, managed, O flag, other */
ra->flags |= 0x80; /* M flag, managed, */
if (parm.other)
ra->flags |= 0x40; /* O flag, other */
/* decide where we're sending */
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -263,97 +473,183 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
addr.sin6_scope_id = iface;
}
else
inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
{
inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr);
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface, sizeof(iface));
}
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
while (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1 && retry_send());
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam)
{
struct dhcp_context *context, *tmp;
struct ra_param *param = vparam;
struct prefix_opt *opt;
(void)scope; /* warning */
(void)dad;
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_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
int real_prefix = 0;
int do_slaac = 0;
int deprecate = 0;
int constructed = 0;
int adv_router = 0;
unsigned int time = 0xffffffff;
struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next)
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))
{
int do_slaac = 0;
context->saved_valid = valid;
if (context->flags & CONTEXT_RA_ONLY)
do_slaac = 1;
if (context->flags & CONTEXT_RA)
{
do_slaac = 1;
if (context->flags & CONTEXT_DHCP)
{
param->other = 1;
if (!(context->flags & CONTEXT_RA_STATELESS))
param->managed = 1;
}
}
else
{
/* don't do RA for non-ra-only unless --enable-ra is set */
if (!option_bool(OPT_RA))
continue;
param->managed = 1;
param->other = 1;
}
if (context->flags & CONTEXT_RA_DONE)
continue;
/* subsequent prefixes on the same interface don't need timers */
if (!param->first)
context->ra_time = 0;
param->first = 0;
param->found_context = 1;
context->flags |= CONTEXT_RA_DONE;
/* mark this subnet and duplicates: as done. */
for (tmp = context->next; tmp; tmp = tmp->next)
if (tmp->prefix == prefix &&
is_same_net6(local, &tmp->start6, prefix) &&
is_same_net6(local, &tmp->end6, prefix))
{
/* if any dhcp-range with ra-only on this subnet
set the "do_slaac" bit */
if (tmp->flags & CONTEXT_RA_ONLY)
do_slaac = 1;
tmp->flags |= CONTEXT_RA_DONE;
context->ra_time = 0;
}
if ((opt = expand(sizeof(struct prefix_opt))))
/* 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)
{
u64 addrpart = addr6part(&context->start6);
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
unsigned int time = context->lease_time;
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only is we're not doing dhcp */
opt->flags = do_slaac ? 0x40 : 0x00;
opt->valid_lifetime = opt->preferred_lifetime = htonl(time);
opt->reserved = 0;
opt->prefix = context->start6;
setaddr6part(&opt->prefix, addrpart & ~mask);
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
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)(3 * param->adv_interval)))
time = 3 * param->adv_interval;
}
if (context->flags & CONTEXT_DEPRECATE)
deprecate = 1;
if (context->flags & CONTEXT_CONSTRUCTED)
constructed = 1;
/* collect dhcp-range tags */
if (context->netid.next == &context->netid && context->netid.net)
{
context->netid.next = param->tags;
param->tags = &context->netid;
}
/* 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 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;
real_prefix = context->prefix;
}
param->first = 0;
param->found_context = 1;
}
/* configured time is ceiling */
if (!constructed || valid > time)
valid = time;
if (flags & IFACE_DEPRECATED)
preferred = 0;
if (deprecate)
time = 0;
/* configured time is ceiling */
if (!constructed || preferred > time)
preferred = time;
if (IN6_IS_ADDR_ULA(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 (real_prefix != 0)
{
struct prefix_opt *opt;
if ((opt = expand(sizeof(struct prefix_opt))))
{
/* zero net part of address */
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 = real_prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = 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);
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
}
return 1;
@@ -385,73 +681,172 @@ time_t periodic_ra(time_t now)
struct search_param param;
struct dhcp_context *context;
time_t next_event;
char interface[IF_NAMESIZE+1];
param.now = now;
param.iface = 0;
while (1)
{
/* find overdue events, and time of first future event */
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) < 0.0)
if (difftime(context->ra_time, now) <= 0.0)
break; /* overdue */
if (next_event == 0 || difftime(next_event, context->ra_time + 2) > 0.0)
next_event = context->ra_time + 2;
if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
next_event = context->ra_time;
}
/* none overdue */
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 (indextoname(daemon->icmp6fd, param.iface, interface))
send_ra(param.iface, 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, param.name))
break;
if (!tmp)
send_ra(now, param.iface, param.name, NULL);
}
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)preferred;
(void)valid;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface
so they don't timeout independently .*/
for (context = daemon->dhcp6; context; context = context->next)
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)
{
/* found an interface that's overdue for RA determine new
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
return 0; /* found, abort */
}
/* 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, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
context->ra_time = 0;
return 0; /* found, abort */
}
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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,11 +34,12 @@ 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);
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
static int in_list(unsigned char *list, int opt);
static void do_options(struct dhcp_context *context,
struct dhcp_packet *mess,
unsigned char *real_end,
@@ -91,7 +92,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;
@@ -155,8 +159,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)
@@ -354,6 +359,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
}
}
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
Otherwise assume the option is an array, and look for a matching element.
If no data given, existance of the option is enough. This code handles
rfc3925 V-I classes too. */
for (o = daemon->dhcp_match; o; o = o->next)
{
unsigned int len, elen, match = 0;
size_t offset, o2;
if (o->flags & DHOPT_RFC3925)
{
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
continue;
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
{
len = option_uint(opt, offset + 4 , 1);
/* Need to take care that bad data can't run us off the end of the packet */
if ((offset + len + 5 <= (option_len(opt))) &&
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
{
elen = option_uint(opt, o2, 1);
if ((o2 + elen + 1 <= option_len(opt)) &&
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
break;
}
if (match)
break;
}
}
else
{
if (!(opt = option_find(mess, sz, o->opt, 1)))
continue;
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
}
if (match)
{
o->netid->next = netid;
netid = o->netid;
}
}
/* user-class options are, according to RFC3004, supposed to contain
a set of counted strings. Here we check that this is so (by seeing
if the counts are consistent with the overall option length) and if
so zero the counts so that we don't get spurious matches between
the vendor string and the counts. If the lengths don't add up, we
assume that the option is a single string and non RFC3004 compliant
and just do the substring match. dhclient provides these broken options.
The code, later, which sends user-class data to the lease-change script
relies on the transformation done here.
*/
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
unsigned char *ucp = option_ptr(opt, 0);
int tmp, j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
if (j == option_len(opt))
for (j = 0; j < option_len(opt); j = tmp)
{
tmp = j + ucp[j] + 1;
ucp[j] = 0;
}
}
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
{
int mopt;
if (vendor->match_type == MATCH_VENDOR)
mopt = OPTION_VENDOR_ID;
else if (vendor->match_type == MATCH_USER)
mopt = OPTION_USER_CLASS;
else
continue;
if ((opt = option_find(mess, sz, mopt, 1)))
{
int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
break;
}
}
}
/* mark vendor-encapsulated options which match the client-supplied vendor class,
save client-supplied vendor class */
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
{
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
vendor_class_len = option_len(opt);
}
match_vendor_opts(opt, daemon->dhcp_opts);
if (option_bool(OPT_LOG_OPTS))
{
if (sanitise(opt, daemon->namebuff))
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
}
mess->op = BOOTREPLY;
@@ -483,7 +599,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
logaddr = &mess->yiaddr;
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now);
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now, 1);
if (hostname)
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
/* infinite lease unless nailed in dhcp-host line. */
@@ -494,16 +610,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, 0, NULL, 0, now);
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
}
}
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);
@@ -515,14 +631,25 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
op += 3;
pp = op;
/* Always force update, since the client has no way to do it itself. */
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
fqdn_flags |= 0x03;
fqdn_flags &= ~0x08;
/* NB, the following always sets at least one bit */
if (option_bool(OPT_FQDN_UPDATE))
{
if (fqdn_flags & 0x01)
{
fqdn_flags |= 0x02; /* set O */
fqdn_flags &= ~0x01; /* clear S */
}
fqdn_flags |= 0x08; /* set N */
}
else
{
if (!(fqdn_flags & 0x01))
fqdn_flags |= 0x03; /* set S and O */
fqdn_flags &= ~0x08; /* clear N */
}
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;
@@ -610,119 +737,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
}
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
Otherwise assume the option is an array, and look for a matching element.
If no data given, existance of the option is enough. This code handles
rfc3925 V-I classes too. */
for (o = daemon->dhcp_match; o; o = o->next)
{
unsigned int len, elen, match = 0;
size_t offset, o2;
if (o->flags & DHOPT_RFC3925)
{
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
continue;
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
{
len = option_uint(opt, offset + 4 , 1);
/* Need to take care that bad data can't run us off the end of the packet */
if ((offset + len + 5 <= (option_len(opt))) &&
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
{
elen = option_uint(opt, o2, 1);
if ((o2 + elen + 1 <= option_len(opt)) &&
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
break;
}
if (match)
break;
}
}
else
{
if (!(opt = option_find(mess, sz, o->opt, 1)))
continue;
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
}
if (match)
{
o->netid->next = netid;
netid = o->netid;
}
}
/* user-class options are, according to RFC3004, supposed to contain
a set of counted strings. Here we check that this is so (by seeing
if the counts are consistent with the overall option length) and if
so zero the counts so that we don't get spurious matches between
the vendor string and the counts. If the lengths don't add up, we
assume that the option is a single string and non RFC3004 compliant
and just do the substring match. dhclient provides these broken options.
The code, later, which sends user-class data to the lease-change script
relies on the transformation done here.
*/
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
unsigned char *ucp = option_ptr(opt, 0);
int tmp, j;
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
if (j == option_len(opt))
for (j = 0; j < option_len(opt); j = tmp)
{
tmp = j + ucp[j] + 1;
ucp[j] = 0;
}
}
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
{
int mopt;
if (vendor->match_type == MATCH_VENDOR)
mopt = OPTION_VENDOR_ID;
else if (vendor->match_type == MATCH_USER)
mopt = OPTION_USER_CLASS;
else
continue;
if ((opt = option_find(mess, sz, mopt, 1)))
{
int i;
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
{
vendor->netid.next = netid;
netid = &vendor->netid;
break;
}
}
}
/* mark vendor-encapsulated options which match the client-supplied vendor class,
save client-supplied vendor class */
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
{
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
vendor_class_len = option_len(opt);
}
match_vendor_opts(opt, daemon->dhcp_opts);
if (option_bool(OPT_LOG_OPTS))
{
if (sanitise(opt, daemon->namebuff))
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
}
tagif_netid = run_tag_if(netid);
/* if all the netids in the ignore list are present, ignore this client */
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
if (match_netid(id_list->list, tagif_netid, 0))
@@ -815,7 +831,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);
}
@@ -836,8 +852,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)
{
@@ -867,7 +891,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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);
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);
}
@@ -899,7 +923,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);
@@ -931,13 +955,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;
}
@@ -995,7 +1021,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;
@@ -1008,7 +1034,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);
@@ -1060,7 +1086,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 &&
@@ -1124,7 +1150,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)
{
@@ -1196,7 +1222,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);
@@ -1222,51 +1248,69 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
log_tags(tagif_netid, ntohl(mess->xid));
#ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command)
if (do_classes)
{
struct dhcp_netid *n;
if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr;
/* pick up INIT-REBOOT events. */
lease->flags |= LEASE_CHANGED;
free(lease->extradata);
lease->extradata = NULL;
lease->extradata_size = lease->extradata_len = 0;
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
add_extradata_opt(lease, oui);
add_extradata_opt(lease, serial);
add_extradata_opt(lease, class);
/* space-concat tag set */
if (!tagif_netid)
add_extradata_opt(lease, NULL);
else
for (n = tagif_netid; n; n = n->next)
{
struct dhcp_netid *n1;
/* kill dupes */
for (n1 = n->next; n1; n1 = n1->next)
if (strcmp(n->net, n1->net) == 0)
break;
if (!n1)
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
}
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command)
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
lease_add_extradata(lease, ucp, len, 0);
struct dhcp_netid *n;
if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr;
free(lease->extradata);
lease->extradata = NULL;
lease->extradata_size = lease->extradata_len = 0;
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
add_extradata_opt(lease, option_find(mess, sz, OPTION_HOSTNAME, 1));
add_extradata_opt(lease, oui);
add_extradata_opt(lease, serial);
add_extradata_opt(lease, class);
if ((opt = option_find(mess, sz, OPTION_AGENT_ID, 1)))
{
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_CIRCUIT_ID, 1));
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_SUBSCR_ID, 1));
add_extradata_opt(lease, option_find1(option_ptr(opt, 0), option_ptr(opt, option_len(opt)), SUBOPT_REMOTE_ID, 1));
}
else
{
add_extradata_opt(lease, NULL);
add_extradata_opt(lease, NULL);
add_extradata_opt(lease, NULL);
}
/* space-concat tag set */
if (!tagif_netid)
add_extradata_opt(lease, NULL);
else
for (n = tagif_netid; n; n = n->next)
{
struct dhcp_netid *n1;
/* kill dupes */
for (n1 = n->next; n1; n1 = n1->next)
if (strcmp(n->net, n1->net) == 0)
break;
if (!n1)
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
}
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{
int len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
lease_add_extradata(lease, ucp, len, 0);
}
}
}
#endif
}
if (!hostname_auth && (client_hostname = host_from_dns(mess->yiaddr)))
{
@@ -1276,7 +1320,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now);
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now, do_classes);
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
if (!hostname_auth)
@@ -1317,7 +1361,7 @@ 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);
@@ -1340,7 +1384,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;
@@ -1355,8 +1399,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)
{
@@ -1366,10 +1410,11 @@ 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)
{
lease_set_interface(lease, int_index, now);
if (override.s_addr != 0)
lease->override = override;
else
@@ -1379,15 +1424,19 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
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));
if (lease)
/* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
we supply a utility which makes DHCPINFORM requests to get this information.
Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
which won't be true for ordinary clients, but will be true for the
dhcp_lease_time utility. */
if (lease && in_list(req_options, OPTION_LEASE_TIME))
{
if (lease->expires == 0)
time = 0xffffffff;
else
time = (unsigned int)difftime(lease->expires, now);
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
lease_set_interface(lease, int_index, now);
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
@@ -1495,10 +1544,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));
@@ -1506,22 +1558,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)
@@ -1731,7 +1785,7 @@ static unsigned char *free_space(struct dhcp_packet *mess, unsigned char *end, i
if (overload[2] & 2)
{
p = dhcp_skip_opts(mess->sname);
if (p + len + 3 >= mess->sname + sizeof(mess->file))
if (p + len + 3 >= mess->sname + sizeof(mess->sname))
p = NULL;
}
}
@@ -1798,7 +1852,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;
}
@@ -2095,7 +2150,8 @@ static void do_options(struct dhcp_context *context,
struct dhcp_netid_list *id_list;
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
context->netid.next = NULL;
if (context)
context->netid.next = NULL;
tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
/* logging */
@@ -2225,7 +2281,8 @@ static void do_options(struct dhcp_context *context,
!option_find2(OPTION_ROUTER))
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
if (in_list(req_options, OPTION_DNSSERVER) &&
if (daemon->port == NAMESERVER_PORT &&
in_list(req_options, OPTION_DNSSERVER) &&
!option_find2(OPTION_DNSSERVER))
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
}
@@ -2252,10 +2309,12 @@ 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;
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
*(p++) = 255;
*(p++) = 255;
@@ -2263,8 +2322,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
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,15 +20,16 @@
#include <netinet/icmp6.h>
static int map_rebuild = 0;
static int ping_id = 0;
void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
{
struct slaac_address *slaac, *old, **up;
struct dhcp_context *context;
int dns_dirty = 0;
if (!(lease->flags & LEASE_HAVE_HWADDR) ||
(lease->flags & (LEASE_TA | LEASE_NA)) ||
lease->last_interface == 0 ||
!lease->hostname)
return ;
@@ -36,8 +37,10 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
old = lease->slaac_address;
lease->slaac_address = NULL;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
for (context = daemon->dhcp6; context; context = context->next)
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 &&
@@ -72,6 +75,13 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
{
*up = slaac->next;
/* recheck when DHCPv4 goes through init-reboot */
if (force)
{
slaac->ping_time = now;
slaac->backoff = 1;
dns_dirty = 1;
}
break;
}
up = &slaac->next;
@@ -83,7 +93,6 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
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);
}
@@ -95,6 +104,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
}
}
if (old || dns_dirty)
lease_update_dns(1);
/* Free any no reused */
for (; old; old = slaac)
{
@@ -108,11 +120,11 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
{
struct dhcp_context *context;
struct dhcp_lease *lease;
struct slaac_address *slaac;
time_t next_event = 0;
struct slaac_address *slaac;
time_t next_event = 0;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
break;
/* nothing configured */
@@ -122,24 +134,18 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
while (ping_id == 0)
ping_id = rand16();
if (map_rebuild)
{
map_rebuild = 0;
build_subnet_map();
}
for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
{
/* confirmed? */
if (slaac->backoff == 0)
/* confirmed or given up? */
if (slaac->backoff == 0 || slaac->ping_time == 0)
continue;
if (difftime(slaac->ping_time, now) <= 0.0)
{
struct ping_packet *ping;
struct sockaddr_in6 addr;
save_counter(0);
ping = expand(sizeof(struct ping_packet));
ping->type = ICMP6_ECHO_REQUEST;
@@ -155,16 +161,22 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr;
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local, lease->last_interface);
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
if (slaac->backoff > 4)
slaac->ping_time += rand16()/4000; /* 0 - 15 */
slaac->backoff++;
if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(0), 0,
(struct sockaddr *)&addr, sizeof(addr)) == -1 &&
errno == EHOSTUNREACH)
slaac->ping_time = 0; /* Give up */
else
{
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
if (slaac->backoff > 4)
slaac->ping_time += rand16()/4000; /* 0 - 15 */
if (slaac->backoff < 12)
slaac->backoff++;
}
}
if (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0)
if (slaac->ping_time != 0 &&
(next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0))
next_event = slaac->ping_time;
}
@@ -187,57 +199,11 @@ 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);
}
/* Build a map from ra-names subnets to corresponding interfaces. This
is used to go from DHCPv4 leases to SLAAC addresses,
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
*/
static int add_subnet(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)vparam;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
context->if_index = if_index;
context->local6 = *local;
}
return 1;
}
void build_subnet_map(void)
{
struct dhcp_context *context;
int ok = 0;
for (context = daemon->ra_contexts; context; context = context->next)
{
context->if_index = 0;
if ((context->flags & CONTEXT_RA_NAME))
ok = 1;
}
/* ra-names configured */
if (ok)
iface_enumerate(AF_INET6, NULL, add_subnet);
}
void schedule_subnet_map(void)
{
map_rebuild = 1;
}
#endif

167
src/tables.c Normal file
View File

@@ -0,0 +1,167 @@
/* tables.c is Copyright (c) 2014 Dohnuts All Rights Reserved.
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)
#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-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,12 +18,13 @@
#ifdef HAVE_TFTP
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int special);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
static ssize_t tftp_err_oops(char *packet, char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end);
static void sanitise(char *buf);
#define OP_RRQ 1
#define OP_WRQ 2
@@ -47,21 +48,24 @@ void tftp_request(struct listener *listen, time_t now)
struct msghdr msg;
struct iovec iov;
struct ifreq ifr;
int is_err = 1, if_index = 0, mtu = 0, special = 0;
#ifdef HAVE_DHCP
int is_err = 1, if_index = 0, mtu = 0;
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)
int mtuflag = IP_PMTUDISC_DONT;
#endif
char namebuff[IF_NAMESIZE];
char *name;
char *name = NULL;
char *prefix = daemon->tftp_prefix;
struct tftp_prefix *pref;
struct interface_list *ir;
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
@@ -92,18 +96,28 @@ 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)
{
addr = listen->iface->addr;
mtu = listen->iface->mtu;
name = listen->iface->name;
if (listen->iface)
{
addr = listen->iface->addr;
mtu = listen->iface->mtu;
name = listen->iface->name;
}
else
{
/* we're listening on an address that doesn't appear on an interface,
ask the kernel what the socket is bound to */
socklen_t tcp_len = sizeof(union mysockaddr);
if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
return;
}
}
else
{
struct cmsghdr *cmptr;
int check;
struct interface_list *ir;
if (msg.msg_controllen < sizeof(struct cmsghdr))
return;
@@ -180,28 +194,40 @@ void tftp_request(struct listener *listen, time_t now)
return;
name = namebuff;
addra.addr.addr4 = addr.in.sin_addr;
#ifdef HAVE_IPV6
if (listen->family == AF_INET6)
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
else
addra.addr.addr6 = addr.in6.sin6_addr;
#endif
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
/* wierd TFTP service override */
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
if (strcmp(ir->interface, name) == 0)
break;
if (!ir)
if (daemon->tftp_interfaces)
{
if (!daemon->tftp_unlimited || !check)
/* 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 && (strcmp(tmp->name, name) == 0))
if (tmp->name && wildcard_match(tmp->name, name))
return;
#endif
}
@@ -211,15 +237,13 @@ void tftp_request(struct listener *listen, time_t now)
mtu = ifr.ifr_mtu;
}
/* check for per-interface prefix */
for (pref = daemon->if_prefix; pref; pref = pref->next)
if (strcmp(pref->interface, name) == 0)
prefix = pref->prefix;
/* wierd TFTP interfaces disable special options. */
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
if (strcmp(ir->interface, name) == 0)
special = 1;
if (name)
{
/* check for per-interface prefix */
for (pref = daemon->if_prefix; pref; pref = pref->next)
if (strcmp(pref->interface, name) == 0)
prefix = pref->prefix;
}
if (listen->family == AF_INET)
{
@@ -297,7 +321,10 @@ void tftp_request(struct listener *listen, time_t now)
!(filename = next(&p, end)) ||
!(mode = next(&p, end)) ||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
{
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
is_err = 1;
}
else
{
if (strcasecmp(mode, "netascii") == 0)
@@ -307,8 +334,7 @@ void tftp_request(struct listener *listen, time_t now)
{
if (strcasecmp(opt, "blksize") == 0)
{
if ((opt = next(&p, end)) &&
(special || !option_bool(OPT_TFTP_NOBLOCK)))
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
{
transfer->blocksize = atoi(opt);
if (transfer->blocksize < 1)
@@ -330,9 +356,12 @@ void tftp_request(struct listener *listen, time_t now)
}
/* cope with backslashes from windows boxen. */
while ((p = strchr(filename, '\\')))
*p = '/';
for (p = filename; *p; p++)
if (*p == '\\')
*p = '/';
else if (option_bool(OPT_TFTP_LC))
*p = tolower(*p);
strcpy(daemon->namebuff, "/");
if (prefix)
{
@@ -342,7 +371,7 @@ void tftp_request(struct listener *listen, time_t now)
if (prefix[strlen(prefix)-1] != '/')
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
if (!special && option_bool(OPT_TFTP_APREF))
if (option_bool(OPT_TFTP_APREF))
{
size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf;
@@ -369,7 +398,7 @@ void tftp_request(struct listener *listen, time_t now)
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix, special)))
if ((transfer->file = check_tftp_fileperm(&len, prefix)))
{
if ((len = get_block(packet, transfer)) == -1)
len = tftp_err_oops(packet, daemon->namebuff);
@@ -379,7 +408,7 @@ void tftp_request(struct listener *listen, time_t now)
}
while (sendto(transfer->sockfd, packet, len, 0,
(struct sockaddr *)&peer, sizeof(peer)) == -1 && errno == EINTR);
(struct sockaddr *)&peer, sa_len(&peer)) == -1 && errno == EINTR);
if (is_err)
free_transfer(transfer);
@@ -390,7 +419,7 @@ void tftp_request(struct listener *listen, time_t now)
}
}
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int special)
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
{
char *packet = daemon->packet, *namebuff = daemon->namebuff;
struct tftp_file *file;
@@ -427,7 +456,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int spe
goto perm;
}
/* in secure mode, must be owned by user running dnsmasq */
else if (!special && option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
else if (option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
goto perm;
/* If we're doing many tranfers from the same file, only
@@ -487,12 +516,12 @@ void check_tftp_listeners(fd_set *rset, time_t now)
{
tmp = transfer->next;
prettyprint_addr(&transfer->peer, daemon->addrbuff);
if (FD_ISSET(transfer->sockfd, rset))
{
/* we overwrote the buffer... */
daemon->srv_save = NULL;
prettyprint_addr(&transfer->peer, daemon->addrbuff);
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
{
@@ -514,14 +543,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
if (!err)
err = "";
else
{
unsigned char *q, *r;
for (q = r = (unsigned char *)err; *r; r++)
if (isprint(*r))
*(q++) = *r;
*q = 0;
}
sanitise(err);
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
(int)ntohs(mess->block), err,
daemon->addrbuff);
@@ -548,32 +571,33 @@ void check_tftp_listeners(fd_set *rset, time_t now)
len = tftp_err_oops(daemon->packet, transfer->file->filename);
endcon = 1;
}
else if (++transfer->backoff > 5)
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
else if (++transfer->backoff > 7 && len != 0)
{
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
if (len != 0)
{
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
transfer->file->filename, daemon->addrbuff);
len = 0;
endcon = 1;
}
endcon = 1;
len = 0;
}
if (len != 0)
while(sendto(transfer->sockfd, daemon->packet, len, 0,
(struct sockaddr *)&transfer->peer, sizeof(transfer->peer)) == -1 && errno == EINTR);
(struct sockaddr *)&transfer->peer, sa_len(&transfer->peer)) == -1 && errno == EINTR);
if (endcon || len == 0)
{
if (!endcon)
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
strcpy(daemon->namebuff, transfer->file->filename);
sanitise(daemon->namebuff);
my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
/* unlink */
*up = tmp;
/* put on queue to be sent to script and deleted */
transfer->next = daemon->tftp_done_trans;
daemon->tftp_done_trans = transfer;
if (endcon)
free_transfer(transfer);
else
{
/* put on queue to be sent to script and deleted */
transfer->next = daemon->tftp_done_trans;
daemon->tftp_done_trans = transfer;
}
continue;
}
}
@@ -607,6 +631,16 @@ static char *next(char **p, char *end)
return ret;
}
static void sanitise(char *buf)
{
unsigned char *q, *r;
for (q = r = (unsigned char *)buf; *r; r++)
if (isprint((int)*r))
*(q++) = *r;
*q = 0;
}
static ssize_t tftp_err(int err, char *packet, char *message, char *file)
{
struct errmess {
@@ -615,7 +649,9 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
} *mess = (struct errmess *)packet;
ssize_t ret = 4;
char *errstr = strerror(errno);
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);
ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
@@ -626,7 +662,9 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
static ssize_t tftp_err_oops(char *packet, char *file)
{
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), file);
/* May have >1 refs to file, so potentially mangle a copy of the name */
strcpy(daemon->namebuff, file);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
}
/* return -1 for error, zero for done. */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2014 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,31 @@ 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
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 +109,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 == '.')
@@ -142,17 +143,20 @@ static int check_name(char *in)
int legal_hostname(char *name)
{
char c;
int first;
if (!check_name(name))
return 0;
for (; (c = *name); name++)
for (first = 1; (c = *name); name++, first = 0)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_')
(c >= '0' && c <= '9'))
continue;
if (!first && (c == '-' || c == '_'))
continue;
/* end of hostname part */
@@ -280,7 +284,7 @@ int sa_len(union mysockaddr *addr)
}
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
int hostname_isequal(char *a, char *b)
int hostname_isequal(const char *a, const char *b)
{
unsigned int c1, c2;
@@ -330,7 +334,7 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
return 0;
if (pfbits == 0 ||
(a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
(a->s6_addr[pfbytes] >> (8 - pfbits) == b->s6_addr[pfbytes] >> (8 - pfbits)))
return 1;
return 0;
@@ -426,7 +430,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
while (maxlen == -1 || i < maxlen)
{
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
for (r = in; *r != 0 && *r != ':' && *r != '-' && *r != ' '; r++)
if (*r != '*' && !isxdigit((unsigned char)*r))
return -1;
@@ -444,12 +448,29 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
else
{
*r = 0;
mask = mask << 1;
if (strcmp(in, "*") == 0)
mask |= 1;
{
mask = (mask << 1) | 1;
i++;
}
else
out[i] = strtol(in, NULL, 16);
i++;
{
int j, bytes = (1 + (r - in))/2;
for (j = 0; j < bytes; j++)
{
char sav = sav;
if (j < bytes - 1)
{
sav = in[(j+1)*2];
in[(j+1)*2] = 0;
}
out[i] = strtol(&in[j*2], NULL, 16);
mask = mask << 1;
i++;
if (j < bytes - 1)
in[(j+1)*2] = sav;
}
}
}
}
in = r+1;
@@ -564,3 +585,20 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
return 1;
}
/* Basically match a string value against a wildcard pattern. */
int wildcard_match(const char* wildcard, const char* match)
{
while (*wildcard && *match)
{
if (*wildcard == '*')
return 1;
if (*wildcard != *match)
return 0;
++wildcard;
++match;
}
return *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