mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
255
Commits
v2.81rc4
...
v2.87test4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72fac0810c | ||
|
|
c166c07a93 | ||
|
|
39a625ff72 | ||
|
|
ad32ca18a7 | ||
|
|
efea282396 | ||
|
|
33d6a01cd3 | ||
|
|
d290630d31 | ||
|
|
d2ad5dc073 | ||
|
|
68ab5127af | ||
|
|
089a11f340 | ||
|
|
de1d04eb66 | ||
|
|
ed4e7defd7 | ||
|
|
267ab619c4 | ||
|
|
0140454ba2 | ||
|
|
2c60441239 | ||
|
|
cbbd56c965 | ||
|
|
2561f9fe0e | ||
|
|
47aefca5e4 | ||
|
|
981fb03710 | ||
|
|
ef2f8d70d2 | ||
|
|
d9995a1add | ||
|
|
ea7a05ad43 | ||
|
|
26bbf5a314 | ||
|
|
c147329823 | ||
|
|
eb88eed1fc | ||
|
|
8312a3ba4f | ||
|
|
35f93081dc | ||
|
|
de372d6914 | ||
|
|
4ac517e4ac | ||
|
|
e3651367b3 | ||
|
|
02ea41ddd1 | ||
|
|
51ffae4eab | ||
|
|
afe84f37f8 | ||
|
|
0afeef0e00 | ||
|
|
94a17fd97f | ||
|
|
5b5ec55445 | ||
|
|
1e6565c1a5 | ||
|
|
fc522515b9 | ||
|
|
9881b0736d | ||
|
|
e52b4b1466 | ||
|
|
2f45670951 | ||
|
|
50d75ae514 | ||
|
|
dea69a12aa | ||
|
|
e0ce3c12f2 | ||
|
|
93cf516bf1 | ||
|
|
6f4de018af | ||
|
|
6e91cf3172 | ||
|
|
9cb7f8a655 | ||
|
|
5d8d1ad14b | ||
|
|
cac9ca38f6 | ||
|
|
c4523639d5 | ||
|
|
1ce1c6beae | ||
|
|
51d56df7a3 | ||
|
|
860a9a57d6 | ||
|
|
c83e33d608 | ||
|
|
7b80c75d9d | ||
|
|
79337f99ae | ||
|
|
a42ee397f3 | ||
|
|
e58f8bb8c1 | ||
|
|
58cf958e41 | ||
|
|
06d01f7ae4 | ||
|
|
1a33eec0ba | ||
|
|
82de7a1e96 | ||
|
|
8e9bde57c5 | ||
|
|
1bb70e08be | ||
|
|
9afcb7ae61 | ||
|
|
545c4955e6 | ||
|
|
2f2d59b35c | ||
|
|
a1729deed3 | ||
|
|
fc64b97cd5 | ||
|
|
daddc8cb80 | ||
|
|
527c3c7d0d | ||
|
|
fcb4dcaf7c | ||
|
|
3ca4995d34 | ||
|
|
d387f8f06c | ||
|
|
ea43234c86 | ||
|
|
867e56a45e | ||
|
|
a163c63787 | ||
|
|
8389b943d3 | ||
|
|
f2266d9678 | ||
|
|
56bd806978 | ||
|
|
ac7eeea44d | ||
|
|
b741059549 | ||
|
|
cbd984287f | ||
|
|
32e15c3f45 | ||
|
|
f0dc324e35 | ||
|
|
f83c6cf51a | ||
|
|
c068b3ae2f | ||
|
|
adf9dec1e6 | ||
|
|
767d9cbd96 | ||
|
|
e7ccd95c04 | ||
|
|
719f79a8fd | ||
|
|
96f6444958 | ||
|
|
df25f204ba | ||
|
|
8acdc3ede7 | ||
|
|
857b445522 | ||
|
|
5bcca1219a | ||
|
|
4558c26fcd | ||
|
|
a92c6d77dc | ||
|
|
0c95a5ff53 | ||
|
|
cb6d06bb54 | ||
|
|
3ef955c85a | ||
|
|
5e95c16c32 | ||
|
|
4205e2ebcf | ||
|
|
9d806c51c2 | ||
|
|
a38bb31727 | ||
|
|
8a1ef367e2 | ||
|
|
1291865c92 | ||
|
|
a9ebbee7b6 | ||
|
|
06df5ad7d0 | ||
|
|
66b863c989 | ||
|
|
c9efe8e5e1 | ||
|
|
d515223bb5 | ||
|
|
b908f4334b | ||
|
|
6261aba026 | ||
|
|
85bc7534da | ||
|
|
1b30fd1732 | ||
|
|
8c9196bff8 | ||
|
|
b1daf44954 | ||
|
|
11c52d032b | ||
|
|
be291d979d | ||
|
|
6d1edd8d32 | ||
|
|
25ff956c7d | ||
|
|
38179500f8 | ||
|
|
5f7be5f0d6 | ||
|
|
627056febb | ||
|
|
cbd76447fd | ||
|
|
a60a233329 | ||
|
|
a0a3b8ad3e | ||
|
|
d0ae3f5a4d | ||
|
|
6860cf932b | ||
|
|
0276e0805b | ||
|
|
06ff3d8a26 | ||
|
|
1a3b69aa56 | ||
|
|
8237d06ab7 | ||
|
|
1c9f136b57 | ||
|
|
5ab7e4a475 | ||
|
|
3236f358f8 | ||
|
|
4a6550d69a | ||
|
|
ff523d0c67 | ||
|
|
3c93e8eb41 | ||
|
|
88a482fdb9 | ||
|
|
12a9aa7c62 | ||
|
|
50ccf9c585 | ||
|
|
d100eb05a3 | ||
|
|
10d8b5f001 | ||
|
|
ffd3ceb856 | ||
|
|
d942aa9321 | ||
|
|
6469fefe89 | ||
|
|
b082842ee7 | ||
|
|
3573ca0eec | ||
|
|
ad90eb075d | ||
|
|
d55e2d086d | ||
|
|
fe9c966a49 | ||
|
|
9f20afb1a8 | ||
|
|
f61afcfc70 | ||
|
|
961daf8f92 | ||
|
|
64a16cb376 | ||
|
|
ea6b0b2665 | ||
|
|
89df73ac05 | ||
|
|
7d3f3c9983 | ||
|
|
1bdbea2461 | ||
|
|
dfb1f7ccf1 | ||
|
|
b5d1b20727 | ||
|
|
2a407a76be | ||
|
|
d1640a6338 | ||
|
|
26b5c40d95 | ||
|
|
0b3ecf7432 | ||
|
|
8f9bd61505 | ||
|
|
ea28d0ef8a | ||
|
|
4a8c098840 | ||
|
|
ffa4628faa | ||
|
|
e10a9239e1 | ||
|
|
51f7bc924c | ||
|
|
6c0bf79078 | ||
|
|
4b03170920 | ||
|
|
1de6bbc108 | ||
|
|
023ace8e54 | ||
|
|
74d4fcd756 | ||
|
|
9eaa91bfc3 | ||
|
|
484bd75ce4 | ||
|
|
4c30e9602b | ||
|
|
b260d222af | ||
|
|
6528d62cd2 | ||
|
|
b7cf754f6f | ||
|
|
14e3f6ba19 | ||
|
|
a8c1474562 | ||
|
|
8b8a4148ec | ||
|
|
9e147480ed | ||
|
|
4c0aecc685 | ||
|
|
d556b8a5d5 | ||
|
|
e7c0d7b348 | ||
|
|
17360439dc | ||
|
|
9e169a9bea | ||
|
|
305cb79c57 | ||
|
|
141a26f979 | ||
|
|
cfcafdd27c | ||
|
|
f1204a875e | ||
|
|
20295012b8 | ||
|
|
807e82343a | ||
|
|
c8e8f5c204 | ||
|
|
a69b017902 | ||
|
|
e75069f79a | ||
|
|
3f535da79e | ||
|
|
8ebdc364af | ||
|
|
12af2b171d | ||
|
|
04490bf622 | ||
|
|
327bbc92bc | ||
|
|
cc0b4489c7 | ||
|
|
9212ad284f | ||
|
|
503f68dbc4 | ||
|
|
e01e09c712 | ||
|
|
6a6e06fbb0 | ||
|
|
2024f97297 | ||
|
|
25e63f1e56 | ||
|
|
15b60ddf93 | ||
|
|
824461192c | ||
|
|
1eb6cedb03 | ||
|
|
059aded070 | ||
|
|
2d765867c5 | ||
|
|
257ac0c5f7 | ||
|
|
4e96a4be68 | ||
|
|
a2a7e040b1 | ||
|
|
4ded96209e | ||
|
|
f60fea1fb0 | ||
|
|
4d85e409cd | ||
|
|
2bd02d2f59 | ||
|
|
7e194a0a7d | ||
|
|
9beb4d9ea2 | ||
|
|
ab5ebe9507 | ||
|
|
837e8f4eb5 | ||
|
|
e2cb655958 | ||
|
|
8270648da1 | ||
|
|
619000a3c5 | ||
|
|
1c1b925052 | ||
|
|
49bdf1ead9 | ||
|
|
60a3ae19c5 | ||
|
|
951a22165c | ||
|
|
51cdd1a227 | ||
|
|
66adee85be | ||
|
|
4890bcdea2 | ||
|
|
8baf583a3f | ||
|
|
913fa15fb1 | ||
|
|
00fe2f49e0 | ||
|
|
ec2067df75 | ||
|
|
7ddb99d251 | ||
|
|
ba26d3485b | ||
|
|
081a1c4014 | ||
|
|
532246fc9e | ||
|
|
8caf3d7c6c | ||
|
|
d162bee356 | ||
|
|
b43585c34b | ||
|
|
3f60ecd6f0 | ||
|
|
0506a5ed4e | ||
|
|
e7ee1aa093 |
No files matched your search
@@ -1,12 +1,261 @@
|
||||
version 2.87
|
||||
Allow arbitrary prefix lengths in --rev-server and
|
||||
--domain=....,local
|
||||
|
||||
Replace --address=/#/..... functionality which got
|
||||
missed in the 2.86 domain search rewrite.
|
||||
|
||||
Add --nftset option, like --ipset but for the newer nftables.
|
||||
Thanks to Chen Zhenge for the patch.
|
||||
|
||||
|
||||
version 2.86
|
||||
Handle DHCPREBIND requests in the DHCPv6 server code.
|
||||
Thanks to Aichun Li for spotting this omission, and the initial
|
||||
patch.
|
||||
|
||||
Fix bug which caused dnsmasq to lose track of processes forked
|
||||
to handle TCP DNS connections under heavy load. The code
|
||||
checked that at least one free process table slot was
|
||||
available before listening on TCP sockets, but didn't take
|
||||
into account that more than one TCP connection could
|
||||
arrive, so that check was not sufficient to ensure that
|
||||
there would be slots for all new processes. It compounded
|
||||
this error by silently failing to store the process when
|
||||
it did run out of slots. Even when this bug is triggered,
|
||||
all the right things happen, and answers are still returned.
|
||||
Only under very exceptional circumstances, does the bug
|
||||
manifest itself: see
|
||||
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q2/014976.html
|
||||
Thanks to Tijs Van Buggenhout for finding the conditions under
|
||||
which the bug manifests itself, and then working out
|
||||
exactly what was going on.
|
||||
|
||||
Major rewrite of the DNS server and domain handling code.
|
||||
This should be largely transparent, but it drastically
|
||||
improves performance and reduces memory foot-print when
|
||||
configuring large numbers domains of the form
|
||||
local=/adserver.com/
|
||||
or
|
||||
local=/adserver.com/#
|
||||
Lookup times now grow as log-to-base-2 of the number of domains,
|
||||
rather than greater than linearly, as before.
|
||||
The change makes multiple addresses associated with a domain work
|
||||
address=/example.com/1.2.3.4
|
||||
address=/example.com/5.6.7.8
|
||||
It also handles multiple upstream servers for a domain better; using
|
||||
the same try/retry algorithms as non domain-specific servers. This
|
||||
also applies to DNSSEC-generated queries.
|
||||
Finally, some of the oldest and gnarliest code in dnsmasq has had
|
||||
a significant clean-up. It's far from perfect, but it _is_ better.
|
||||
|
||||
Revise resource handling for number of concurrent DNS queries. This
|
||||
used to have a global limit, but that has a problem when using
|
||||
different servers for different upstream domains. Queries which are
|
||||
routed by domain to an upstream server which is not responding will
|
||||
build up and trigger the limit, which breaks DNS service for
|
||||
all other domains which could be handled by other servers. The
|
||||
change is to make the limit per server-group, where a server group
|
||||
is the set of servers configured for a particular domain. In the
|
||||
common case, where only default servers are declared, there is
|
||||
no effective change.
|
||||
|
||||
Improve efficiency of DNSSEC. The sharing point for DNSSEC RR data
|
||||
used to be when it entered the cache, having been validated. After
|
||||
that queries requiring the KEY or DS records would share the cached
|
||||
values. There is a common case in dual-stack hosts that queries for
|
||||
A and AAAA records for the same domain are made simultaneously.
|
||||
If required keys were not in the cache, this would result in two
|
||||
requests being sent upstream for the same key data (and all the
|
||||
subsequent chain-of-trust queries.) Now we combine these requests
|
||||
and elide the duplicates, resulting in fewer queries upstream
|
||||
and better performance. To keep a better handle on what's
|
||||
going on, the "extra" logging mode has been modified to associate
|
||||
queries and answers for DNSSEC queries in the same way as ordinary
|
||||
queries. The requesting address and port have been removed from
|
||||
DNSSEC logging lines, since this is no longer strictly defined.
|
||||
|
||||
Connection track mark based DNS query filtering. Thanks to
|
||||
Etan Kissling for implementing this It extends query filtering
|
||||
support beyond what is currently possible
|
||||
with the `--ipset` configuration option, by adding support for:
|
||||
1) Specifying allowlists on a per-client basis, based on their
|
||||
associated Linux connection track mark.
|
||||
2) Dynamic configuration of allowlists via Ubus.
|
||||
3) Reporting when a DNS query resolves or is rejected via Ubus.
|
||||
4) DNS name patterns containing wildcards.
|
||||
Disallowed queries are not forwarded; they are rejected
|
||||
with a REFUSED error code.
|
||||
|
||||
Allow smaller than 64 prefix lengths in synth-domain, with caveats.
|
||||
--synth-domain=1234:4567::/56,example.com is now valid.
|
||||
|
||||
Make domains generated by --synth-domain appear in replies
|
||||
when in authoritative mode.
|
||||
|
||||
Ensure CAP_NET_ADMIN capability is available when
|
||||
conntrack is configured. Thanks to Yick Xie for spotting
|
||||
the lack of this.
|
||||
|
||||
When --dhcp-hostsfile --dhcp-optsfile and --addn-hosts are
|
||||
given a directory as argument, define the order in which
|
||||
files within that directory are read (alphabetical order
|
||||
of filename). Thanks to Ed Wildgoose for the initial patch
|
||||
and motivation for this.
|
||||
|
||||
Allow adding IP address to nftables set in addition to
|
||||
ipset.
|
||||
|
||||
|
||||
version 2.85
|
||||
Fix problem with DNS retries in 2.83/2.84.
|
||||
The new logic in 2.83/2.84 which merges distinct requests
|
||||
for the same domain causes problems with clients which do
|
||||
retries as distinct requests (differing IDs and/or source ports.)
|
||||
The retries just get piggy-backed on the first, failed, request.
|
||||
The logic is now changed so that distinct requests for repeated
|
||||
queries still get merged into a single ID/source port, but
|
||||
they now always trigger a re-try upstream.
|
||||
Thanks to Nicholas Mu for his analysis.
|
||||
|
||||
Tweak sort order of tags in get-version. v2.84 sorts
|
||||
before v2.83, but v2.83 sorts before v2.83rc1 and 2.83rc1
|
||||
sorts before v2.83test1. This fixes the problem which lead
|
||||
to 2.84 announcing itself as 2.84rc2.
|
||||
|
||||
Avoid treating a --dhcp-host which has an IPv6 address
|
||||
as eligible for use with DHCPv4 on the grounds that it has
|
||||
no address, and vice-versa. Thanks to Viktor Papp for
|
||||
spotting the problem. (This bug was fixed was back in 2.67, and
|
||||
then regressed in 2.81).
|
||||
|
||||
Add --dynamic-host option: A and AAAA records which take their
|
||||
network part from the network of a local interface. Useful
|
||||
for routers with dynamically prefixes. Thanks
|
||||
to Fred F for the suggestion.
|
||||
|
||||
Teach --bogus-nxdomain and --ignore-address to take an IPv4 subnet.
|
||||
|
||||
Use random source ports where possible if source
|
||||
addresses/interfaces in use.
|
||||
CVE-2021-3448 applies. Thanks to Petr Menšík for spotting this.
|
||||
It's possible to specify the source address or interface to be
|
||||
used when contacting upstream name servers: server=8.8.8.8@1.2.3.4
|
||||
or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
|
||||
these have, until now, used a single socket, bound to a fixed
|
||||
port. This was originally done to allow an error (non-existent
|
||||
interface, or non-local address) to be detected at start-up. This
|
||||
means that any upstream servers specified in such a way don't use
|
||||
random source ports, and are more susceptible to cache-poisoning
|
||||
attacks.
|
||||
We now use random ports where possible, even when the
|
||||
source is specified, so server=8.8.8.8@1.2.3.4 or
|
||||
server=8.8.8.8@eth0 will use random source
|
||||
ports. server=8.8.8.8@1.2.3.4#66 or any use of --query-port will
|
||||
use the explicitly configured port, and should only be done with
|
||||
understanding of the security implications.
|
||||
Note that this change changes non-existing interface, or non-local
|
||||
source address errors from fatal to run-time. The error will be
|
||||
logged and communication with the server not possible.
|
||||
|
||||
Change the method of allocation of random source ports for DNS.
|
||||
Previously, without min-port or max-port configured, dnsmasq would
|
||||
default to the compiled in defaults for those, which are 1024 and
|
||||
65535. Now, when neither are configured, it defaults instead to
|
||||
the kernel's ephemeral port range, which is typically
|
||||
32768 to 60999 on Linux systems. This change eliminates the
|
||||
possibility that dnsmasq may be using a registered port > 1024
|
||||
when a long-running daemon starts up and wishes to claim it.
|
||||
This change does likely slightly reduce the number of random ports
|
||||
and therefore the protection from reply spoofing. The older
|
||||
behaviour can be restored using the min-port and max-port config
|
||||
switches should that be a concern.
|
||||
|
||||
Scale the size of the DNS random-port pool based on the
|
||||
value of the --dns-forward-max configuration.
|
||||
|
||||
Tweak TFTP code to check sender of all received packets, as
|
||||
specified in RFC 1350 para 4.
|
||||
|
||||
Support some wildcard matching of input tags to --tag-if.
|
||||
Thanks to Geoff Back for the idea and the patch.
|
||||
|
||||
|
||||
version 2.84
|
||||
Fix a problem, introduced in 2.83, which could see DNS replies
|
||||
being sent via the wrong socket. On machines running both
|
||||
IPv4 and IPv6 this could result in sporadic messages of
|
||||
the form "failed to send packet: Network is unreachable" and
|
||||
the lost of the query. Since the error is sporadic and of
|
||||
low probability, the client retry would normally succeed.
|
||||
|
||||
Change HAVE_NETTLEHASH compile-time to HAVE_CRYPTOHASH.
|
||||
|
||||
|
||||
version 2.83
|
||||
Use the values of --min-port and --max-port in outgoing
|
||||
TCP connections to upstream DNS servers.
|
||||
|
||||
Fix a remote buffer overflow problem in the DNSSEC code. Any
|
||||
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
referenced by CVE-2020-25681, CVE-2020-25682, CVE-2020-25683
|
||||
CVE-2020-25687.
|
||||
|
||||
Be sure to only accept UDP DNS query replies at the address
|
||||
from which the query was originated. This keeps as much entropy
|
||||
in the {query-ID, random-port} tuple as possible, to help defeat
|
||||
cache poisoning attacks. Refer: CVE-2020-25684.
|
||||
|
||||
Use the SHA-256 hash function to verify that DNS answers
|
||||
received are for the questions originally asked. This replaces
|
||||
the slightly insecure SHA-1 (when compiled with DNSSEC) or
|
||||
the very insecure CRC32 (otherwise). Refer: CVE-2020-25685.
|
||||
|
||||
Handle multiple identical near simultaneous DNS queries better.
|
||||
Previously, such queries would all be forwarded
|
||||
independently. This is, in theory, inefficient but in practise
|
||||
not a problem, _except_ that is means that an answer for any
|
||||
of the forwarded queries will be accepted and cached.
|
||||
An attacker can send a query multiple times, and for each repeat,
|
||||
another {port, ID} becomes capable of accepting the answer he is
|
||||
sending in the blind, to random IDs and ports. The chance of a
|
||||
successful attack is therefore multiplied by the number of repeats
|
||||
of the query. The new behaviour detects repeated queries and
|
||||
merely stores the clients sending repeats so that when the
|
||||
first query completes, the answer can be sent to all the
|
||||
clients who asked. Refer: CVE-2020-25686.
|
||||
|
||||
|
||||
version 2.82
|
||||
Improve behaviour in the face of network interfaces which come
|
||||
and go and change index. Thanks to Petr Mensik for the patch.
|
||||
|
||||
Convert hard startup failure on NETLINK_NO_ENOBUFS under qemu-user
|
||||
to a warning.
|
||||
|
||||
Allow IPv6 addresses ofthe form [::ffff:1.2.3.4] in --dhcp-option.
|
||||
|
||||
Fix crash under heavy TCP connection load introduced in 2.81.
|
||||
Thanks to Frank for good work chasing this down.
|
||||
|
||||
Change default lease time for DHCPv6 to one day.
|
||||
|
||||
Alter calculation of preferred and valid times in router
|
||||
advertisements, so that these do not have a floor applied
|
||||
of the lease time in the dhcp-range if this is not explicitly
|
||||
specified and is merely the default.
|
||||
Thanks to Martin-Éric Racine for suggestions on this.
|
||||
|
||||
|
||||
version 2.81
|
||||
Impove cache behaviour for TCP connections. For ease of
|
||||
implementaion, dnsmasq has always forked a new process to handle
|
||||
Improve cache behaviour for TCP connections. For ease of
|
||||
implementation, dnsmasq has always forked a new process to handle
|
||||
each incoming TCP connection. A side-effect of this is that
|
||||
any DNS queries answered from TCP connections are not cached:
|
||||
when TCP connections were rare, this was not a problem.
|
||||
With the coming of DNSSEC, it's now the case that some
|
||||
With the coming of DNSSEC, it is now the case that some
|
||||
DNSSEC queries have answers which spill to TCP, and if,
|
||||
for instance, this applies to the keys for the root then
|
||||
for instance, this applies to the keys for the root, then
|
||||
those never get cached, and performance is very bad.
|
||||
This fix passes cache entries back from the TCP child process to
|
||||
the main server process, and fixes the problem.
|
||||
@@ -35,7 +284,7 @@ version 2.81
|
||||
configuration.
|
||||
|
||||
Add --shared-network config. This enables allocation of addresses
|
||||
the DHCP server in subnets where the server (or relay) doesn't
|
||||
by the DHCP server in subnets where the server (or relay) does not
|
||||
have an interface on the network in that subnet. Many thanks to
|
||||
kamp.de for sponsoring this feature.
|
||||
|
||||
@@ -66,7 +315,7 @@ version 2.81
|
||||
Evgenii Seliavka for the suggestion and initial patch.
|
||||
|
||||
In the router advert code, handle case where we have two
|
||||
different interfaces on the same IPv6 net, and we're doing
|
||||
different interfaces on the same IPv6 net, and we are doing
|
||||
RA/DHCP service on only one of them. Thanks to NIIBE Yutaka
|
||||
for spotting this case and making the initial patch.
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ 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 are these strange "bind-interface" and "bind-dynamic" options?
|
||||
Q: What are these strange "bind-interfaces" and "bind-dynamic" options?
|
||||
|
||||
A: Dnsmasq from v2.63 can operate in one of three different "networking
|
||||
modes". This is unfortunate as it requires users configuring dnsmasq
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
# dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -53,7 +53,7 @@ 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`
|
||||
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy -lubox -lubus`
|
||||
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
|
||||
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
|
||||
@@ -62,11 +62,17 @@ ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CON
|
||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
|
||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
|
||||
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`
|
||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
||||
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
||||
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
|
||||
HAVE_CRYPTOHASH $(PKG_CONFIG) --libs nettle \
|
||||
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
|
||||
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
|
||||
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
|
||||
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
|
||||
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
|
||||
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
|
||||
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
|
||||
@@ -75,9 +81,10 @@ copts_conf = .copts_$(sum)
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o pattern.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
|
||||
metrics.o hash-questions.o domain-match.o nftset.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
@@ -85,8 +92,8 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
all : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
mostly_clean :
|
||||
@@ -110,8 +117,8 @@ all-i18n : $(BUILDDIR)
|
||||
@cd $(BUILDDIR) && $(MAKE) \
|
||||
top="$(top)" \
|
||||
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
for f in `cd $(PO); echo *.po`; do \
|
||||
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
||||
crypto.c dump.c ubus.c
|
||||
crypto.c dump.c ubus.c metrics.c hash-questions.c \
|
||||
domain-match.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
+5
-2
@@ -9,7 +9,10 @@
|
||||
# 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.
|
||||
# first. The insane arguments to the sort command are to ensure
|
||||
# that, eg v2.64 comes before v2.63, but v2.63 comes before v2.63rc1
|
||||
# and v2.63rc1 comes before v2.63test1
|
||||
|
||||
|
||||
# Change directory to the toplevel source directory.
|
||||
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
|
||||
@@ -28,7 +31,7 @@ else
|
||||
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "${vers}" | sort -r | head -n 1 | sed 's/^v//'
|
||||
echo "${vers}" | sort -k1.2,1.5Vr -k1.6,1.6 -k1.8,1.9Vr -k1.10,1.11Vr | head -n 1 | sed 's/^v//'
|
||||
else
|
||||
cat $1/VERSION
|
||||
fi
|
||||
|
||||
+22
-19
@@ -1,35 +1,37 @@
|
||||
#!/bin/sh
|
||||
|
||||
search=$1
|
||||
shift
|
||||
pkg=$1
|
||||
shift
|
||||
op=$1
|
||||
shift
|
||||
|
||||
in=`cat`
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $search >/dev/null 2>&1; then
|
||||
search()
|
||||
{
|
||||
grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $1 >/dev/null 2>&1
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
search=$1
|
||||
pkg=$2
|
||||
op=$3
|
||||
lib=$4
|
||||
shift 4
|
||||
if search "$search"; then
|
||||
|
||||
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
|
||||
if [ $op = "--copy" ]; then
|
||||
if [ -z "$pkg" ]; then
|
||||
pkg="$*"
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*$pkg" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep $pkg >/dev/null 2>&1; then
|
||||
pkg="$lib"
|
||||
elif search "$pkg"; then
|
||||
pkg=""
|
||||
else
|
||||
pkg="$*"
|
||||
pkg="$lib"
|
||||
fi
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
elif search "${search}_STATIC"; then
|
||||
pkg=`$pkg --static $op $lib`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
pkg=`$pkg $op $lib`
|
||||
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 search "${search}_STATIC"; then
|
||||
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
|
||||
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
|
||||
else
|
||||
@@ -40,3 +42,4 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
fi
|
||||
fi
|
||||
|
||||
done
|
||||
@@ -1,6 +0,0 @@
|
||||
This packaging is now unmaintained in the dnsmasq source: dnsmasq is
|
||||
included in Suse proper, and up-to-date packages are now available
|
||||
from
|
||||
|
||||
ftp://ftp.suse.com/pub/people/ug/
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
|
||||
It fixes the dependency from the dns daemon name 'named'
|
||||
After appending the patch, the SuSEfirewall is again able to autodetect
|
||||
the dnsmasq named service.
|
||||
This is a very old bug in the SuSEfirewall script.
|
||||
The SuSE people think the name of the dns server will always 'named'
|
||||
|
||||
|
||||
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
|
||||
+++ /sbin/SuSEfirewall2 2004-01-23 13:31:56.000000000 +0100
|
||||
@@ -764,7 +764,7 @@
|
||||
echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
|
||||
|
||||
test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
|
||||
- test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
|
||||
+ test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
|
||||
echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
|
||||
You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
|
||||
FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
|
||||
@@ -878,7 +878,7 @@
|
||||
test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
|
||||
# Get ports/IP bindings of NAMED/SQUID
|
||||
test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
|
||||
- $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
+ $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
|
||||
test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
|
||||
$AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`
|
||||
@@ -1,23 +0,0 @@
|
||||
--- man/dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
||||
+++ man/dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -69,7 +69,7 @@
|
||||
.TP
|
||||
.B \-g, --group=<groupname>
|
||||
Specify the group which dnsmasq will run
|
||||
-as. The defaults to "dip", if available, to facilitate access to
|
||||
+as. The defaults to "dialout", if available, to facilitate access to
|
||||
/etc/ppp/resolv.conf which is not normally world readable.
|
||||
.TP
|
||||
.B \-v, --version
|
||||
--- src/config.h 2004-08-11 11:39:18.000000000 +0200
|
||||
+++ src/config.h 2004-08-12 00:40:01.000000000 +0200
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
-#define CHGRP "dip"
|
||||
+#define CHGRP "dialout"
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
###############################################################################
|
||||
#
|
||||
# General
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
Name: dnsmasq
|
||||
Version: 2.33
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Productivity/Networking/DNS/Servers
|
||||
Vendor: Simon Kelley
|
||||
Packager: Simon Kelley
|
||||
URL: http://www.thekelleys.org.uk/dnsmasq
|
||||
Provides: dns_daemon
|
||||
Conflicts: bind bind8 bind9
|
||||
PreReq: %fillup_prereq %insserv_prereq
|
||||
Autoreqprov: on
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
BuildRoot: /var/tmp/%{name}-%{version}
|
||||
Summary: A lightweight caching nameserver
|
||||
|
||||
%description
|
||||
Dnsmasq is 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 for network booting of diskless machines.
|
||||
|
||||
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Build
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
patch -p0 <rpm/%{name}-SuSE.patch
|
||||
|
||||
%build
|
||||
%{?suse_update_config:%{suse_update_config -f}}
|
||||
make all-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Install
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
mkdir -p ${RPM_BUILD_ROOT}/etc/init.d
|
||||
make install-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
|
||||
install -o root -g root -m 755 rpm/rc.dnsmasq-suse $RPM_BUILD_ROOT/etc/init.d/dnsmasq
|
||||
install -o root -g root -m 644 dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
|
||||
strip $RPM_BUILD_ROOT/usr/sbin/dnsmasq
|
||||
ln -sf ../../etc/init.d/dnsmasq $RPM_BUILD_ROOT/usr/sbin/rcdnsmasq
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-install scriptlet
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%post
|
||||
%{fillup_and_insserv dnsmasq}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# Post-uninstall scriptlet
|
||||
#
|
||||
# The %postun script executes after the package has been removed. It is the
|
||||
# last chance for a package to clean up after itself.
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%postun
|
||||
%{insserv_cleanup}
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# File list
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
|
||||
%doc contrib
|
||||
%config /etc/init.d/dnsmasq
|
||||
%config /etc/dnsmasq.conf
|
||||
/usr/sbin/rcdnsmasq
|
||||
/usr/sbin/dnsmasq
|
||||
/usr/share/locale/*/LC_MESSAGES/*
|
||||
%doc %{_mandir}/man8/dnsmasq.8.gz
|
||||
%doc %{_mandir}/*/man8/dnsmasq.8.gz
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# init.d/dnsmasq
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: dnsmasq
|
||||
# Required-Start: $network $remote_fs $syslog
|
||||
# Required-Stop:
|
||||
# Default-Start: 3 5
|
||||
# Default-Stop:
|
||||
# Description: Starts internet name service masq caching server (DNS)
|
||||
### END INIT INFO
|
||||
|
||||
NAMED_BIN=/usr/sbin/dnsmasq
|
||||
NAMED_PID=/var/run/dnsmasq.pid
|
||||
NAMED_CONF=/etc/dnsmasq.conf
|
||||
|
||||
if [ ! -x $NAMED_BIN ] ; then
|
||||
echo -n "dnsmasq not installed ! "
|
||||
exit 5
|
||||
fi
|
||||
|
||||
. /etc/rc.status
|
||||
rc_reset
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
if [ $? -eq 0 ] ; then
|
||||
echo -n "- Warning: dnsmasq already running ! "
|
||||
else
|
||||
[ -e $NAMED_PID ] && echo -n "- Warning: $NAMED_PID exists ! "
|
||||
fi
|
||||
startproc -p $NAMED_PID $NAMED_BIN -u nobody
|
||||
rc_status -v
|
||||
;;
|
||||
stop)
|
||||
echo -n "Shutting name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -TERM $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
try-restart)
|
||||
$0 stop && $0 start
|
||||
rc_status
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
rc_status
|
||||
;;
|
||||
force-reload)
|
||||
$0 reload
|
||||
rc_status
|
||||
;;
|
||||
reload)
|
||||
echo -n "Reloading name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
|
||||
killproc -p $NAMED_PID -HUP $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
status)
|
||||
echo -n "Checking for name service masq caching server "
|
||||
checkproc -p $NAMED_PID $NAMED_BIN
|
||||
rc_status -v
|
||||
;;
|
||||
probe)
|
||||
test $NAMED_CONF -nt $NAMED_PID && echo reload
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
rc_exit
|
||||
|
||||
@@ -153,7 +153,11 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[1]);
|
||||
if (inet_pton(AF_INET, argv[1], &lease) < 1)
|
||||
{
|
||||
fprintf(stderr, "invalid address: %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
@@ -176,8 +180,8 @@ int main(int argc, char **argv)
|
||||
|
||||
*(p++) = OPTION_END;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
dest.sin_family = AF_INET;
|
||||
(void)inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr);
|
||||
dest.sin_port = ntohs(DHCP_SERVER_PORT);
|
||||
|
||||
if (sendto(fd, &packet, sizeof(packet), 0,
|
||||
|
||||
@@ -280,6 +280,7 @@ int main(int argc, char **argv)
|
||||
|
||||
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
|
||||
a DHCP server */
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
|
||||
@@ -288,13 +289,12 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inet_addr(argv[2]) == INADDR_NONE)
|
||||
if (inet_pton(AF_INET, argv[2], &lease.s_addr) < 1)
|
||||
{
|
||||
perror("invalid ip address");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lease.s_addr = inet_addr(argv[2]);
|
||||
server = find_interface(lease, nl, if_nametoindex(argv[1]), fd, &ifr);
|
||||
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
|
||||
@@ -318,6 +318,12 @@ void usage(const char* arg, FILE* stream)
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
}
|
||||
|
||||
static void fail_fatal(const char *errstr, int exitcode)
|
||||
{
|
||||
perror(errstr);
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
{
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
@@ -343,18 +349,19 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
|
||||
client_addr.sin6_flowinfo = 0;
|
||||
client_addr.sin6_scope_id =0;
|
||||
inet_pton(AF_INET6, "::", &client_addr.sin6_addr);
|
||||
bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6));
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
|
||||
perror("bind"); /* continue on bind error */
|
||||
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
|
||||
fail_fatal("inet_pton", 5);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
ssize_t recv_size = 0;
|
||||
int result;
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
fail_fatal("sendto failed", 4);
|
||||
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1)
|
||||
@@ -367,16 +374,18 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
else
|
||||
{
|
||||
perror("recvfrom");
|
||||
result = UNSPEC_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
else
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vendored
+79
-2
@@ -1,3 +1,79 @@
|
||||
dnsmasq (2.87-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Include new NFTset support in the build.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 08 Sep 2021 23:11:25 +0000
|
||||
|
||||
dnsmasq (2.86-1) unstable; urgency=low
|
||||
|
||||
* Fix debian/changelog format error. (closes: #986626)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 08 Apr 2021 22:39:00 +0100
|
||||
|
||||
dnsmasq (2.85-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Includes fix to CVE-2021-3448.
|
||||
* Fix manpage typos. (closes: #986150)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 03 Apr 2021 22:17:23 +0100
|
||||
|
||||
dnsmasq (2.84-1.2) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Bump old-version in dpkg-maintscript-helper dir_to_symlink calls to also
|
||||
clean up after upgrades to an earlier version in testing.
|
||||
|
||||
-- Andreas Beckmann <anbe@debian.org> Thu, 01 Apr 2021 16:01:51 +0200
|
||||
|
||||
dnsmasq (2.84-1.1) unstable; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* Fix symlink to directory conversion for /usr/share/doc/dnsmasq.
|
||||
This is achieved by directly calling dpkg-maintscript-helper in the preinst,
|
||||
postinst, and postrm scripts, since the package does not use debhelper.
|
||||
(Closes: #985282)
|
||||
|
||||
-- Sébastien Villemot <sebastien@debian.org> Sun, 28 Mar 2021 10:55:07 +0200
|
||||
|
||||
dnsmasq (2.84-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 24 Jan 2021 22:02:01 +0000
|
||||
|
||||
dnsmasq (2.83-1) unstable; urgency=high
|
||||
|
||||
* New upstream.
|
||||
* Includes fixes to CVE-2020-25681 - CVE-2020-25687 inclusive.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 15 Jan 2021 22:22:41 +0000
|
||||
|
||||
dnsmasq (2.82-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 22:22:41 +0000
|
||||
|
||||
dnsmasq (2.81-4) unstable; urgency=low
|
||||
|
||||
* Remove runit support when building for Ubuntu. (closes: #960401)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 21:52:44 +0000
|
||||
|
||||
dnsmasq (2.81-3) unstable; urgency=low
|
||||
|
||||
* Fixes to control file for bug 958100
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 19 Apr 2020 21:44:12 +0000
|
||||
|
||||
dnsmasq (2.81-2) unstable; urgency=low
|
||||
|
||||
* Fix FTBFS on kFreeBSD. (closes: #958100)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 18 Apr 2020 18:34:15 +0000
|
||||
|
||||
dnsmasq (2.81-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
@@ -12,8 +88,9 @@ dnsmasq (2.81-1) unstable; urgency=low
|
||||
* Fix breakage of dig +trace. (closes: #942363)
|
||||
* Fix build faliure with newer Nettle libraries. (closes: #940985)
|
||||
* Support runscript init-system (closes: #929884)
|
||||
* Security fix for CVE-2019-14834 (closes: #948373)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 27 Jan 2020 22:31:15 +0000
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 8 Apr 2020 17:33:15 +0000
|
||||
|
||||
dnsmasq (2.80-1) unstable; urgency=low
|
||||
|
||||
@@ -1011,7 +1088,7 @@ dnsmasq (2.6-2) unstable; urgency=low
|
||||
* Added note about the --bind-interfaces option to
|
||||
readme.Debian (closes: #241700)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 13 Apr 2004 18:37:55 +0000
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 13 Apr 2004 18:37:55 +0000
|
||||
|
||||
dnsmasq (2.6-1) unstable; urgency=low
|
||||
|
||||
|
||||
Vendored
+3
-2
@@ -3,8 +3,9 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10)
|
||||
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
|
||||
pkg-config, libnftables-dev
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
Vendored
+3
@@ -1,6 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
|
||||
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
|
||||
|
||||
# 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
|
||||
|
||||
Vendored
+3
@@ -1,6 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
|
||||
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
|
||||
|
||||
if [ purge = "$1" ]; then
|
||||
update-rc.d dnsmasq remove >/dev/null
|
||||
fi
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
|
||||
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
|
||||
Vendored
+1
@@ -60,6 +60,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
nodbus : omit DBus support.
|
||||
noconntrack : omit connection tracking support.
|
||||
noipset : omit IPset support.
|
||||
nonftset : omit nftset 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
|
||||
|
||||
Vendored
+22
-11
@@ -52,6 +52,10 @@ ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_LIBIDN2
|
||||
endif
|
||||
|
||||
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_NFTSET
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
DEB_COPTS += -DHAVE_CONNTRACK
|
||||
@@ -98,9 +102,10 @@ ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_DNSSEC
|
||||
endif
|
||||
|
||||
ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),kfreebsd)
|
||||
# For strlcpy in FreeBSD
|
||||
LDFLAGS += -lbsd
|
||||
LIBS += $(shell ${PKG_CONFIG} --libs libbsd-overlay)
|
||||
CFLAGS += $(shell ${PKG_CONFIG} --cflags libbsd-overlay)
|
||||
endif
|
||||
|
||||
define build_tree
|
||||
@@ -169,16 +174,20 @@ binary-indep: checkroot
|
||||
-d debian/trees/daemon/etc/resolvconf/update.d \
|
||||
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/trees/daemon/usr/share/dnsmasq \
|
||||
-d debian/trees/daemon/usr/share/doc/dnsmasq \
|
||||
-d debian/trees/daemon/etc/default \
|
||||
-d debian/trees/daemon/lib/systemd/system \
|
||||
-d debian/trees/daemon/usr/lib/tmpfiles.d \
|
||||
-d debian/trees/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm
|
||||
install -m 755 debian/postinst debian/postrm debian/preinst debian/prerm debian/trees/daemon/DEBIAN
|
||||
if ! dpkg-vendor --derives-from Ubuntu; then \
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst; \
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm; \
|
||||
cd debian/trees/daemon && find etc/sv -type f -printf '/%p\n' >>DEBIAN/conffiles; \
|
||||
fi
|
||||
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
@@ -190,7 +199,9 @@ binary-indep: checkroot
|
||||
install -m 644 debian/systemd@.service debian/trees/daemon/lib/systemd/system/dnsmasq@.service
|
||||
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
|
||||
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
|
||||
install -m 644 debian/copyright debian/trees/daemon/usr/share/doc/dnsmasq/copyright
|
||||
install -m 644 debian/changelog debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
gzip -9n debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/dnsmasq.substvars -pdnsmasq -Pdebian/trees/daemon
|
||||
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
@@ -200,7 +211,7 @@ binary-indep: checkroot
|
||||
|
||||
binary-arch: checkroot
|
||||
$(call build_tree,debian/trees/base)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/base)
|
||||
else
|
||||
@@ -219,7 +230,7 @@ endif
|
||||
dpkg --build debian/trees/base ..
|
||||
|
||||
$(call build_tree,debian/trees/lua-base)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/lua-base)
|
||||
else
|
||||
@@ -249,7 +260,7 @@ ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 755 -d debian/trees/utils/usr/share/man/man1
|
||||
endif
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
|
||||
@@ -85,6 +85,16 @@
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to netfilters sets, which is equivalent to
|
||||
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
|
||||
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
|
||||
|
||||
# Use netfilters sets for both IPv4 and IPv6:
|
||||
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
|
||||
#nftset=/yahoo.com/4#ip#test#vpn4
|
||||
#nftset=/yahoo.com/6#ip#test#vpn6
|
||||
|
||||
# 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
|
||||
|
||||
+183
-63
@@ -1,4 +1,4 @@
|
||||
.TH DNSMASQ 8
|
||||
.TH DNSMASQ 8 2021-08-16
|
||||
.SH NAME
|
||||
dnsmasq \- A lightweight DHCP and caching DNS server.
|
||||
.SH SYNOPSIS
|
||||
@@ -55,7 +55,8 @@ Don't read the hostnames in /etc/hosts.
|
||||
.B \-H, --addn-hosts=<file>
|
||||
Additional hosts file. Read the specified file as well as /etc/hosts. If \fB--no-hosts\fP is given, read
|
||||
only the specified file. This option may be repeated for more than one
|
||||
additional hosts file. If a directory is given, then read all the files contained in that directory.
|
||||
additional hosts file. If a directory is given, then read all the files contained in that directory
|
||||
in alphabetical order.
|
||||
.TP
|
||||
.B --hostsdir=<path>
|
||||
Read all the hosts files contained in the directory. New or changed files
|
||||
@@ -135,6 +136,9 @@ running, will go exclusively to the file.) When logging to a file,
|
||||
dnsmasq will close and reopen the file when it receives SIGUSR2. This
|
||||
allows the log file to be rotated without stopping dnsmasq.
|
||||
.TP
|
||||
.B --log-debug
|
||||
Enable extra logging intended for debugging rather than information.
|
||||
.TP
|
||||
.B --log-async[=<lines>]
|
||||
Enable asynchronous logging and optionally set the limit on the
|
||||
number of lines
|
||||
@@ -181,7 +185,7 @@ OS: this was the default behaviour in versions prior to 2.43.
|
||||
.B --min-port=<port>
|
||||
Do not use ports less than that given as source for outbound DNS
|
||||
queries. Dnsmasq picks random ports as source for outbound queries:
|
||||
when this option is given, the ports used will always to larger
|
||||
when this option is given, the ports used will always be larger
|
||||
than that specified. Useful for systems behind firewalls. If not specified,
|
||||
defaults to 1024.
|
||||
.TP
|
||||
@@ -244,7 +248,7 @@ specified interface. The <domain> is the "glue record". It should
|
||||
resolve in the global DNS to an A and/or AAAA record which points to
|
||||
the address dnsmasq is listening on. When an interface is specified,
|
||||
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||
addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the glue record.
|
||||
addresses associated with the interface. Since any defined authoritative zones are also available as part of the normal recusive DNS service supplied by dnsmasq, it can make sense to have an --auth-server declaration with no interfaces or address, but simply specifying the primary external nameserver.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
@@ -296,7 +300,7 @@ option requires non-standard networking APIs and it is only available
|
||||
under Linux. On other platforms it falls-back to \fB--bind-interfaces\fP mode.
|
||||
.TP
|
||||
.B \-y, --localise-queries
|
||||
Return answers to DNS queries from /etc/hosts and \fB--interface-name\fP which depend on the interface over which the query was
|
||||
Return answers to DNS queries from /etc/hosts and \fB--interface-name\fP and \fB--dynamic-host\fP which depend on the interface over which the query was
|
||||
received. If a name has more than one address associated with
|
||||
it, and at least one of those addresses is on the same subnet as the
|
||||
interface to which the query was sent, then return only the
|
||||
@@ -323,17 +327,17 @@ are re-written. So
|
||||
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||
.TP
|
||||
.B \-B, --bogus-nxdomain=<ipaddr>
|
||||
Transform replies which contain the IP address given into "No such
|
||||
domain" replies. This is intended to counteract a devious move made by
|
||||
.B \-B, --bogus-nxdomain=<ipaddr>[/prefix]
|
||||
Transform replies which contain the specified address or subnet into "No such
|
||||
domain" replies. IPv4 and IPv6 are supported. This is intended to counteract a devious move made by
|
||||
Verisign in September 2003 when they started returning the address of
|
||||
an advertising web page in response to queries for unregistered names,
|
||||
instead of the correct NXDOMAIN response. This option tells dnsmasq to
|
||||
fake the correct response when it sees this behaviour. As at Sept 2003
|
||||
the IP address being returned by Verisign is 64.94.110.11
|
||||
.TP
|
||||
.B --ignore-address=<ipaddr>
|
||||
Ignore replies to A-record queries which include the specified address.
|
||||
.B --ignore-address=<ipaddr>[/prefix]
|
||||
Ignore replies to A or AAAA queries which include the specified address or subnet.
|
||||
No error is generated, dnsmasq simply continues to listen for another reply.
|
||||
This is useful to defeat blocking strategies which rely on quickly supplying a
|
||||
forged answer to a DNS request for certain domain, before the correct answer can arrive.
|
||||
@@ -366,10 +370,16 @@ been built with DBus support. If the service name is given, dnsmasq
|
||||
provides service at that name, rather than the default which is
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B --enable-ubus
|
||||
.B --enable-ubus[=<service-name>]
|
||||
Enable dnsmasq UBus interface. It sends notifications via UBus on
|
||||
DHCPACK and DHCPRELEASE events. Furthermore it offers metrics.
|
||||
Requires that dnsmasq has been built with UBus support.
|
||||
DHCPACK and DHCPRELEASE events. Furthermore it offers metrics
|
||||
and allows configuration of Linux connection track mark based filtering.
|
||||
When DNS query filtering based on Linux connection track marks is enabled
|
||||
UBus notifications are generated for each resolved or filtered DNS query.
|
||||
Requires that dnsmasq has been built with UBus support. If the service
|
||||
name is given, dnsmasq provides service at that namespace, rather than
|
||||
the default which is
|
||||
.B dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
By default, dnsmasq will send queries to any of the upstream servers
|
||||
@@ -395,11 +405,13 @@ were previously disabled.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Reject (and log) addresses from upstream nameservers which are in the
|
||||
private IP ranges. This blocks an attack where a browser behind a
|
||||
firewall is used to probe machines on the local network.
|
||||
private ranges. This blocks an attack where a browser behind a
|
||||
firewall is used to probe machines on the local network. For IPv6, the
|
||||
private range covers the IPv4-mapped addresses in private space plus
|
||||
all link-local (LL) and site-local (ULA) addresses.
|
||||
.TP
|
||||
.B --rebind-localhost-ok
|
||||
Exempt 127.0.0.0/8 from rebinding checks. This address range is
|
||||
Exempt 127.0.0.0/8 and ::1 from rebinding checks. This address range is
|
||||
returned by realtime black hole servers, so blocking it may disable
|
||||
these services.
|
||||
.TP
|
||||
@@ -423,7 +435,7 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<interface>][@<source-ip>[#<port>]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use \fB--no-resolv\fP to do that. If one or more
|
||||
optional domains are given, that server is used only for those domains
|
||||
@@ -449,13 +461,22 @@ repeated domain or ipaddr parts as required.
|
||||
More specific domains take precedence over less specific domains, so:
|
||||
.B --server=/google.com/1.2.3.4
|
||||
.B --server=/www.google.com/2.3.4.5
|
||||
will send queries for *.google.com to 1.2.3.4, except *www.google.com,
|
||||
which will go to 2.3.4.5
|
||||
will send queries for google.com and gmail.google.com to 1.2.3.4, but www.google.com
|
||||
will go to 2.3.4.5
|
||||
|
||||
Matching of domains is normally done on complete labels, so /google.com/ matches google.com and www.google.com
|
||||
but NOT supergoogle.com. This can be overridden with a * at the start of a pattern only: /*google.com/
|
||||
will match google.com and www.google.com AND supergoogle.com. The non-wildcard form has priority, so
|
||||
if /google.com/ and /*google.com/ are both specified then google.com and www.google.com will match /google.com/
|
||||
and /*google.com/ will only match supergoogle.com.
|
||||
|
||||
For historical reasons, the pattern /.google.com/ is equivalent to /google.com/ if you wish to match any subdomain
|
||||
of google.com but NOT google.com itself, use /*.google.com/
|
||||
|
||||
The special server address '#' means, "use the standard servers", so
|
||||
.B --server=/google.com/1.2.3.4
|
||||
.B --server=/www.google.com/#
|
||||
will send queries for *.google.com to 1.2.3.4, except *www.google.com which will
|
||||
will send queries for google.com and its subdomains to 1.2.3.4, except www.google.com (and its subdomains) which will
|
||||
be forwarded as usual.
|
||||
|
||||
Also permitted is a -S
|
||||
@@ -484,25 +505,24 @@ source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>/<prefix-len>[,<ipaddr>][#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
.B --rev-server=<ip-address>[/<prefix-len>][,<ipaddr>][#<port>][@<interface>][@<source-ip>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
.B --rev-server=1.2.3.0/24,192.168.0.1
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is omitted, dnsmasq substitutes either 32 (IPv4) or 128 (IPv6).
|
||||
.TP
|
||||
.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
Queries in the domains are never forwarded and always replied to
|
||||
with the specified IP address which may be IPv4 or IPv6. To give
|
||||
both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
|
||||
To include multiple IP addresses for a single query, use
|
||||
\fB--addn-hosts=<path>\fP instead.
|
||||
multiple addresses or both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
|
||||
Note that /etc/hosts and DHCP leases override this for individual
|
||||
names. A common use of this is to redirect the entire doubleclick.net
|
||||
domain to some friendly local web server to avoid banner ads. The
|
||||
domain specification works in the same was as for \fB--server\fP, with
|
||||
domain specification works in the same way as for \fB--server\fP, with
|
||||
the additional facility that \fB/#/\fP matches any domain. Thus
|
||||
\fB--address=/#/1.2.3.4\fP will always return \fB1.2.3.4\fP for any
|
||||
query not answered from \fB/etc/hosts\fP or DHCP and not sent to an
|
||||
@@ -528,6 +548,41 @@ These IP sets must already exist. See
|
||||
.BR ipset (8)
|
||||
for more details.
|
||||
.TP
|
||||
.B --nftset=/<domain>[/<domain>...]/[(6|4)#[<family>#]<table>#<set>[,[(6|4)#[<family>#]<table>#<set>]...]
|
||||
Similar to the \fB--ipset\fP option, but accepts one or more nftables
|
||||
sets to add IP addresses into.
|
||||
These sets must already exist. See
|
||||
.BR nft (8)
|
||||
for more details. The family, table and set are passed directly to the nft. If the spec starts with 4# or 6# then
|
||||
only A or AAAA records respectively are added to the set. Since an nftset can hold only IPv4 or IPv6 addresses, this
|
||||
avoids errors being logged for addresses of the wrong type.
|
||||
.TP
|
||||
.B --connmark-allowlist-enable[=<mask>]
|
||||
Enables filtering of incoming DNS queries with associated Linux connection track marks
|
||||
according to individual allowlists configured via a series of \fB--connmark-allowlist\fP
|
||||
options. Disallowed queries are not forwarded; they are rejected with a REFUSED error code.
|
||||
DNS queries are only allowed if they do not have an associated Linux connection
|
||||
track mark, or if the queried domains match the configured DNS patterns for the
|
||||
associated Linux connection track mark. If no allowlist is configured for a
|
||||
Linux connection track mark, all DNS queries associated with that mark are rejected.
|
||||
If a mask is specified, Linux connection track marks are first bitwise ANDed
|
||||
with the given mask before being processed.
|
||||
.TP
|
||||
.B --connmark-allowlist=<connmark>[/<mask>][,<pattern>[/<pattern>...]]
|
||||
Configures the DNS patterns that are allowed in DNS queries associated with
|
||||
the given Linux connection track mark.
|
||||
If a mask is specified, Linux connection track marks are first bitwise ANDed
|
||||
with the given mask before they are compared to the given connection track mark.
|
||||
Patterns follow the syntax of DNS names, but additionally allow the wildcard
|
||||
character "*" to be used up to twice per label to match 0 or more characters
|
||||
within that label. Note that the wildcard never matches a dot (e.g., "*.example.com"
|
||||
matches "api.example.com" but not "api.us.example.com"). Patterns must be
|
||||
fully qualified, i.e., consist of at least two labels. The final label must not be
|
||||
fully numeric, and must not be the "local" pseudo-TLD. A pattern must end with at least
|
||||
two literal (non-wildcard) labels.
|
||||
Instead of a pattern, "*" can be specified to disable allowlist filtering
|
||||
for a given Linux connection track mark entirely.
|
||||
.TP
|
||||
.B \-m, --mx-host=<mx name>[[,<hostname>],<preference>]
|
||||
Return an MX record named <mx name> pointing to the given hostname (if
|
||||
given), or
|
||||
@@ -586,6 +641,12 @@ If the time-to-live is given, it overrides the default, which is zero
|
||||
or the value of \fB--local-ttl\fP. The value is a positive integer and gives
|
||||
the time-to-live in seconds.
|
||||
.TP
|
||||
.B --dynamic-host=<name>,[IPv4-address],[IPv6-address],<interface>
|
||||
Add A, AAAA and PTR records to the DNS in the same subnet as the specified interface. The address is derived from the network part of each address associated with the interface, and the host part from the specified address. For example
|
||||
.B --dynamic-host=example.com,0.0.0.8,eth0
|
||||
will, when eth0 has the address 192.168.78.x and netmask 255.255.255.0 give the
|
||||
name example.com an A record for 192.168.78.8. The same principle applies to IPv6 addresses. Note that if an interface has more than one address, more than one A or AAAA record will be created. The TTL of the records is always zero, and any changes to interface addresses will be immediately reflected in them.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
so any number may be included, delimited by commas; use quotes to put
|
||||
@@ -653,7 +714,8 @@ configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
V4 mapped IPv6 addresses, which have a representation like ::ffff:1.2.3.4 are handled specially, and become like 0--ffff-1-2-3-4
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask> in both forms of the option.
|
||||
<start address>,<end address> or <ip address>/<prefix-length> in both forms of the option. For IPv6 the start and end addresses
|
||||
must fall in the same /64 network, or prefix-length must be greater than or equal to 64 except that shorter prefix lengths than 64 are allowed only if non-sequential names are in use.
|
||||
.TP
|
||||
.B --dumpfile=<path/to/file>
|
||||
Specify the location of a pcap-format file which dnsmasq uses to dump copies of network packets for debugging purposes. If the file exists when dnsmasq starts, it is not deleted; new packets are added to the end.
|
||||
@@ -687,8 +749,8 @@ still marks the request so that no upstream nameserver will add client
|
||||
address information either. The default is zero for both IPv4 and
|
||||
IPv6. Note that upstream nameservers may be configured to return
|
||||
different results based on this information, but the dnsmasq cache
|
||||
does not take account. If a dnsmasq instance is configured such that
|
||||
different results may be encountered, caching should be disabled.
|
||||
does not take account. Caching is therefore disabled for such replies,
|
||||
unless the subnet address being added is constant.
|
||||
|
||||
For example,
|
||||
.B --add-subnet=24,96
|
||||
@@ -697,7 +759,13 @@ will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors,
|
||||
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
|
||||
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
|
||||
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
|
||||
|
||||
.TP
|
||||
.B --umbrella[=deviceid:<deviceid>[,orgid:<orgid>]]
|
||||
Embeds the requestor's IP address in DNS queries forwarded upstream.
|
||||
If device id or organization id are specified, the information is
|
||||
included in the forwarded queries and may be able to be used in
|
||||
filtering policies and reporting. The order of the deviceid and orgid
|
||||
attributes is irrelevant, but must be separated by a comma.
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Note: huge cache size impacts performance.
|
||||
@@ -711,7 +779,8 @@ identical queries without forwarding them again.
|
||||
Set the maximum number of concurrent DNS queries. The default value is
|
||||
150, which should be fine for most setups. The only known situation
|
||||
where this needs to be increased is when using web-server log file
|
||||
resolvers, which can generate large numbers of concurrent queries.
|
||||
resolvers, which can generate large numbers of concurrent queries. This
|
||||
parameter actually controls the number of concurrent queries per server group, where a server group is the set of server(s) associated with a single domain. So if a domain has it's own server via --server=/example.com/1.2.3.4 and 1.2.3.4 is not responding, but queries for *.example.com cannot go elsewhere, then other queries will not be affected. On configurations with many such server groups and tight resources, this value may need to be reduced.
|
||||
.TP
|
||||
.B --dnssec
|
||||
Validate DNS replies and cache DNSSEC data. When forwarding DNS queries, dnsmasq requests the
|
||||
@@ -845,7 +914,7 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
.B --query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>|<mode>[,<netmask>[,<broadcast>]]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
@@ -855,8 +924,8 @@ in
|
||||
.B --dhcp-host
|
||||
options. If the lease time is given, then leases
|
||||
will be given for that length of time. The lease time is in seconds,
|
||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
||||
the default lease time is one hour. The
|
||||
or minutes (eg 45m) or hours (eg 1h) or days (2d) or weeks (1w) or "infinite". If not given,
|
||||
the default lease time is one hour for IPv4 and one day for IPv6. The
|
||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||
lease or router advertisement to zero, which causes clients to use
|
||||
@@ -904,7 +973,7 @@ then the address can be simply ::
|
||||
The optional
|
||||
.B set:<tag>
|
||||
sets an alphanumeric label which marks this network so that
|
||||
dhcp options may be specified on a per-network basis.
|
||||
DHCP options may be specified on a per-network basis.
|
||||
When it is prefixed with 'tag:' instead, then its meaning changes from setting
|
||||
a tag to matching it. Only one tag may be set, but more than one tag
|
||||
may be matched.
|
||||
@@ -975,7 +1044,7 @@ is also included, as described in RFC-3775 section 7.3.
|
||||
tells dnsmasq to advertise the prefix without the on-link (aka L) bit set.
|
||||
|
||||
.TP
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,tag:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
|
||||
Specify per host parameters for the DHCP server. This allows a machine
|
||||
with a particular hardware address to be always allocated the same
|
||||
hostname, IP address and lease time. A hostname specified like this
|
||||
@@ -1012,7 +1081,7 @@ may contain an IPv4 address or one or more IPv6 addresses, or both. IPv6 address
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
IPv6 addresses may contain only the host-identifier part:
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
in which case they act as wildcards in constructed dhcp ranges, with
|
||||
in which case they act as wildcards in constructed DHCP ranges, with
|
||||
the appropriate network part inserted. For IPv6, an address may include a prefix length:
|
||||
.B --dhcp-host=laptop,[1234:50/126]
|
||||
which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
|
||||
@@ -1040,6 +1109,19 @@ option, but aliases are possible by using CNAMEs. (See
|
||||
.B --cname
|
||||
).
|
||||
|
||||
More than one
|
||||
.B --dhcp-host
|
||||
can be associated (by name, hardware address or UID) with a host. Which one is used
|
||||
(and therefore which address is allocated by DHCP and appears in the DNS) depends
|
||||
on the subnet on which the host last obtained a DHCP lease:
|
||||
the
|
||||
.B --dhcp-host
|
||||
with an address within the subnet is used. If more than one address is within the subnet,
|
||||
the result is undefined. A corollary to this is that the name associated with a host using
|
||||
.B --dhcp-host
|
||||
does not appear in the DNS until the host obtains a DHCP lease.
|
||||
|
||||
|
||||
The special keyword "ignore"
|
||||
tells dnsmasq to never offer a DHCP lease to a machine. The machine
|
||||
can be specified by hardware address, client ID or hostname, for
|
||||
@@ -1061,7 +1143,10 @@ ignore requests from unknown machines using
|
||||
If the host matches only a \fB--dhcp-host\fP directive which cannot
|
||||
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
|
||||
|
||||
The tag:<tag> construct filters which dhcp-host directives are used. Tagged directives are used in preference to untagged ones.
|
||||
The tag:<tag> construct filters which dhcp-host directives are used; more than
|
||||
one can be provided, in this case the request must match all of them. Tagged
|
||||
directives are used in preference to untagged ones. Note that one of <hwaddr>,
|
||||
<client_id> or <hostname> still needs to be specified (can be a wildcard).
|
||||
|
||||
Ethernet addresses (but not client-ids) may have
|
||||
wildcard bytes, so for example
|
||||
@@ -1092,7 +1177,7 @@ has both wired and wireless interfaces.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<path>
|
||||
Read DHCP host information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The file contains
|
||||
is given, then read all the files contained in that directory in alphabetical order. The file contains
|
||||
information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in \fB--dhcp-host\fP. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
@@ -1100,7 +1185,7 @@ the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<path>
|
||||
Read DHCP option information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The advantage of
|
||||
is given, then read all the files contained in that directory in alphabetical order. The advantage of
|
||||
using this option is the same as for \fB--dhcp-hostsfile\fP: the
|
||||
\fB--dhcp-optsfile\fP will be re-read when dnsmasq receives SIGHUP. Note that
|
||||
it is possible to encode the information in a
|
||||
@@ -1115,7 +1200,8 @@ directory, and not an individual file. Changed or new files within
|
||||
the directory are read automatically, without the need to send SIGHUP.
|
||||
If a file is deleted or changed after it has been read by dnsmasq, then the
|
||||
host record it contained will remain until dnsmasq receives a SIGHUP, or
|
||||
is restarted; ie host records are only added dynamically.
|
||||
is restarted; ie host records are only added dynamically. The order in which the
|
||||
files in a directory are read is not defined.
|
||||
.TP
|
||||
.B --dhcp-optsdir=<path>
|
||||
This is equivalent to \fB--dhcp-optsfile\fP, with the differences noted for \fB--dhcp-hostsdir\fP.
|
||||
@@ -1349,7 +1435,7 @@ vendor-identifying vendor classes for the specified enterprise. Please
|
||||
see RFC 3925 for more details of these rare and interesting beasts.
|
||||
.TP
|
||||
.B --dhcp-name-match=set:<tag>,<name>[*]
|
||||
Set the tag if the given name is supplied by a dhcp client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client.
|
||||
Set the tag if the given name is supplied by a DHCP client. There may be a single trailing wildcard *, which has the usual meaning. Combined with dhcp-ignore or dhcp-ignore-names this gives the ability to ignore certain clients by name, or disallow certain hostnames from being claimed by a client.
|
||||
.TP
|
||||
.B --tag-if=set:<tag>[,set:<tag>[,tag:<tag>[,tag:<tag>]]]
|
||||
Perform boolean operations on tags. Any tag appearing as set:<tag> is set if
|
||||
@@ -1360,6 +1446,12 @@ Any number of set: and tag: forms may appear, in any order.
|
||||
tag set by another
|
||||
.B --tag-if,
|
||||
the line which sets the tag must precede the one which tests it.
|
||||
|
||||
As an extension, the tag:<tag> clauses support limited wildcard matching,
|
||||
similar to the matching in the \fB--interface\fP directive. This allows, for
|
||||
example, using \fB--tag-if=set:ppp,tag:ppp*\fP to set the tag 'ppp' for all requests
|
||||
received on any matching interface (ppp0, ppp1, etc). This can be used in conjunction
|
||||
with the tag:!<tag> format meaning that no tag matching the wildcard may be set.
|
||||
.TP
|
||||
.B \-J, --dhcp-ignore=tag:<tag>[,tag:<tag>]
|
||||
When all the given tags appear in the tag set ignore the host and do
|
||||
@@ -1431,7 +1523,7 @@ functions when supported by a suitable DHCP server.
|
||||
This specifies a boot option which may appear in a PXE boot menu. <CSA> is
|
||||
client system type, only services of the correct type will appear in a
|
||||
menu. The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
|
||||
Intel_Lean_Client, IA32_EFI, X86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI and ARM64_EFI; an
|
||||
Intel_Lean_Client, IA32_EFI, x86-64_EFI, Xscale_EFI, BC_EFI, ARM32_EFI and ARM64_EFI; an
|
||||
integer may be used for other types. The
|
||||
parameter after the menu text may be a file name, in which case dnsmasq acts as a
|
||||
boot server and directs the PXE client to download the file by TFTP,
|
||||
@@ -1475,6 +1567,21 @@ to allow netbooting. This mode is enabled using the
|
||||
.B proxy
|
||||
keyword in
|
||||
.B --dhcp-range.
|
||||
.TP
|
||||
.B --dhcp-pxe-vendor=<vendor>[,...]
|
||||
According to UEFI and PXE specifications, DHCP packets between PXE clients and
|
||||
proxy PXE servers should have
|
||||
.I PXEClient
|
||||
in their vendor-class field. However, the firmware of computers from a few
|
||||
vendors is customized to carry a different identifier in that field. This option
|
||||
is used to consider such identifiers valid for identifying PXE clients. For
|
||||
instance
|
||||
|
||||
.B --dhcp-pxe-vendor=PXEClient,HW-Client
|
||||
|
||||
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
|
||||
.I HW-Client
|
||||
in as their identifier.
|
||||
.TP
|
||||
.B \-X, --dhcp-lease-max=<number>
|
||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||
@@ -1525,10 +1632,11 @@ tried. This flag disables this check. Use with caution.
|
||||
Extra logging for DHCP: log all the options sent to DHCP clients and
|
||||
the tags used to determine them.
|
||||
.TP
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra
|
||||
.B --quiet-dhcp, --quiet-dhcp6, --quiet-ra, --quiet-tftp
|
||||
Suppress logging of the routine operation of these protocols. Errors and
|
||||
problems will still be logged. \fB--quiet-dhcp\fP and quiet-dhcp6 are
|
||||
over-ridden by \fB--log-dhcp\fP.
|
||||
problems will still be logged. \fB--quiet-tftp\fP does not consider file not
|
||||
found to be an error. \fB--quiet-dhcp\fP and quiet-dhcp6 are over-ridden by
|
||||
\fB--log-dhcp\fP.
|
||||
.TP
|
||||
.B \-l, --dhcp-leasefile=<path>
|
||||
Use the specified file to store DHCP lease information.
|
||||
@@ -1746,7 +1854,7 @@ option also forces the leasechange script to be called on changes
|
||||
to the client-id and lease length and expiry time.
|
||||
.TP
|
||||
.B --script-on-renewal
|
||||
Call the dhcp script when the lease expiry time changes, for instance when the
|
||||
Call the DHCP script when the lease expiry time changes, for instance when the
|
||||
lease is renewed.
|
||||
.TP
|
||||
.B --bridge-interface=<interface>,<alias>[,<alias>]
|
||||
@@ -1762,25 +1870,34 @@ It is permissible to add more than one alias using more than one \fB--bridge-int
|
||||
\fB--bridge-interface=int1,alias1,alias2\fP is exactly equivalent to
|
||||
\fB--bridge-interface=int1,alias1 --bridge-interface=int1,alias2\fP
|
||||
.TP
|
||||
.B --shared-network=<interface>|<addr>,<addr>
|
||||
The DHCP server determines which dhcp ranges are useable for allocating and
|
||||
.B --shared-network=<interface>,<addr>
|
||||
.PD 0
|
||||
.TP
|
||||
.B --shared-network=<addr>,<addr>
|
||||
.PD 1v
|
||||
The DHCP server determines which DHCP ranges are useable for allocating an
|
||||
address to a DHCP client based on the network from which the DHCP request arrives,
|
||||
and the IP configuration of the server's interface on that network. The shared-network
|
||||
option extends the available subnets (and therefore dhcp ranges) beyond the
|
||||
subnets configured on the arrival interface. The first argument is either the
|
||||
name of an interface or an address which is configured on a local interface, and the
|
||||
option extends the available subnets (and therefore DHCP ranges) beyond the
|
||||
subnets configured on the arrival interface.
|
||||
|
||||
The first argument is either the
|
||||
name of an interface, or an address that is configured on a local interface, and the
|
||||
second argument is an address which defines another subnet on which addresses can be allocated.
|
||||
To be useful, there must be suitable dhcp-range which allows address allocation on this subnet
|
||||
and this dhcp-range MUST include the netmask. Use shared-network also needs extra
|
||||
consideration of routing. Dnsmasq doesn't have the usual information which it uses to
|
||||
|
||||
To be useful, there must be a suitable dhcp-range which allows address allocation on this subnet
|
||||
and this dhcp-range MUST include the netmask.
|
||||
|
||||
Using shared-network also needs extra
|
||||
consideration of routing. Dnsmasq does not have the usual information that it uses to
|
||||
determine the default route, so the default route option (or other routing) MUST be
|
||||
manually configured. The client must have a route to the server: if the two-address form
|
||||
of shared-network is used, this will be to the first specified address. If the interface,address
|
||||
configured manually. The client must have a route to the server: if the two-address form
|
||||
of shared-network is used, this needs to be to the first specified address. If the interface,address
|
||||
form is used, there must be a route to all of the addresses configured on the interface.
|
||||
|
||||
The two-address form of shared-network is also usable with a DHCP relay: the first address
|
||||
is the address of the relay and the second, as before, specifies an extra subnet which
|
||||
may be allocated.
|
||||
addresses may be allocated from.
|
||||
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
@@ -1790,7 +1907,7 @@ firstly it causes the DHCP server to return the domain to any hosts
|
||||
which request it, and secondly it sets the domain which it is legal
|
||||
for DHCP-configured hosts to claim. The intention is to constrain
|
||||
hostnames so that an untrusted host on the LAN cannot advertise
|
||||
its name via dhcp as e.g. "microsoft.com" and capture traffic not
|
||||
its name via DHCP as e.g. "microsoft.com" and capture traffic not
|
||||
meant for it. If no domain suffix is specified, then any DHCP
|
||||
hostname with a domain part (ie with a period) will be disallowed
|
||||
and logged. If suffix is specified, then hostnames with a domain
|
||||
@@ -1817,7 +1934,6 @@ additional flag "local" may be supplied which has the effect of adding
|
||||
is identical to
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
.B --local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
The network size must be 8, 16 or 24 for this to be legal.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
In the default mode, dnsmasq inserts the unqualified names of
|
||||
@@ -1881,7 +1997,7 @@ The mtu: parameter may be an arbitrary interface name, in which case the MTU val
|
||||
for (eg) advertising the MTU of a WAN interface on the other interfaces of a router.
|
||||
.TP
|
||||
.B --dhcp-reply-delay=[tag:<tag>,]<integer>
|
||||
Delays sending DHCPOFFER and proxydhcp replies for at least the specified number of seconds.
|
||||
Delays sending DHCPOFFER and PROXYDHCP replies for at least the specified number of seconds.
|
||||
This can be used as workaround for bugs in PXE boot firmware that does not function properly when
|
||||
receiving an instant reply.
|
||||
This option takes into account the time already spent waiting (e.g. performing ping check) if any.
|
||||
@@ -2017,7 +2133,7 @@ and
|
||||
.I /etc/ethers
|
||||
and any file given by \fB--dhcp-hostsfile\fP, \fB--dhcp-hostsdir\fP, \fB--dhcp-optsfile\fP,
|
||||
\fB--dhcp-optsdir\fP, \fB--addn-hosts\fP or \fB--hostsdir\fP.
|
||||
The dhcp lease change script is called for all
|
||||
The DHCP lease change script is called for all
|
||||
existing DHCP leases. If
|
||||
.B
|
||||
--no-poll
|
||||
@@ -2195,7 +2311,6 @@ as is the tag "bootp", allowing some control over the options returned to
|
||||
different classes of hosts.
|
||||
|
||||
.SH AUTHORITATIVE CONFIGURATION
|
||||
.PP
|
||||
Configuring dnsmasq to act as an authoritative DNS server is
|
||||
complicated by the fact that it involves configuration of external DNS
|
||||
servers to provide delegation. We will walk through three scenarios of
|
||||
@@ -2322,6 +2437,10 @@ following data is used to populate the authoritative zone.
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record, --caa-record,
|
||||
as long as the record names are in the authoritative domain.
|
||||
.PP
|
||||
.B --synth-domain
|
||||
as long as the domain is in the authoritative zone and, for
|
||||
reverse (PTR) queries, the address is in the relevant subnet.
|
||||
.PP
|
||||
.B --cname
|
||||
as long as the record name is in the authoritative domain. If the
|
||||
target of the CNAME is unqualified, then it is qualified with the
|
||||
@@ -2338,6 +2457,8 @@ IPv4 and IPv6 addresses from /etc/hosts (and
|
||||
.B --host-record
|
||||
and
|
||||
.B --interface-name
|
||||
and
|
||||
.B ---dynamic-host
|
||||
provided the address falls into one of the subnets specified in the
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
@@ -2365,7 +2486,6 @@ used, and must match the zone's domain.
|
||||
|
||||
|
||||
.SH EXIT CODES
|
||||
.PP
|
||||
0 - Dnsmasq successfully forked into the background, or terminated
|
||||
normally if backgrounding is not enabled.
|
||||
.PP
|
||||
|
||||
+809
-622
File diff suppressed because it is too large.
Load diff
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -230,5 +230,3 @@ int do_arp_script_run(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+70
-38
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -105,7 +105,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
|
||||
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
|
||||
struct auth_zone *zone = NULL;
|
||||
struct addrlist *subnet = NULL;
|
||||
char *cut;
|
||||
@@ -146,6 +146,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (qclass != C_IN)
|
||||
{
|
||||
auth = 0;
|
||||
out_of_zone = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -159,6 +160,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -208,7 +210,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (local_query || in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -232,7 +234,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
strcat(name, ".");
|
||||
strcat(name, zone->domain);
|
||||
}
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -241,7 +243,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
|
||||
found = 1;
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
@@ -253,10 +255,21 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
|
||||
found = 1;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -273,6 +286,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (!zone)
|
||||
{
|
||||
out_of_zone = 1;
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
@@ -286,7 +300,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
anscount++;
|
||||
@@ -301,7 +315,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -335,7 +349,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -349,7 +363,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -363,7 +377,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (rc == 2 && qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -393,13 +407,23 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
continue;
|
||||
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && is_name_synthetic(flag, name, &addr) )
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
@@ -408,8 +432,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (qtype == T_SOA)
|
||||
{
|
||||
auth = soa = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
|
||||
}
|
||||
else if (qtype == T_AXFR)
|
||||
{
|
||||
@@ -444,16 +467,14 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
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>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
|
||||
}
|
||||
else if (qtype == T_NS)
|
||||
{
|
||||
auth = 1;
|
||||
ns = 1; /* inhibits auth section */
|
||||
found = 1;
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
|
||||
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,9 +492,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
(local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
*cut = '.'; /* restore domain part */
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
*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))
|
||||
@@ -493,8 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
nxdomain = 0;
|
||||
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
|
||||
{
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid));
|
||||
found = 1;
|
||||
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &crecp->addr))
|
||||
@@ -541,7 +560,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
if (candidate)
|
||||
{
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
|
||||
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
|
||||
strcpy(name, candidate->target);
|
||||
if (!strchr(name, '.'))
|
||||
{
|
||||
@@ -559,7 +578,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
else if (cache_find_non_terminal(name, now))
|
||||
nxdomain = 0;
|
||||
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
|
||||
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -589,7 +608,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -602,7 +621,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
sprintf(p, "ip6.arpa");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -628,16 +647,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
{
|
||||
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))
|
||||
/* Only include the machine running dnsmasq if it's acting as an auth server */
|
||||
if (daemon->authinterface)
|
||||
{
|
||||
if (offset == 0)
|
||||
offset = newoffset;
|
||||
if (ns)
|
||||
anscount++;
|
||||
else
|
||||
authcount++;
|
||||
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)
|
||||
@@ -851,10 +874,22 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(authcount);
|
||||
header->arcount = htons(0);
|
||||
|
||||
if (!local_query && out_of_zone)
|
||||
{
|
||||
SET_RCODE(header, REFUSED);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
addr.log.rcode = REFUSED;
|
||||
addr.log.ede = EDE_NOT_AUTH;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
|
||||
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
|
||||
}
|
||||
|
||||
/* Advertise our packet size limit in our reply */
|
||||
if (have_pseudoheader)
|
||||
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
@@ -863,6 +898,3 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+2
-3
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -52,7 +52,7 @@ void blockdata_init(void)
|
||||
|
||||
void blockdata_report(void)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("pool memory in use %u, max %u, allocated %u"),
|
||||
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
|
||||
blockdata_count * sizeof(struct blockdata),
|
||||
blockdata_hwm * sizeof(struct blockdata),
|
||||
blockdata_alloced * sizeof(struct blockdata));
|
||||
@@ -174,4 +174,3 @@ struct blockdata *blockdata_read(int fd, size_t len)
|
||||
{
|
||||
return blockdata_alloc_real(fd, NULL, len);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -440,5 +440,3 @@ void route_sock(void)
|
||||
}
|
||||
|
||||
#endif /* HAVE_BSD_NETWORK */
|
||||
|
||||
|
||||
+203
-88
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -30,50 +30,100 @@ static struct crec *really_insert(char *name, union all_addr *addr, unsigned sho
|
||||
time_t now, unsigned long ttl, unsigned int flags);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
/* taken from https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml */
|
||||
static const struct {
|
||||
unsigned int type;
|
||||
const char * const name;
|
||||
} typestr[] = {
|
||||
{ 1, "A" },
|
||||
{ 2, "NS" },
|
||||
{ 5, "CNAME" },
|
||||
{ 6, "SOA" },
|
||||
{ 10, "NULL" },
|
||||
{ 11, "WKS" },
|
||||
{ 12, "PTR" },
|
||||
{ 13, "HINFO" },
|
||||
{ 15, "MX" },
|
||||
{ 16, "TXT" },
|
||||
{ 22, "NSAP" },
|
||||
{ 23, "NSAP_PTR" },
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 29, "LOC" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
{ 37, "CERT" },
|
||||
{ 38, "A6" },
|
||||
{ 39, "DNAME" },
|
||||
{ 41, "OPT" },
|
||||
{ 43, "DS" },
|
||||
{ 46, "RRSIG" },
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 51, "NSEC3PARAM" },
|
||||
{ 52, "TLSA" },
|
||||
{ 53, "SMIMEA" },
|
||||
{ 55, "HIP" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
{ 252, "AXFR" },
|
||||
{ 253, "MAILB" },
|
||||
{ 254, "MAILA" },
|
||||
{ 255, "ANY" },
|
||||
{ 257, "CAA" }
|
||||
{ 1, "A" }, /* a host address [RFC1035] */
|
||||
{ 2, "NS" }, /* an authoritative name server [RFC1035] */
|
||||
{ 3, "MD" }, /* a mail destination (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 4, "MF" }, /* a mail forwarder (OBSOLETE - use MX) [RFC1035] */
|
||||
{ 5, "CNAME" }, /* the canonical name for an alias [RFC1035] */
|
||||
{ 6, "SOA" }, /* marks the start of a zone of authority [RFC1035] */
|
||||
{ 7, "MB" }, /* a mailbox domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 8, "MG" }, /* a mail group member (EXPERIMENTAL) [RFC1035] */
|
||||
{ 9, "MR" }, /* a mail rename domain name (EXPERIMENTAL) [RFC1035] */
|
||||
{ 10, "NULL" }, /* a null RR (EXPERIMENTAL) [RFC1035] */
|
||||
{ 11, "WKS" }, /* a well known service description [RFC1035] */
|
||||
{ 12, "PTR" }, /* a domain name pointer [RFC1035] */
|
||||
{ 13, "HINFO" }, /* host information [RFC1035] */
|
||||
{ 14, "MINFO" }, /* mailbox or mail list information [RFC1035] */
|
||||
{ 15, "MX" }, /* mail exchange [RFC1035] */
|
||||
{ 16, "TXT" }, /* text strings [RFC1035] */
|
||||
{ 17, "RP" }, /* for Responsible Person [RFC1183] */
|
||||
{ 18, "AFSDB" }, /* for AFS Data Base location [RFC1183][RFC5864] */
|
||||
{ 19, "X25" }, /* for X.25 PSDN address [RFC1183] */
|
||||
{ 20, "ISDN" }, /* for ISDN address [RFC1183] */
|
||||
{ 21, "RT" }, /* for Route Through [RFC1183] */
|
||||
{ 22, "NSAP" }, /* for NSAP address, NSAP style A record [RFC1706] */
|
||||
{ 23, "NSAP_PTR" }, /* for domain name pointer, NSAP style [RFC1348][RFC1637][RFC1706] */
|
||||
{ 24, "SIG" }, /* for security signature [RFC2535][RFC2536][RFC2537][RFC2931][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 25, "KEY" }, /* for security key [RFC2535][RFC2536][RFC2537][RFC2539][RFC3008][RFC3110][RFC3755][RFC4034] */
|
||||
{ 26, "PX" }, /* X.400 mail mapping information [RFC2163] */
|
||||
{ 27, "GPOS" }, /* Geographical Position [RFC1712] */
|
||||
{ 28, "AAAA" }, /* IP6 Address [RFC3596] */
|
||||
{ 29, "LOC" }, /* Location Information [RFC1876] */
|
||||
{ 30, "NXT" }, /* Next Domain (OBSOLETE) [RFC2535][RFC3755] */
|
||||
{ 31, "EID" }, /* Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 32, "NIMLOC" }, /* Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] 1995-06*/
|
||||
{ 33, "SRV" }, /* Server Selection [1][RFC2782] */
|
||||
{ 34, "ATMA" }, /* ATM Address [ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.] */
|
||||
{ 35, "NAPTR" }, /* Naming Authority Pointer [RFC2168][RFC2915][RFC3403] */
|
||||
{ 36, "KX" }, /* Key Exchanger [RFC2230] */
|
||||
{ 37, "CERT" }, /* CERT [RFC4398] */
|
||||
{ 38, "A6" }, /* A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563] */
|
||||
{ 39, "DNAME" }, /* DNAME [RFC6672] */
|
||||
{ 40, "SINK" }, /* SINK [Donald_E_Eastlake][http://tools.ietf.org/html/draft-eastlake-kitchen-sink] 1997-11*/
|
||||
{ 41, "OPT" }, /* OPT [RFC3225][RFC6891] */
|
||||
{ 42, "APL" }, /* APL [RFC3123] */
|
||||
{ 43, "DS" }, /* Delegation Signer [RFC3658][RFC4034] */
|
||||
{ 44, "SSHFP" }, /* SSH Key Fingerprint [RFC4255] */
|
||||
{ 45, "IPSECKEY" }, /* IPSECKEY [RFC4025] */
|
||||
{ 46, "RRSIG" }, /* RRSIG [RFC3755][RFC4034] */
|
||||
{ 47, "NSEC" }, /* NSEC [RFC3755][RFC4034][RFC9077] */
|
||||
{ 48, "DNSKEY" }, /* DNSKEY [RFC3755][RFC4034] */
|
||||
{ 49, "DHCID" }, /* DHCID [RFC4701] */
|
||||
{ 50, "NSEC3" }, /* NSEC3 [RFC5155][RFC9077] */
|
||||
{ 51, "NSEC3PARAM" }, /* NSEC3PARAM [RFC5155] */
|
||||
{ 52, "TLSA" }, /* TLSA [RFC6698] */
|
||||
{ 53, "SMIMEA" }, /* S/MIME cert association [RFC8162] SMIMEA/smimea-completed-template 2015-12-01*/
|
||||
{ 55, "HIP" }, /* Host Identity Protocol [RFC8005] */
|
||||
{ 56, "NINFO" }, /* NINFO [Jim_Reid] NINFO/ninfo-completed-template 2008-01-21*/
|
||||
{ 57, "RKEY" }, /* RKEY [Jim_Reid] RKEY/rkey-completed-template 2008-01-21*/
|
||||
{ 58, "TALINK" }, /* Trust Anchor LINK [Wouter_Wijngaards] TALINK/talink-completed-template 2010-02-17*/
|
||||
{ 59, "CDS" }, /* Child DS [RFC7344] CDS/cds-completed-template 2011-06-06*/
|
||||
{ 60, "CDNSKEY" }, /* DNSKEY(s) the Child wants reflected in DS [RFC7344] 2014-06-16*/
|
||||
{ 61, "OPENPGPKEY" }, /* OpenPGP Key [RFC7929] OPENPGPKEY/openpgpkey-completed-template 2014-08-12*/
|
||||
{ 62, "CSYNC" }, /* Child-To-Parent Synchronization [RFC7477] 2015-01-27*/
|
||||
{ 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/
|
||||
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
|
||||
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
|
||||
{ 99, "SPF" }, /* [RFC7208] */
|
||||
{ 100, "UINFO" }, /* [IANA-Reserved] */
|
||||
{ 101, "UID" }, /* [IANA-Reserved] */
|
||||
{ 102, "GID" }, /* [IANA-Reserved] */
|
||||
{ 103, "UNSPEC" }, /* [IANA-Reserved] */
|
||||
{ 104, "NID" }, /* [RFC6742] ILNP/nid-completed-template */
|
||||
{ 105, "L32" }, /* [RFC6742] ILNP/l32-completed-template */
|
||||
{ 106, "L64" }, /* [RFC6742] ILNP/l64-completed-template */
|
||||
{ 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */
|
||||
{ 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/
|
||||
{ 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/
|
||||
{ 249, "TKEY" }, /* Transaction Key [RFC2930] */
|
||||
{ 250, "TSIG" }, /* Transaction Signature [RFC8945] */
|
||||
{ 251, "IXFR" }, /* incremental transfer [RFC1995] */
|
||||
{ 252, "AXFR" }, /* transfer of an entire zone [RFC1035][RFC5936] */
|
||||
{ 253, "MAILB" }, /* mailbox-related RRs (MB, MG or MR) [RFC1035] */
|
||||
{ 254, "MAILA" }, /* mail agent RRs (OBSOLETE - see MX) [RFC1035] */
|
||||
{ 255, "ANY" }, /* A request for some or all records the server has available [RFC1035][RFC6895][RFC8482] */
|
||||
{ 256, "URI" }, /* URI [RFC7553] URI/uri-completed-template 2011-02-22*/
|
||||
{ 257, "CAA" }, /* Certification Authority Restriction [RFC8659] CAA/caa-completed-template 2011-04-07*/
|
||||
{ 258, "AVC" }, /* Application Visibility and Control [Wolfgang_Riedel] AVC/avc-completed-template 2016-02-26*/
|
||||
{ 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/
|
||||
{ 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/
|
||||
{ 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/
|
||||
{ 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */
|
||||
};
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
@@ -433,7 +483,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
|
||||
else if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) &&
|
||||
(flags & crecp->flags & F_REVERSE) &&
|
||||
(flags & crecp->flags & (F_IPV4 | F_IPV6)) &&
|
||||
memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
addr && memcmp(&crecp->addr, addr, addrlen) == 0)
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
cache_unlink(crecp);
|
||||
@@ -472,16 +522,27 @@ void cache_start_insert(void)
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned int flags)
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DNSKEY | F_DS))
|
||||
{
|
||||
/* The DNSSEC validation process works by getting needed records into the
|
||||
cache, then retrying the validation until they are all in place.
|
||||
This can be messed up by very short TTLs, and _really_ messed up by
|
||||
zero TTLs, so we force the TTL to be at least long enough to do a validation.
|
||||
Ideally, we should use some kind of reference counting so that records are
|
||||
locked until the validation that asked for them is complete, but this
|
||||
is much easier, and just as effective. */
|
||||
if (ttl < DNSSEC_MIN_TTL)
|
||||
ttl = DNSSEC_MIN_TTL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don't mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
}
|
||||
|
||||
return really_insert(name, addr, class, now, ttl, flags);
|
||||
}
|
||||
@@ -1536,7 +1597,8 @@ static void make_non_terminals(struct crec *source)
|
||||
if (crecp)
|
||||
{
|
||||
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_SRV | F_DNSKEY | F_DS | F_REVERSE);
|
||||
crecp->ttd = source->ttd;
|
||||
if (!(crecp->flags & F_IMMORTAL))
|
||||
crecp->ttd = source->ttd;
|
||||
crecp->name.namep = name;
|
||||
|
||||
cache_hash(crecp);
|
||||
@@ -1589,21 +1651,18 @@ int cache_make_stat(struct txt_record *t)
|
||||
case TXT_STAT_SERVERS:
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
char *new, *lenp;
|
||||
int port, newlen, bytes_avail, bytes_needed;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
@@ -1631,6 +1690,7 @@ int cache_make_stat(struct txt_record *t)
|
||||
}
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = p - buff;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1673,27 +1733,24 @@ void dump_cache(time_t now)
|
||||
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
if (!(serv->flags & SERV_MARK))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags & SERV_MARK) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
serv1->flags |= SERV_MARK;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
|
||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
@@ -1799,7 +1856,7 @@ char *record_source(unsigned int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
char *querystr(char *desc, unsigned short type)
|
||||
static char *querystr(char *desc, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
@@ -1847,47 +1904,97 @@ char *querystr(char *desc, unsigned short type)
|
||||
if (types)
|
||||
sprintf(buff, "<%s>", types);
|
||||
else
|
||||
sprintf(buff, "type=%d", type);
|
||||
sprintf(buff, "<type=%d>", type);
|
||||
}
|
||||
}
|
||||
|
||||
return buff ? buff : "";
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
static char *edestr(int ede)
|
||||
{
|
||||
char *source, *dest = daemon->addrbuff;
|
||||
switch (ede)
|
||||
{
|
||||
case EDE_OTHER: return "other";
|
||||
case EDE_USUPDNSKEY: return "unsupported DNSKEY algorithm";
|
||||
case EDE_USUPDS: return "unsupported DS digest";
|
||||
case EDE_STALE: return "stale answer";
|
||||
case EDE_FORGED: return "forged";
|
||||
case EDE_DNSSEC_IND: return "DNSSEC indeterminate";
|
||||
case EDE_DNSSEC_BOGUS: return "DNSSEC bogus";
|
||||
case EDE_SIG_EXP: return "DNSSEC signature expired";
|
||||
case EDE_SIG_NYV: return "DNSSEC sig not yet valid";
|
||||
case EDE_NO_DNSKEY: return "DNSKEY missing";
|
||||
case EDE_NO_RRSIG: return "RRSIG missing";
|
||||
case EDE_NO_ZONEKEY: return "no zone key bit set";
|
||||
case EDE_NO_NSEC: return "NSEC(3) missing";
|
||||
case EDE_CACHED_ERR: return "cached error";
|
||||
case EDE_NOT_READY: return "not ready";
|
||||
case EDE_BLOCKED: return "blocked";
|
||||
case EDE_CENSORED: return "censored";
|
||||
case EDE_FILTERED: return "filtered";
|
||||
case EDE_PROHIBITED: return "prohibited";
|
||||
case EDE_STALE_NXD: return "stale NXDOMAIN";
|
||||
case EDE_NOT_AUTH: return "not authoritative";
|
||||
case EDE_NOT_SUP: return "not supported";
|
||||
case EDE_NO_AUTH: return "no reachable authority";
|
||||
case EDE_NETERR: return "network error";
|
||||
case EDE_INVALID_DATA: return "invalid data";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
char *source, *dest = arg;
|
||||
char *verb = "is";
|
||||
char *extra = "";
|
||||
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
/* build query type string if requested */
|
||||
if(type > 0)
|
||||
arg = querystr(arg, type);
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if ((flags & F_DNSSECOK) && option_bool(OPT_EXTRALOG))
|
||||
extra = " (DNSSEC signed)";
|
||||
#endif
|
||||
|
||||
name = sanitise(name);
|
||||
|
||||
if (addr)
|
||||
{
|
||||
dest = daemon->addrbuff;
|
||||
|
||||
if (flags & F_KEYTAG)
|
||||
sprintf(daemon->addrbuff, arg, addr->log.keytag, addr->log.algo, addr->log.digest);
|
||||
else if (flags & F_RCODE)
|
||||
{
|
||||
unsigned int rcode = addr->log.rcode;
|
||||
|
||||
if (rcode == SERVFAIL)
|
||||
dest = "SERVFAIL";
|
||||
else if (rcode == REFUSED)
|
||||
dest = "REFUSED";
|
||||
else if (rcode == NOTIMP)
|
||||
dest = "not implemented";
|
||||
else
|
||||
sprintf(daemon->addrbuff, "%u", rcode);
|
||||
if (rcode == SERVFAIL)
|
||||
dest = "SERVFAIL";
|
||||
else if (rcode == REFUSED)
|
||||
dest = "REFUSED";
|
||||
else if (rcode == NOTIMP)
|
||||
dest = "not implemented";
|
||||
else
|
||||
sprintf(daemon->addrbuff, "%u", rcode);
|
||||
|
||||
if (addr->log.ede != EDE_UNSET)
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (flags & (F_IPV4 | F_IPV6))
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
else
|
||||
dest = arg;
|
||||
}
|
||||
else
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_REVERSE)
|
||||
{
|
||||
@@ -1925,7 +2032,15 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
else if (flags & F_SECSTAT)
|
||||
source = "validation";
|
||||
{
|
||||
if (addr && addr->log.ede != EDE_UNSET && option_bool(OPT_EXTRALOG))
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE: %s)", edestr(addr->log.ede));
|
||||
}
|
||||
source = "validation";
|
||||
dest = arg;
|
||||
}
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_SERVER)
|
||||
@@ -1945,7 +2060,7 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
source = type ? "ipset add" : "nftset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
@@ -1953,19 +2068,19 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
if (strlen(name) == 0)
|
||||
if (name && !name[0])
|
||||
name = ".";
|
||||
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
{
|
||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
||||
if (flags & F_NOEXTRA)
|
||||
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%u %s %s %s %s%s", daemon->log_display_id, source, name, verb, dest, extra);
|
||||
else
|
||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
|
||||
{
|
||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s%s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest, extra);
|
||||
}
|
||||
}
|
||||
else
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%s %s %s %s%s", source, name, verb, dest, extra);
|
||||
}
|
||||
|
||||
|
||||
+25
-9
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -23,13 +23,12 @@
|
||||
#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
|
||||
#define KEYBLOCK_LEN 40 /* choose to minimise 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 TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
|
||||
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
|
||||
@@ -40,9 +39,11 @@
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define DNSSEC_MIN_TTL 60 /* DNSKEY and DS records in cache last at least this long */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define DEFLEASE 3600 /* default DHCPv4 lease time, one hour */
|
||||
#define DEFLEASE6 (3600*24) /* default lease time for DHCPv6. One day. */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
@@ -50,6 +51,7 @@
|
||||
#define RANDFILE "/dev/urandom"
|
||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
|
||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||
#define DNSMASQ_UBUS_NAME "dnsmasq" /* Default - may be overridden by config */
|
||||
#define AUTH_TTL 600 /* default TTL for auth DNS */
|
||||
#define SOA_REFRESH 1200 /* SOA refresh default */
|
||||
#define SOA_RETRY 180 /* SOA retry default */
|
||||
@@ -113,10 +115,17 @@ HAVE_IPSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given ipsets.
|
||||
|
||||
HAVE_NFTSET
|
||||
define this to include the ability to selectively add resolved ip addresses
|
||||
to given nftables sets.
|
||||
|
||||
HAVE_AUTH
|
||||
define this to include the facility to act as an authoritative DNS
|
||||
server for one or more zones.
|
||||
|
||||
HAVE_CRYPTOHASH
|
||||
include just hash function from crypto library, but no DNSSEC.
|
||||
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
@@ -138,6 +147,7 @@ NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
NO_DUMPFILE
|
||||
NO_LOOP
|
||||
NO_INOTIFY
|
||||
these are available to explicitly disable compile time options which would
|
||||
otherwise be enabled automatically or which are enabled by default
|
||||
@@ -184,8 +194,9 @@ RESOLVFILE
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_LIBIDN2 */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_CRYPTOHASH */
|
||||
/* #define HAVE_DNSSEC */
|
||||
|
||||
/* #define HAVE_NFTSET */
|
||||
|
||||
/* Default locations for important system files. */
|
||||
|
||||
@@ -413,10 +424,18 @@ static char *compile_opts =
|
||||
"no-"
|
||||
#endif
|
||||
"ipset "
|
||||
#ifndef HAVE_NFTSET
|
||||
"no-"
|
||||
#endif
|
||||
"nftset "
|
||||
#ifndef HAVE_AUTH
|
||||
"no-"
|
||||
#endif
|
||||
"auth "
|
||||
#if !defined(HAVE_CRYPTOHASH) && !defined(HAVE_DNSSEC)
|
||||
"no-"
|
||||
#endif
|
||||
"cryptohash "
|
||||
#ifndef HAVE_DNSSEC
|
||||
"no-"
|
||||
#endif
|
||||
@@ -437,7 +456,4 @@ static char *compile_opts =
|
||||
#endif
|
||||
"dumpfile";
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* defined(HAVE_DHCP) */
|
||||
+2
-5
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -82,7 +82,4 @@ static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, vo
|
||||
return NFCT_CB_CONTINUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_CONNTRACK */
|
||||
+65
-41
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,18 +16,34 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
|
||||
/* Minimal version of nettle */
|
||||
|
||||
/* bignum.h includes version.h and works on
|
||||
earlier releases of nettle which don't have version.h */
|
||||
#include <nettle/bignum.h>
|
||||
#if !defined(NETTLE_VERSION_MAJOR)
|
||||
# define NETTLE_VERSION_MAJOR 2
|
||||
# define NETTLE_VERSION_MINOR 0
|
||||
#endif
|
||||
#define MIN_VERSION(major, minor) ((NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
|
||||
(NETTLE_VERSION_MAJOR > (major)))
|
||||
|
||||
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
|
||||
|
||||
#if defined(HAVE_DNSSEC)
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/ecdsa.h>
|
||||
#include <nettle/ecc-curve.h>
|
||||
#if MIN_VERSION(3, 1)
|
||||
#include <nettle/eddsa.h>
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
#endif
|
||||
#if MIN_VERSION(3, 6)
|
||||
# include <nettle/gostdsa.h>
|
||||
#endif
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||
the input data, concatenated into a single, statically maintained, buffer.
|
||||
|
||||
@@ -81,7 +97,6 @@ static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
@@ -100,35 +115,7 @@ static struct nettle_hash null_hash = {
|
||||
(nettle_hash_digest_func *) null_hash_digest
|
||||
};
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
|
||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||
versions. It also #defines nettle_hashes, so use that to tell
|
||||
if we have the new facilities. */
|
||||
|
||||
#ifdef nettle_hashes
|
||||
return nettle_lookup_hash(name);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
#endif /* MIN_VERSION(3, 1) */
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
@@ -167,7 +154,7 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
@@ -231,7 +218,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR < 4
|
||||
#if !MIN_VERSION(3, 4)
|
||||
#define nettle_get_secp_256r1() (&nettle_secp_256r1)
|
||||
#define nettle_get_secp_384r1() (&nettle_secp_384r1)
|
||||
#endif
|
||||
@@ -294,7 +281,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
#if MIN_VERSION(3, 6)
|
||||
static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
@@ -335,6 +322,7 @@ static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_l
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
@@ -361,7 +349,7 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 16:
|
||||
if (key_len != ED448_KEY_SIZE ||
|
||||
sig_len != ED448_SIGNATURE_SIZE)
|
||||
@@ -377,6 +365,7 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
@@ -392,16 +381,18 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
|
||||
case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
|
||||
#if MIN_VERSION(3, 6)
|
||||
case 12:
|
||||
return dnsmasq_gostdsa_verify;
|
||||
#endif
|
||||
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
|
||||
#if MIN_VERSION(3, 1)
|
||||
case 15: case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -472,4 +463,37 @@ char *nsec3_digest_name(int digest)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_DNSSEC) */
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
#if MIN_VERSION(3,1) && defined(HAVE_DNSSEC)
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
#endif
|
||||
|
||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||
versions. */
|
||||
#if MIN_VERSION(3, 4)
|
||||
return nettle_lookup_hash(name);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
|
||||
+24
-19
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -114,7 +114,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
|
||||
w->next = daemon->watches;
|
||||
daemon->watches = w;
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -134,16 +134,20 @@ static void remove_watch(DBusWatch *watch, void *data)
|
||||
up = &(w->next);
|
||||
}
|
||||
|
||||
w = data; /* no warning */
|
||||
(void)data; /* no warning */
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
static DBusMessage* dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
union mysockaddr addr, source_addr;
|
||||
char *domain;
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Failed to initialize dbus message iter");
|
||||
}
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
@@ -215,13 +219,14 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
domain = NULL;
|
||||
|
||||
if (!skip)
|
||||
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
|
||||
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain, NULL);
|
||||
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_servers();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
@@ -237,7 +242,7 @@ static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_LOOP)
|
||||
{
|
||||
prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
|
||||
}
|
||||
|
||||
@@ -276,7 +281,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
int flags = 0;
|
||||
u16 flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
@@ -361,10 +366,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
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)))
|
||||
{
|
||||
@@ -377,7 +378,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
/* 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;
|
||||
flags |= SERV_LITERAL_ADDRESS;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
@@ -392,7 +393,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
@@ -407,7 +408,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
@@ -416,7 +417,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
}
|
||||
|
||||
cleanup_servers();
|
||||
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
|
||||
@@ -549,6 +550,10 @@ static DBusMessage *dbus_add_lease(DBusMessage* message)
|
||||
"Invalid IP address '%s'", ipaddr);
|
||||
|
||||
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||
if (hw_len < 0)
|
||||
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid HW address '%s'", hwaddr);
|
||||
|
||||
if (hw_type == 0 && hw_len != 0)
|
||||
hw_type = ARPHRD_ETHER;
|
||||
|
||||
@@ -672,7 +677,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
#endif
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
dbus_read_servers(message);
|
||||
reply = dbus_read_servers(message);
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
@@ -715,7 +720,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
if (new_servers)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
check_servers();
|
||||
check_servers(0);
|
||||
if (option_bool(OPT_RELOAD))
|
||||
clear_cache = 1;
|
||||
}
|
||||
@@ -723,7 +728,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
(void)user_data; /* no warning */
|
||||
|
||||
/* If no reply or no error, return nothing */
|
||||
if (!reply)
|
||||
|
||||
+62
-20
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -38,7 +38,7 @@ void dhcp_common_init(void)
|
||||
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
{
|
||||
ssize_t sz;
|
||||
ssize_t sz, new_sz;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -65,9 +65,48 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
}
|
||||
}
|
||||
|
||||
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
|
||||
/* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway.
|
||||
If that happens we get EAGAIN here because the socket is non-blocking.
|
||||
Use the result of the original testing recvmsg as long as the buffer
|
||||
was big enough. There's a small race here that may lose the odd packet,
|
||||
but it's UDP anyway. */
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||
if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
new_sz = sz;
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
|
||||
}
|
||||
|
||||
/* like match_netid() except that the check can have a trailing * for wildcard */
|
||||
/* started as a direct copy of match_netid() */
|
||||
int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||
{
|
||||
struct dhcp_netid *tmp1;
|
||||
|
||||
for (; check; check = check->next)
|
||||
{
|
||||
const int check_len = strlen(check->net);
|
||||
const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
|
||||
|
||||
/* '#' for not is for backwards compat. */
|
||||
if (check->net[0] != '!' && check->net[0] != '#')
|
||||
{
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
|
||||
(strcmp(check->net, tmp1->net) == 0))
|
||||
break;
|
||||
if (!tmp1)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||
if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
|
||||
(strcmp((check->net)+1, tmp1->net) == 0))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
@@ -75,8 +114,11 @@ struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
struct tag_if *exprs;
|
||||
struct dhcp_netid_list *list;
|
||||
|
||||
/* this now uses match_netid_wild() above so that tag_if can
|
||||
* be used to set a 'group of interfaces' tag.
|
||||
*/
|
||||
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
|
||||
if (match_netid(exprs->tag, tags, 1))
|
||||
if (match_netid_wild(exprs->tag, tags))
|
||||
for (list = exprs->set; list; list = list->next)
|
||||
{
|
||||
list->list->next = tags;
|
||||
@@ -271,31 +313,29 @@ static int is_config_in_context(struct dhcp_context *context, struct dhcp_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)
|
||||
{
|
||||
struct addrlist *addr_list;
|
||||
|
||||
if (!(config->flags & CONFIG_ADDR6))
|
||||
return 1;
|
||||
|
||||
for (; context; context = context->current)
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
{
|
||||
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
|
||||
return 1;
|
||||
|
||||
if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
|
||||
return 1;
|
||||
}
|
||||
if (config->flags & CONFIG_ADDR6)
|
||||
for (; context; context = context->current)
|
||||
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
|
||||
{
|
||||
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
|
||||
return 1;
|
||||
|
||||
if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (!(config->flags & CONFIG_ADDR))
|
||||
return 1;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
|
||||
return 1;
|
||||
@@ -613,6 +653,8 @@ static const struct opttab_t {
|
||||
{ "client-arch", 93, 2 | OT_DEC },
|
||||
{ "client-interface-id", 94, 0 },
|
||||
{ "client-machine-id", 97, 0 },
|
||||
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
|
||||
{ "subnet-select", 118, OT_INTERNAL },
|
||||
{ "domain-search", 119, OT_RFC1035_NAME },
|
||||
{ "sip-server", 120, 0 },
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+13
-8
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -468,8 +468,11 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
|
||||
/* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
|
||||
if (errno != 0)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
|
||||
inet_ntoa(dest.sin_addr), strerror(errno));
|
||||
{
|
||||
inet_ntop(AF_INET, &dest.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
|
||||
daemon->addrbuff, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
@@ -521,10 +524,11 @@ static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
|
||||
!(is_same_net(addr, context->start, netmask) &&
|
||||
is_same_net(addr, context->end, netmask)))
|
||||
{
|
||||
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
|
||||
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
|
||||
inet_ntop(AF_INET, &context->start, daemon->dhcp_buff, DHCP_BUFF_SZ);
|
||||
inet_ntop(AF_INET, &context->end, daemon->dhcp_buff2, DHCP_BUFF_SZ);
|
||||
inet_ntop(AF_INET, &netmask, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
|
||||
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
|
||||
daemon->dhcp_buff, daemon->dhcp_buff2, daemon->addrbuff);
|
||||
}
|
||||
context->netmask = netmask;
|
||||
}
|
||||
@@ -922,7 +926,7 @@ void dhcp_read_ethers(void)
|
||||
|
||||
if (!*cp)
|
||||
{
|
||||
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
|
||||
if (inet_pton(AF_INET, ip, &addr.s_addr) < 1)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
|
||||
continue;
|
||||
@@ -1097,7 +1101,8 @@ static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess,
|
||||
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.addr4));
|
||||
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
/* Save this for replies */
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -72,4 +72,3 @@
|
||||
#define DHCP6NOBINDING 3
|
||||
#define DHCP6NOTONLINK 4
|
||||
#define DHCP6USEMULTI 5
|
||||
|
||||
+3
-5
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -292,7 +292,7 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsi
|
||||
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
|
||||
break;
|
||||
|
||||
sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr));
|
||||
while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr))));
|
||||
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000000; /* 100ms */
|
||||
@@ -825,6 +825,4 @@ void dhcp_construct_contexts(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP6 */
|
||||
+34
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -80,8 +80,41 @@
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
#define EDNS0_OPTION_EDE 15 /* IANA - RFC 8914 */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors, negative values are our definitions */
|
||||
#define EDE_UNSET -1 /* No extended DNS error available */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||
#define EDE_STALE 3 /* Stale answer */
|
||||
#define EDE_FORGED 4 /* Forged answer */
|
||||
#define EDE_DNSSEC_IND 5 /* DNSSEC Indeterminate */
|
||||
#define EDE_DNSSEC_BOGUS 6 /* DNSSEC Bogus */
|
||||
#define EDE_SIG_EXP 7 /* Signature Expired */
|
||||
#define EDE_SIG_NYV 8 /* Signature Not Yet Valid */
|
||||
#define EDE_NO_DNSKEY 9 /* DNSKEY missing */
|
||||
#define EDE_NO_RRSIG 10 /* RRSIGs missing */
|
||||
#define EDE_NO_ZONEKEY 11 /* No Zone Key Bit Set */
|
||||
#define EDE_NO_NSEC 12 /* NSEC Missing */
|
||||
#define EDE_CACHED_ERR 13 /* Cached Error */
|
||||
#define EDE_NOT_READY 14 /* Not Ready */
|
||||
#define EDE_BLOCKED 15 /* Blocked */
|
||||
#define EDE_CENSORED 16 /* Censored */
|
||||
#define EDE_FILTERED 17 /* Filtered */
|
||||
#define EDE_PROHIBITED 18 /* Prohibited */
|
||||
#define EDE_STALE_NXD 19 /* Stale NXDOMAIN */
|
||||
#define EDE_NOT_AUTH 20 /* Not Authoritative */
|
||||
#define EDE_NOT_SUP 21 /* Not Supported */
|
||||
#define EDE_NO_AUTH 22 /* No Reachable Authority */
|
||||
#define EDE_NETERR 23 /* Network error */
|
||||
#define EDE_INVALID_DATA 24 /* Invalid Data */
|
||||
|
||||
|
||||
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
|
||||
+198
-120
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -17,14 +17,19 @@
|
||||
/* Declare static char *compiler_opts in config.h */
|
||||
#define DNSMASQ_COMPILE_OPTS
|
||||
|
||||
/* dnsmasq.h has to be included first as it sources config.h */
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
struct daemon *daemon;
|
||||
|
||||
static volatile pid_t pid = 0;
|
||||
static volatile int pipewrite;
|
||||
|
||||
static int set_dns_listeners(time_t now);
|
||||
static void set_dns_listeners(void);
|
||||
static void check_dns_listeners(time_t now);
|
||||
static void sig_handler(int sig);
|
||||
static void async_event(int pipe, time_t now);
|
||||
@@ -34,7 +39,6 @@ static void poll_resolv(int force, int do_reload, time_t now);
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int bind_fallback = 0;
|
||||
time_t now;
|
||||
struct sigaction sigact;
|
||||
struct iname *if_tmp;
|
||||
@@ -58,6 +62,9 @@ int main (int argc, char **argv)
|
||||
char *bound_device = NULL;
|
||||
int did_bind = 0;
|
||||
struct server *serv;
|
||||
char *netlink_warn;
|
||||
#else
|
||||
int bind_fallback = 0;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
@@ -67,8 +74,10 @@ int main (int argc, char **argv)
|
||||
int tftp_prefix_missing = 0;
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
#ifdef LOCALEDIR
|
||||
bindtextdomain("dnsmasq", LOCALEDIR);
|
||||
textdomain("dnsmasq");
|
||||
#endif
|
||||
@@ -89,11 +98,15 @@ int main (int argc, char **argv)
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
|
||||
umask(022); /* known umask, create leases and pid files as 0644 */
|
||||
|
||||
|
||||
rand_init(); /* Must precede read_opts() */
|
||||
|
||||
read_opts(argc, argv, compile_opts);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
daemon->kernel_version = kernel_version();
|
||||
#endif
|
||||
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = PACKETSZ;
|
||||
|
||||
@@ -104,7 +117,6 @@ int main (int argc, char **argv)
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
|
||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
@@ -130,6 +142,13 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
/* CONNTRACK UBUS code uses this buffer, so if not allocated above,
|
||||
we need to allocate it here. */
|
||||
if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename)
|
||||
daemon->workspacename = safe_malloc(MAXDNAME);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (!daemon->lease_file)
|
||||
{
|
||||
@@ -200,8 +219,13 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
|
||||
die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
if (daemon->query_port != 0 || daemon->osport)
|
||||
die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||
|
||||
need_cap_net_admin = 1;
|
||||
}
|
||||
#else
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
|
||||
@@ -232,9 +256,16 @@ int main (int argc, char **argv)
|
||||
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
/* Handle only one of min_port/max_port being set. */
|
||||
if (daemon->min_port != 0 && daemon->max_port == 0)
|
||||
daemon->max_port = MAX_PORT;
|
||||
|
||||
if (daemon->max_port != 0 && daemon->min_port == 0)
|
||||
daemon->min_port = MIN_PORT;
|
||||
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
if (daemon->auth_zones)
|
||||
@@ -322,8 +353,18 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NFTSET
|
||||
if (daemon->nftsets)
|
||||
{
|
||||
nftset_init();
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
need_cap_net_admin = 1;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_init();
|
||||
netlink_warn = netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
route_init();
|
||||
#endif
|
||||
@@ -354,7 +395,7 @@ int main (int argc, char **argv)
|
||||
bindtodevice(bound_device, daemon->dhcpfd);
|
||||
did_bind = 1;
|
||||
}
|
||||
if (daemon->enable_pxe && bound_device)
|
||||
if (daemon->enable_pxe && bound_device && daemon->pxefd != -1)
|
||||
{
|
||||
bindtodevice(bound_device, daemon->pxefd);
|
||||
did_bind = 1;
|
||||
@@ -385,8 +426,16 @@ int main (int argc, char **argv)
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
cache_init();
|
||||
|
||||
blockdata_init();
|
||||
hash_questions_init();
|
||||
|
||||
/* Scale random socket pool by ftabsize, but
|
||||
limit it based on available fds. */
|
||||
daemon->numrrand = daemon->ftabsize/2;
|
||||
if (daemon->numrrand > max_fd/3)
|
||||
daemon->numrrand = max_fd/3;
|
||||
/* safe_malloc returns zero'd memory */
|
||||
daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd));
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
@@ -410,8 +459,6 @@ int main (int argc, char **argv)
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
char *err;
|
||||
daemon->dbus = NULL;
|
||||
daemon->watches = NULL;
|
||||
if ((err = dbus_init()))
|
||||
die(_("DBus error: %s"), err, EC_MISC);
|
||||
}
|
||||
@@ -422,8 +469,9 @@ int main (int argc, char **argv)
|
||||
if (option_bool(OPT_UBUS))
|
||||
#ifdef HAVE_UBUS
|
||||
{
|
||||
daemon->ubus = NULL;
|
||||
ubus_init();
|
||||
char *err;
|
||||
if ((err = ubus_init()))
|
||||
die(_("UBus error: %s"), err, EC_MISC);
|
||||
}
|
||||
#else
|
||||
die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
||||
@@ -890,8 +938,10 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_WARNING, _("warning: failed to change owner of %s: %s"),
|
||||
daemon->log_file, strerror(log_err));
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
warn_bound_listeners();
|
||||
@@ -942,6 +992,9 @@ int main (int argc, char **argv)
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
if (did_bind)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
|
||||
|
||||
if (netlink_warn)
|
||||
my_syslog(LOG_WARNING, netlink_warn);
|
||||
# endif
|
||||
|
||||
/* after dhcp_construct_contexts */
|
||||
@@ -972,7 +1025,7 @@ int main (int argc, char **argv)
|
||||
a single file will be sent to may clients (the file only needs
|
||||
one fd). */
|
||||
|
||||
max_fd -= 30; /* use other than TFTP */
|
||||
max_fd -= 30 + daemon->numrrand; /* use other than TFTP */
|
||||
|
||||
if (max_fd < 0)
|
||||
max_fd = 5;
|
||||
@@ -1002,7 +1055,7 @@ int main (int argc, char **argv)
|
||||
close(err_pipe[1]);
|
||||
|
||||
if (daemon->port != 0)
|
||||
check_servers();
|
||||
check_servers(0);
|
||||
|
||||
pid = getpid();
|
||||
|
||||
@@ -1017,16 +1070,10 @@ int main (int argc, char **argv)
|
||||
|
||||
while (1)
|
||||
{
|
||||
int t, timeout = -1;
|
||||
int timeout = -1;
|
||||
|
||||
poll_reset();
|
||||
|
||||
/* if we are out of resources, find how long we have to wait
|
||||
for some to come free, we'll loop around then and restart
|
||||
listening for queries */
|
||||
if ((t = set_dns_listeners(now)) != 0)
|
||||
timeout = t * 1000;
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
@@ -1036,15 +1083,18 @@ int main (int argc, char **argv)
|
||||
else if (is_dad_listeners())
|
||||
timeout = 1000;
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners();
|
||||
#endif
|
||||
set_dns_listeners();
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (option_bool(OPT_DBUS))
|
||||
set_dbus_listeners();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (option_bool(OPT_UBUS))
|
||||
set_ubus_listeners();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
@@ -1164,28 +1214,44 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS))
|
||||
{
|
||||
char *err;
|
||||
if ((err = dbus_init()))
|
||||
my_syslog(LOG_WARNING, _("DBus error: %s"), err);
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
||||
if (!daemon->dbus)
|
||||
{
|
||||
char *err = dbus_init();
|
||||
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("connected to system DBus"));
|
||||
else if (err)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("DBus error: %s"), err);
|
||||
reset_option_bool(OPT_DBUS); /* fatal error, stop trying. */
|
||||
}
|
||||
}
|
||||
|
||||
check_dbus_listeners();
|
||||
}
|
||||
check_dbus_listeners();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
/* if we didn't create a UBus connection, retry now. */
|
||||
if (option_bool(OPT_UBUS))
|
||||
{
|
||||
/* if we didn't create a UBus connection, retry now. */
|
||||
if (!daemon->ubus)
|
||||
{
|
||||
ubus_init();
|
||||
}
|
||||
{
|
||||
if (!daemon->ubus)
|
||||
{
|
||||
char *err = ubus_init();
|
||||
|
||||
check_ubus_listeners();
|
||||
}
|
||||
if (daemon->ubus)
|
||||
my_syslog(LOG_INFO, _("connected to system UBus"));
|
||||
else if (err)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("UBus error: %s"), err);
|
||||
reset_option_bool(OPT_UBUS); /* fatal error, stop trying. */
|
||||
}
|
||||
}
|
||||
|
||||
check_ubus_listeners();
|
||||
}
|
||||
#endif
|
||||
|
||||
check_dns_listeners(now);
|
||||
@@ -1418,7 +1484,7 @@ static void async_event(int pipe, time_t now)
|
||||
}
|
||||
|
||||
if (check)
|
||||
check_servers();
|
||||
check_servers(0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -1529,7 +1595,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
/* block in writes until all done */
|
||||
if ((i = fcntl(daemon->helperfd, F_GETFL)) != -1)
|
||||
fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(daemon->helperfd, F_SETFL, i & ~O_NONBLOCK)));
|
||||
do {
|
||||
helper_write();
|
||||
} while (!helper_buf_empty() || do_script_run(now));
|
||||
@@ -1617,12 +1683,17 @@ static void poll_resolv(int force, int do_reload, time_t now)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("reading %s"), latest->name);
|
||||
warned = 0;
|
||||
check_servers();
|
||||
check_servers(0);
|
||||
if (option_bool(OPT_RELOAD) && do_reload)
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we're delaying things, we don't call check_servers(), but
|
||||
reload_servers() may have deleted some servers, rendering the server_array
|
||||
invalid, so just rebuild that here. Once reload_servers() succeeds,
|
||||
we call check_servers() above, which calls build_server_array itself. */
|
||||
build_server_array();
|
||||
latest->mtime = 0;
|
||||
if (!warned)
|
||||
{
|
||||
@@ -1660,11 +1731,12 @@ void clear_cache_and_reload(time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_dns_listeners(time_t now)
|
||||
static void set_dns_listeners(void)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
int wait = 0, i;
|
||||
struct randfd_list *rfl;
|
||||
int i;
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
int tftp = 0;
|
||||
@@ -1677,66 +1749,68 @@ static int set_dns_listeners(time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* will we be able to get memory? */
|
||||
if (daemon->port != 0)
|
||||
get_new_frec(now, &wait, 0);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
poll_listen(serverfdp->fd, POLLIN);
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0)
|
||||
poll_listen(daemon->randomsocks[i].fd, POLLIN);
|
||||
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0)
|
||||
poll_listen(daemon->randomsocks[i].fd, POLLIN);
|
||||
|
||||
/* Check overflow random sockets too. */
|
||||
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
||||
poll_listen(rfl->rfd->fd, POLLIN);
|
||||
|
||||
/* check to see if we have free tcp process slots. */
|
||||
for (i = MAX_PROCS - 1; i >= 0; i--)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
break;
|
||||
|
||||
for (listener = daemon->listeners; listener; listener = listener->next)
|
||||
{
|
||||
/* only listen for queries if we have resources */
|
||||
if (listener->fd != -1 && wait == 0)
|
||||
if (listener->fd != -1)
|
||||
poll_listen(listener->fd, POLLIN);
|
||||
|
||||
/* death of a child goes through the select loop, so
|
||||
we don't need to explicitly arrange to wake up here */
|
||||
if (listener->tcpfd != -1)
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
poll_listen(listener->tcpfd, POLLIN);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Only listen for TCP connections when a process slot
|
||||
is available. Death of a child goes through the select loop, so
|
||||
we don't need to explicitly arrange to wake up here,
|
||||
we'll be called again when a slot becomes available. */
|
||||
if (listener->tcpfd != -1 && i >= 0)
|
||||
poll_listen(listener->tcpfd, POLLIN);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* tftp == 0 in single-port mode. */
|
||||
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
|
||||
poll_listen(listener->tftpfd, POLLIN);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pipes[i] != -1)
|
||||
poll_listen(daemon->tcp_pipes[i], POLLIN);
|
||||
|
||||
return wait;
|
||||
}
|
||||
|
||||
static void check_dns_listeners(time_t now)
|
||||
{
|
||||
struct serverfd *serverfdp;
|
||||
struct listener *listener;
|
||||
struct randfd_list *rfl;
|
||||
int i;
|
||||
int pipefd[2];
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
if (poll_check(serverfdp->fd, POLLIN))
|
||||
reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now);
|
||||
reply_query(serverfdp->fd, now);
|
||||
|
||||
if (daemon->port != 0 && !daemon->osport)
|
||||
for (i = 0; i < RANDOM_SOCKS; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||
reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now);
|
||||
for (i = 0; i < daemon->numrrand; i++)
|
||||
if (daemon->randomsocks[i].refcount != 0 &&
|
||||
poll_check(daemon->randomsocks[i].fd, POLLIN))
|
||||
reply_query(daemon->randomsocks[i].fd, now);
|
||||
|
||||
/* Check overflow random sockets too. */
|
||||
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
|
||||
if (poll_check(rfl->rfd->fd, POLLIN))
|
||||
reply_query(rfl->rfd->fd, now);
|
||||
|
||||
/* Races. The child process can die before we read all of the data from the
|
||||
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
|
||||
@@ -1765,7 +1839,16 @@ static void check_dns_listeners(time_t now)
|
||||
tftp_request(listener, now);
|
||||
#endif
|
||||
|
||||
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
|
||||
/* check to see if we have a free tcp process slot.
|
||||
Note that we can't assume that because we had
|
||||
at least one a poll() time, that we still do.
|
||||
There may be more waiting connections after
|
||||
poll() returns then free process slots. */
|
||||
for (i = MAX_PROCS - 1; i >= 0; i--)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
break;
|
||||
|
||||
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
|
||||
{
|
||||
int confd, client_ok = 1;
|
||||
struct irec *iface = NULL;
|
||||
@@ -1816,7 +1899,8 @@ static void check_dns_listeners(time_t now)
|
||||
addr.addr4 = tcp_addr.in.sin_addr;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
if (iface->index == if_index &&
|
||||
iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
@@ -1854,34 +1938,28 @@ static void check_dns_listeners(time_t now)
|
||||
close(pipefd[0]);
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
char a;
|
||||
(void)a; /* suppress potential unused warning */
|
||||
|
||||
daemon->tcp_pids[i] = p;
|
||||
daemon->tcp_pipes[i] = pipefd[0];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
retry_send(read(pipefd[0], &a, 1));
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
|
||||
unsigned char a;
|
||||
read_write(pipefd[0], &a, 1, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
/* i holds index of free slot */
|
||||
daemon->tcp_pids[i] = p;
|
||||
daemon->tcp_pipes[i] = pipefd[0];
|
||||
}
|
||||
close(confd);
|
||||
|
||||
@@ -1911,16 +1989,16 @@ static void check_dns_listeners(time_t now)
|
||||
terminate the process. */
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
char a = 0;
|
||||
(void)a; /* suppress potential unused warning */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re: netlink socket. */
|
||||
unsigned char a = 0;
|
||||
|
||||
close(daemon->netlinkfd);
|
||||
read_write(pipefd[1], &a, 1, 0);
|
||||
#endif
|
||||
alarm(CHILD_LIFETIME);
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re netlink socket. */
|
||||
close(daemon->netlinkfd);
|
||||
retry_send(write(pipefd[1], &a, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
@@ -1931,7 +2009,7 @@ static void check_dns_listeners(time_t now)
|
||||
attribute from the listening socket.
|
||||
Reset that here. */
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
|
||||
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
|
||||
|
||||
@@ -1947,8 +2025,10 @@ static void check_dns_listeners(time_t now)
|
||||
shutdown(s->tcpfd, SHUT_RDWR);
|
||||
close(s->tcpfd);
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
close(daemon->pipe_to_parent);
|
||||
flush_log();
|
||||
_exit(0);
|
||||
}
|
||||
@@ -2058,7 +2138,7 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
|
||||
poll_reset();
|
||||
if (fd != -1)
|
||||
poll_listen(fd, POLLIN);
|
||||
set_dns_listeners(now);
|
||||
set_dns_listeners();
|
||||
set_log_writer();
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -2108,6 +2188,4 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP */
|
||||
+239
-100
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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-2020 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2021 Simon Kelley"
|
||||
|
||||
/* We do defines that influence behavior of stdio.h, so complain
|
||||
if included too early. */
|
||||
@@ -95,11 +95,7 @@ typedef unsigned long long u64;
|
||||
#if defined(HAVE_SOLARIS_NETWORK)
|
||||
# include <sys/sockio.h>
|
||||
#endif
|
||||
#if defined(HAVE_POLL_H)
|
||||
# include <poll.h>
|
||||
#else
|
||||
# include <sys/poll.h>
|
||||
#endif
|
||||
#include <poll.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/un.h>
|
||||
@@ -111,6 +107,7 @@ typedef unsigned long long u64;
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
@@ -141,6 +138,7 @@ typedef unsigned long long u64;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
#include <linux/version.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/capability.h>
|
||||
/* There doesn't seem to be a universally-available
|
||||
@@ -156,7 +154,11 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Backwards compat with 2.83 */
|
||||
#if defined(HAVE_NETTLEHASH)
|
||||
# define HAVE_CRYPTOHASH
|
||||
#endif
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
@@ -268,7 +270,12 @@ struct event_desc {
|
||||
#define OPT_IGNORE_CLID 59
|
||||
#define OPT_SINGLE_PORT 60
|
||||
#define OPT_LEASE_RENEW 61
|
||||
#define OPT_LAST 62
|
||||
#define OPT_LOG_DEBUG 62
|
||||
#define OPT_UMBRELLA 63
|
||||
#define OPT_UMBRELLA_DEVID 64
|
||||
#define OPT_CMARK_ALST_EN 65
|
||||
#define OPT_QUIET_TFTP 66
|
||||
#define OPT_LAST 67
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -276,11 +283,13 @@ struct event_desc {
|
||||
#define option_val(x) ((1u) << ((x) % OPTION_BITS))
|
||||
#define option_bool(x) (option_var(x) & option_val(x))
|
||||
|
||||
/* 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. */
|
||||
/* extra flags for my_syslog, we use facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up.
|
||||
MS_DEBUG messages are suppressed unless --log-debug is set. */
|
||||
#define MS_TFTP LOG_USER
|
||||
#define MS_DHCP LOG_DAEMON
|
||||
#define MS_SCRIPT LOG_MAIL
|
||||
#define MS_DEBUG LOG_NEWS
|
||||
|
||||
/* Note that this is used widely as a container for IPv4/IPv6 addresses,
|
||||
so for that reason, was well as to avoid wasting memory in almost every
|
||||
@@ -316,12 +325,14 @@ union all_addr {
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest, rcode;
|
||||
int ede;
|
||||
} log;
|
||||
};
|
||||
|
||||
|
||||
struct bogus_addr {
|
||||
struct in_addr addr;
|
||||
int is6, prefix;
|
||||
union all_addr addr;
|
||||
struct bogus_addr *next;
|
||||
};
|
||||
|
||||
@@ -422,10 +433,17 @@ struct host_record {
|
||||
struct host_record *next;
|
||||
};
|
||||
|
||||
#define IN4 1
|
||||
#define IN6 2
|
||||
#define INP4 4
|
||||
#define INP6 8
|
||||
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
int family; /* AF_INET, AF_INET6 or zero for both */
|
||||
int flags;
|
||||
struct in_addr proto4;
|
||||
struct in6_addr proto6;
|
||||
struct addrlist *addr;
|
||||
struct interface_name *next;
|
||||
};
|
||||
@@ -485,7 +503,7 @@ struct crec {
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
#define F_NOEXTRA (1u<<27)
|
||||
#define F_SERVFAIL (1u<<28) /* currently unused. */
|
||||
#define F_DOMAINSRV (1u<<28)
|
||||
#define F_RCODE (1u<<29)
|
||||
#define F_SRV (1u<<30)
|
||||
|
||||
@@ -511,23 +529,24 @@ union mysockaddr {
|
||||
#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 */
|
||||
#define SERV_HAS_DOMAIN 8 /* server for one domain only */
|
||||
#define SERV_HAS_SOURCE 16 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
|
||||
#define SERV_MARK 256 /* for mark-and-delete */
|
||||
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
|
||||
#define SERV_COUNTED 512 /* workspace for log code */
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
/* The actual values here matter, since we sort on them to get records in the order
|
||||
IPv6 addr, IPv4 addr, all zero return, resolvconf servers, upstream server, no-data return */
|
||||
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next four flags */
|
||||
#define SERV_USE_RESOLV 2 /* forward this domain in the normal way */
|
||||
#define SERV_ALL_ZEROS 4 /* return all zeros for A and AAAA */
|
||||
#define SERV_4ADDR 8 /* addr is IPv4 */
|
||||
#define SERV_6ADDR 16 /* addr is IPv6 */
|
||||
#define SERV_HAS_SOURCE 32 /* source address defined */
|
||||
#define SERV_FOR_NODOTS 64 /* server for names with no domain part only */
|
||||
#define SERV_WARNED_RECURSIVE 128 /* avoid warning spam */
|
||||
#define SERV_FROM_DBUS 256 /* 1 if source is DBus */
|
||||
#define SERV_MARK 512 /* for mark-and-delete and log code */
|
||||
#define SERV_WILDCARD 1024 /* domain has leading '*' */
|
||||
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
#define SERV_LOOP 8192 /* server causes forwarding loop */
|
||||
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
|
||||
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -538,22 +557,61 @@ struct serverfd {
|
||||
};
|
||||
|
||||
struct randfd {
|
||||
struct server *serv;
|
||||
int fd;
|
||||
unsigned short refcount, family;
|
||||
unsigned short refcount; /* refcount == 0xffff means overflow record. */
|
||||
};
|
||||
|
||||
|
||||
struct randfd_list {
|
||||
struct randfd *rfd;
|
||||
struct randfd_list *next;
|
||||
};
|
||||
|
||||
|
||||
struct server {
|
||||
u16 flags, domain_len;
|
||||
char *domain;
|
||||
struct server *next;
|
||||
int serial, arrayposn;
|
||||
int last_server;
|
||||
union mysockaddr addr, source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
unsigned int ifindex; /* corresponding to interface, above */
|
||||
struct serverfd *sfd;
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd, edns_pktsz;
|
||||
int tcpfd, edns_pktsz;
|
||||
time_t pktsz_reduced;
|
||||
unsigned int queries, failed_queries;
|
||||
time_t forwardtime;
|
||||
int forwardcount;
|
||||
#ifdef HAVE_LOOP
|
||||
u32 uid;
|
||||
#endif
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
/* First four fields must match struct server in next three definitions.. */
|
||||
struct serv_addr4 {
|
||||
u16 flags, domain_len;
|
||||
char *domain;
|
||||
struct server *next;
|
||||
struct in_addr addr;
|
||||
};
|
||||
|
||||
struct serv_addr6 {
|
||||
u16 flags, domain_len;
|
||||
char *domain;
|
||||
struct server *next;
|
||||
struct in6_addr addr;
|
||||
};
|
||||
|
||||
struct serv_local {
|
||||
u16 flags, domain_len;
|
||||
char *domain;
|
||||
struct server *next;
|
||||
};
|
||||
|
||||
struct rebind_domain {
|
||||
char *domain;
|
||||
struct rebind_domain *next;
|
||||
};
|
||||
|
||||
struct ipsets {
|
||||
@@ -562,6 +620,12 @@ struct ipsets {
|
||||
struct ipsets *next;
|
||||
};
|
||||
|
||||
struct allowlist {
|
||||
u32 mark, mask;
|
||||
char **patterns;
|
||||
struct allowlist *next;
|
||||
};
|
||||
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
@@ -571,7 +635,8 @@ struct irec {
|
||||
};
|
||||
|
||||
struct listener {
|
||||
int fd, tcpfd, tftpfd, family;
|
||||
int fd, tcpfd, tftpfd, used;
|
||||
union mysockaddr addr;
|
||||
struct irec *iface; /* only sometimes valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
@@ -630,17 +695,28 @@ struct hostsfile {
|
||||
#define DUMP_BOGUS 0x0040
|
||||
#define DUMP_SEC_BOGUS 0x0080
|
||||
|
||||
|
||||
/* 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_OK 8
|
||||
#define STAT_ABANDONED 9
|
||||
#define STAT_SECURE 0x10000
|
||||
#define STAT_INSECURE 0x20000
|
||||
#define STAT_BOGUS 0x30000
|
||||
#define STAT_NEED_DS 0x40000
|
||||
#define STAT_NEED_KEY 0x50000
|
||||
#define STAT_TRUNCATED 0x60000
|
||||
#define STAT_SECURE_WILDCARD 0x70000
|
||||
#define STAT_OK 0x80000
|
||||
#define STAT_ABANDONED 0x90000
|
||||
|
||||
#define DNSSEC_FAIL_NYV 0x0001 /* key not yet valid */
|
||||
#define DNSSEC_FAIL_EXP 0x0002 /* key expired */
|
||||
#define DNSSEC_FAIL_INDET 0x0004 /* indetermined */
|
||||
#define DNSSEC_FAIL_NOKEYSUP 0x0008 /* no supported key algo. */
|
||||
#define DNSSEC_FAIL_NOSIG 0x0010 /* No RRsigs */
|
||||
#define DNSSEC_FAIL_NOZONE 0x0020 /* No Zone bit set */
|
||||
#define DNSSEC_FAIL_NONSEC 0x0040 /* No NSEC */
|
||||
#define DNSSEC_FAIL_NODSSUP 0x0080 /* no supported DS algo. */
|
||||
#define DNSSEC_FAIL_NOKEY 0x0100 /* no DNSKEY */
|
||||
|
||||
#define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b))
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
@@ -651,23 +727,25 @@ struct hostsfile {
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_TEST_PKTSZ 256
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_EXTRADATA 512
|
||||
#define FREC_HAS_PHEADER 1024
|
||||
#define FREC_NO_CACHE 2048
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
#else
|
||||
#define HASH_SIZE sizeof(int)
|
||||
#endif
|
||||
#define HASH_SIZE 32 /* SHA-256 digest size */
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
struct frec_src {
|
||||
union mysockaddr source;
|
||||
union all_addr dest;
|
||||
unsigned int iface, log_id;
|
||||
int fd;
|
||||
unsigned short orig_id;
|
||||
struct frec_src *next;
|
||||
} frec_src;
|
||||
struct server *sentto; /* NULL means free */
|
||||
struct randfd *rfd4;
|
||||
struct randfd *rfd6;
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int log_id, fd, forwardall, flags;
|
||||
struct randfd_list *rfds;
|
||||
unsigned short new_id;
|
||||
int forwardall, flags;
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
@@ -675,6 +753,7 @@ struct frec {
|
||||
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 *next_dependent; /* list of above. */
|
||||
struct frec *blocking_query; /* Query which is blocking us. */
|
||||
#endif
|
||||
struct frec *next;
|
||||
@@ -827,6 +906,7 @@ struct dhcp_opt {
|
||||
#define DHOPT_RFC3925 2048
|
||||
#define DHOPT_TAGOK 4096
|
||||
#define DHOPT_ADDR6 8192
|
||||
#define DHOPT_VENDOR_PXE 16384
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname, *tftp_sname;
|
||||
@@ -850,6 +930,8 @@ struct pxe_service {
|
||||
struct pxe_service *next;
|
||||
};
|
||||
|
||||
#define DHCP_PXE_DEF_VENDOR "PXEClient"
|
||||
|
||||
#define MATCH_VENDOR 1
|
||||
#define MATCH_USER 2
|
||||
#define MATCH_CIRCUIT 3
|
||||
@@ -865,6 +947,11 @@ struct dhcp_vendor {
|
||||
struct dhcp_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_pxe_vendor {
|
||||
char *data;
|
||||
struct dhcp_pxe_vendor *next;
|
||||
};
|
||||
|
||||
struct dhcp_mac {
|
||||
unsigned int mask;
|
||||
int hwaddr_len, hwaddr_type;
|
||||
@@ -879,10 +966,10 @@ struct dhcp_bridge {
|
||||
};
|
||||
|
||||
struct cond_domain {
|
||||
char *domain, *prefix;
|
||||
char *domain, *prefix; /* prefix is text-prefix on domain name */
|
||||
struct in_addr start, end;
|
||||
struct in6_addr start6, end6;
|
||||
int is6, indexed;
|
||||
int is6, indexed, prefixlen;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
@@ -940,6 +1027,7 @@ struct shared_network {
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
#define CONTEXT_RA_OFF_LINK (1u<<18)
|
||||
#define CONTEXT_SETLEASE (1u<<19)
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -1022,8 +1110,13 @@ extern struct daemon {
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
|
||||
struct bogus_addr *bogus_addr, *ignore_addr;
|
||||
struct server *servers;
|
||||
struct ipsets *ipsets;
|
||||
struct server *servers, *servers_tail, *local_domains, **serverarray;
|
||||
struct rebind_domain *no_rebind;
|
||||
int server_has_wildcard;
|
||||
int serverarraysz, serverarrayhwm;
|
||||
struct ipsets *ipsets, *nftsets;
|
||||
u32 allowlist_mask;
|
||||
struct allowlist *allowlists;
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
@@ -1031,12 +1124,16 @@ extern struct daemon {
|
||||
int port, query_port, min_port, max_port;
|
||||
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
|
||||
char *dns_client_id;
|
||||
u32 umbrella_org;
|
||||
u32 umbrella_asset;
|
||||
u8 umbrella_device[8];
|
||||
struct hostsfile *addn_hosts;
|
||||
struct dhcp_context *dhcp, *dhcp6;
|
||||
struct ra_interface *ra_interfaces;
|
||||
struct dhcp_config *dhcp_conf;
|
||||
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
|
||||
struct dhcp_match_name *dhcp_name_match;
|
||||
struct dhcp_pxe_vendor *dhcp_pxe_vendors;
|
||||
struct dhcp_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
@@ -1062,6 +1159,7 @@ extern struct daemon {
|
||||
unsigned int duid_enterprise, duid_config_len;
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
char *ubus_name;
|
||||
char *dump_file;
|
||||
int dump_mask;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
@@ -1075,28 +1173,32 @@ extern struct daemon {
|
||||
char *packet; /* packet buffer */
|
||||
int packet_buff_sz; /* size of above */
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
|
||||
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
|
||||
char *workspacename;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
||||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
int back_to_the_future;
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
struct frec_src *free_frec_src;
|
||||
int frec_src_count;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
struct listener *listeners;
|
||||
struct server *last_server;
|
||||
time_t forwardtime;
|
||||
int forwardcount;
|
||||
struct server *srv_save; /* Used for resend on DoD */
|
||||
size_t packet_len; /* " " */
|
||||
struct randfd *rfd_save; /* " " */
|
||||
int fd_save; /* " " */
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
int tcp_pipes[MAX_PROCS];
|
||||
int pipe_to_parent;
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int numrrand;
|
||||
struct randfd *randomsocks;
|
||||
struct randfd_list *rfl_spare, *rfl_poll;
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
int log_id, log_display_id; /* ids of transactions for logging */
|
||||
@@ -1108,7 +1210,7 @@ extern struct daemon {
|
||||
int inotifyfd;
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
int netlinkfd;
|
||||
int netlinkfd, kernel_version;
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
|
||||
#endif
|
||||
@@ -1152,9 +1254,8 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void next_uid(struct crec *crecp);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
int cache_find_non_terminal(char *name, time_t now);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
union all_addr *addr, time_t now,
|
||||
@@ -1203,20 +1304,20 @@ 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,
|
||||
union all_addr *addrp, unsigned int flags,
|
||||
unsigned long ttl);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
||||
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
||||
#endif
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
@@ -1234,6 +1335,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, int edns_pktsz);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
@@ -1241,8 +1343,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
int errflags_to_ede(int status);
|
||||
#endif
|
||||
|
||||
/* hash_questions.c */
|
||||
void hash_questions_init(void);
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
@@ -1266,12 +1373,13 @@ void safe_strncpy(char *dest, const char *src, size_t size);
|
||||
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 sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||
int hostname_isequal(const char *a, const char *b);
|
||||
int hostname_issubdomain(char *a, char *b);
|
||||
time_t dnsmasq_time(void);
|
||||
int netmask_length(struct in_addr mask);
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix);
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||
u64 addr6part(struct in6_addr *addr);
|
||||
void setaddr6part(struct in6_addr *addr, u64 host);
|
||||
@@ -1288,6 +1396,9 @@ int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
int kernel_version(void);
|
||||
#endif
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN;
|
||||
@@ -1310,37 +1421,28 @@ 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);
|
||||
union mysockaddr *source_addr, char *interface, u16 *flags);
|
||||
int option_read_dynfile(char *file, int flags);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void reply_query(int fd, 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, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
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, union all_addr *source,
|
||||
unsigned int iface);
|
||||
void resend_query(void);
|
||||
struct randfd *allocate_rfd(int family);
|
||||
void free_rfd(struct randfd *rfd);
|
||||
int allocate_rfd(struct randfd_list **fdlp, struct server *serv);
|
||||
void free_rfds(struct randfd_list **fdlp);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
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);
|
||||
void check_servers(int no_loop_call);
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int dienow);
|
||||
@@ -1445,7 +1547,7 @@ void clear_cache_and_reload(time_t now);
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
char *netlink_init(void);
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
@@ -1473,10 +1575,14 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
|
||||
/* ubus.c */
|
||||
#ifdef HAVE_UBUS
|
||||
void ubus_init(void);
|
||||
char *ubus_init(void);
|
||||
void set_ubus_listeners(void);
|
||||
void check_ubus_listeners(void);
|
||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
|
||||
# ifdef HAVE_CONNTRACK
|
||||
void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name);
|
||||
void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *pattern, const char *ip, u32 ttl);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ipset.c */
|
||||
@@ -1485,6 +1591,19 @@ void ipset_init(void);
|
||||
int add_to_ipset(const char *setname, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* nftset.c */
|
||||
#ifdef HAVE_NFTSET
|
||||
void nftset_init(void);
|
||||
int add_to_nftset(const char *setpath, const union all_addr *ipaddr, int flags, int remove);
|
||||
#endif
|
||||
|
||||
/* pattern.c */
|
||||
#ifdef HAVE_CONNTRACK
|
||||
int is_valid_dns_name(const char *value);
|
||||
int is_valid_dns_name_pattern(const char *value);
|
||||
int is_dns_name_matching_pattern(const char *name, const char *pattern);
|
||||
#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);
|
||||
@@ -1638,7 +1757,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet);
|
||||
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
|
||||
/* arp.c */
|
||||
@@ -1650,3 +1769,23 @@ int do_arp_script_run(void);
|
||||
void dump_init(void);
|
||||
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
|
||||
#endif
|
||||
|
||||
/* domain-match.c */
|
||||
void build_server_array(void);
|
||||
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
|
||||
int filter_servers(int seed, int flags, int *lowout, int *highout);
|
||||
int is_local_answer(time_t now, int first, char *name);
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header,
|
||||
char *name, char *limit, int first, int last, int ede);
|
||||
int server_samegroup(struct server *a, struct server *b);
|
||||
#ifdef HAVE_DNSSEC
|
||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
|
||||
#endif
|
||||
void mark_servers(int flag);
|
||||
void cleanup_servers(void);
|
||||
int add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain,
|
||||
union all_addr *local_addr);
|
||||
+331
-219
@@ -215,137 +215,135 @@ static int is_check_date(unsigned long curtime)
|
||||
return !daemon->dnssec_no_time_check;
|
||||
}
|
||||
|
||||
/* Check whether today/now is between date_start and date_end */
|
||||
static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
|
||||
{
|
||||
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
|
||||
return serial_compare_32(curtime, date_start) == SERIAL_GT
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
|
||||
data, pointed to by *p, should be used raw. */
|
||||
static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
|
||||
unsigned char **p, u16 **desc)
|
||||
{
|
||||
int d = **desc;
|
||||
|
||||
/* No more data needs mangling */
|
||||
if (d == (u16)-1)
|
||||
{
|
||||
/* If there's more data than we have space for, just return what fits,
|
||||
we'll get called again for more chunks */
|
||||
if (end - *p > bufflen)
|
||||
{
|
||||
memcpy(buff, *p, bufflen);
|
||||
*p += bufflen;
|
||||
return bufflen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
(*desc)++;
|
||||
|
||||
if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
|
||||
/* domain-name, canonicalise */
|
||||
return to_wire(buff);
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((end - *p) < d)
|
||||
d = end - *p;
|
||||
|
||||
if (d != 0)
|
||||
{
|
||||
memcpy(buff, *p, d);
|
||||
*p += d;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bubble sort the RRset into the canonical order.
|
||||
Note that the byte-streams from two RRs may get unsynced: consider
|
||||
RRs which have two domain-names at the start and then other data.
|
||||
The domain-names may have different lengths in each RR, but sort equal
|
||||
|
||||
------------
|
||||
|abcde|fghi|
|
||||
------------
|
||||
|abcd|efghi|
|
||||
------------
|
||||
|
||||
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
/* Return bytes of canonicalised rrdata one by one.
|
||||
Init state->ip with the RR, and state->end with the end of same.
|
||||
Init state->op to NULL.
|
||||
Init state->desc to RR descriptor.
|
||||
Init state->buff with a MAXDNAME * 2 buffer.
|
||||
|
||||
After each call which returns 1, state->op points to the next byte of data.
|
||||
On returning 0, the end has been reached.
|
||||
*/
|
||||
struct rdata_state {
|
||||
u16 *desc;
|
||||
size_t c;
|
||||
unsigned char *end, *ip, *op;
|
||||
char *buff;
|
||||
};
|
||||
|
||||
static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
|
||||
{
|
||||
int d;
|
||||
|
||||
if (state->op && state->c != 1)
|
||||
{
|
||||
state->op++;
|
||||
state->c--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
d = *(state->desc);
|
||||
|
||||
if (d == (u16)-1)
|
||||
{
|
||||
/* all the bytes to the end. */
|
||||
if ((state->c = state->end - state->ip) != 0)
|
||||
{
|
||||
state->op = state->ip;
|
||||
state->ip = state->end;;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->desc++;
|
||||
|
||||
if (d == (u16)0)
|
||||
{
|
||||
/* domain-name, canonicalise */
|
||||
int len;
|
||||
|
||||
if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
|
||||
(len = to_wire(state->buff)) == 0)
|
||||
continue;
|
||||
|
||||
state->c = len;
|
||||
state->op = (unsigned char *)state->buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((state->end - state->ip) < d)
|
||||
d = state->end - state->ip;
|
||||
|
||||
if (d == 0)
|
||||
continue;
|
||||
|
||||
state->op = state->ip;
|
||||
state->c = d;
|
||||
state->ip += d;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bubble sort the RRset into the canonical order. */
|
||||
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
int swap, quit, i, j;
|
||||
int swap, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
for (swap = 0, i = 0; i < rrsetidx-1; i++)
|
||||
{
|
||||
int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
|
||||
u16 *dp1, *dp2;
|
||||
unsigned char *end1, *end2;
|
||||
int rdlen1, rdlen2;
|
||||
struct rdata_state state1, state2;
|
||||
|
||||
/* Note that these have been determined to be OK previously,
|
||||
so we don't need to check for NULL return here. */
|
||||
unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
|
||||
unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.ip = skip_name(rrset[i], header, plen, 10);
|
||||
state2.ip = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.op = state2.op = NULL;
|
||||
state1.buff = buff1;
|
||||
state2.buff = buff2;
|
||||
state1.desc = state2.desc = rr_desc;
|
||||
|
||||
p1 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, p1);
|
||||
end1 = p1 + rdlen1;
|
||||
state1.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, state1.ip);
|
||||
if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
|
||||
return rrsetidx; /* short packet */
|
||||
state1.end = state1.ip + rdlen1;
|
||||
|
||||
p2 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, p2);
|
||||
end2 = p2 + rdlen2;
|
||||
|
||||
dp1 = dp2 = rr_desc;
|
||||
|
||||
for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
|
||||
state2.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, state2.ip);
|
||||
if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
return rrsetidx; /* short packet */
|
||||
state2.end = state2.ip + rdlen2;
|
||||
|
||||
/* If the RR has no names in it then canonicalisation
|
||||
is the identity function and we can compare
|
||||
the RRs directly. If not we compare the
|
||||
canonicalised RRs one byte at a time. */
|
||||
if (*rr_desc == (u16)-1)
|
||||
{
|
||||
if (left1 != 0)
|
||||
memmove(buff1, buff1 + len1 - left1, left1);
|
||||
int rdmin = rdlen1 > rdlen2 ? rdlen2 : rdlen1;
|
||||
int cmp = memcmp(state1.ip, state2.ip, rdmin);
|
||||
|
||||
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len1 = end1 - p1;
|
||||
memcpy(buff1 + left1, p1, len1);
|
||||
}
|
||||
len1 += left1;
|
||||
|
||||
if (left2 != 0)
|
||||
memmove(buff2, buff2 + len2 - left2, left2);
|
||||
|
||||
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len2 = end2 - p2;
|
||||
memcpy(buff2 + left2, p2, len2);
|
||||
}
|
||||
len2 += left2;
|
||||
|
||||
if (len1 > len2)
|
||||
left1 = len1 - len2, left2 = 0, len = len2;
|
||||
else
|
||||
left2 = len2 - len1, left1 = 0, len = len1;
|
||||
|
||||
rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
|
||||
|
||||
if (rc > 0 || (rc == 0 && quit && len1 > len2))
|
||||
if (cmp > 0 || (cmp == 0 && rdlen1 > rdmin))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = quit = 1;
|
||||
swap = 1;
|
||||
}
|
||||
else if (rc == 0 && quit && len1 == len2)
|
||||
else if (cmp == 0 && (rdlen1 == rdlen2))
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
@@ -353,9 +351,39 @@ static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
||||
rrsetidx--;
|
||||
i--;
|
||||
}
|
||||
else if (rc < 0)
|
||||
quit = 1;
|
||||
}
|
||||
else
|
||||
/* Comparing canonicalised RRs, byte-at-a-time. */
|
||||
while (1)
|
||||
{
|
||||
int ok1, ok2;
|
||||
|
||||
ok1 = get_rdata(header, plen, &state1);
|
||||
ok2 = get_rdata(header, plen, &state2);
|
||||
|
||||
if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
break;
|
||||
}
|
||||
else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
break;
|
||||
|
||||
/* arrive here when bytes are equal, go round the loop again
|
||||
and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
|
||||
@@ -498,7 +526,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
struct crec *crecp = NULL;
|
||||
u16 *rr_desc = rrfilter_desc(type);
|
||||
u32 sig_expiration, sig_inception;
|
||||
|
||||
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP | DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
unsigned long curtime = time(0);
|
||||
int time_check = is_check_date(curtime);
|
||||
|
||||
@@ -521,6 +550,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
void *ctx;
|
||||
char *name_start;
|
||||
u32 nsigttl, ttl, orig_ttl;
|
||||
|
||||
failflags &= ~DNSSEC_FAIL_NOSIG;
|
||||
|
||||
p = sigs[j];
|
||||
GETLONG(ttl, p);
|
||||
@@ -538,12 +569,31 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((time_check && !check_date_range(curtime, sig_inception, sig_expiration)) ||
|
||||
labels > name_labels ||
|
||||
!(hash = hash_find(algo_digest_name(algo))) ||
|
||||
if (!time_check)
|
||||
failflags &= ~(DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP);
|
||||
else
|
||||
{
|
||||
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
|
||||
if (serial_compare_32(curtime, sig_inception) == SERIAL_LT)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NYV;
|
||||
|
||||
if (serial_compare_32(curtime, sig_expiration) == SERIAL_GT)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_EXP;
|
||||
}
|
||||
|
||||
if (!(hash = hash_find(algo_digest_name(algo))))
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
if (labels > name_labels ||
|
||||
!hash_init(hash, &ctx, &digest))
|
||||
continue;
|
||||
|
||||
|
||||
/* OK, we have the signature record, see if the relevant DNSKEY is in the cache. */
|
||||
if (!key && !(crecp = cache_find_by_name(NULL, keyname, now, F_DNSKEY)))
|
||||
return STAT_NEED_KEY;
|
||||
@@ -569,15 +619,18 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
wire_len = to_wire(keyname);
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
|
||||
#define RRBUFLEN 128 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
int seg;
|
||||
unsigned char *end, *cp;
|
||||
u16 len, *dp;
|
||||
int j;
|
||||
struct rdata_state state;
|
||||
u16 len;
|
||||
unsigned char rrbuf[RRBUFLEN];
|
||||
|
||||
p = rrset[i];
|
||||
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -586,12 +639,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
{
|
||||
int k;
|
||||
for (k = name_labels - labels; k != 0; k--)
|
||||
for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
while (*name_start != '.' && *name_start != 0)
|
||||
name_start++;
|
||||
if (k != 1 && *name_start == '.')
|
||||
if (j != 1 && *name_start == '.')
|
||||
name_start++;
|
||||
}
|
||||
|
||||
@@ -606,37 +658,74 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char *)name_start);
|
||||
hash->update(ctx, 4, p); /* class and type */
|
||||
hash->update(ctx, 4, (unsigned char *)&nsigttl);
|
||||
|
||||
p += 8; /* skip class, type, ttl */
|
||||
|
||||
p += 8; /* skip type, class, ttl */
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
|
||||
end = p + rdlen;
|
||||
|
||||
/* canonicalise rdata and calculate length of same, use name buffer as workspace.
|
||||
Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
|
||||
cp = p;
|
||||
dp = rr_desc;
|
||||
for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
|
||||
len += end - cp;
|
||||
len = htons(len);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
|
||||
/* Now canonicalise again and digest. */
|
||||
cp = p;
|
||||
dp = rr_desc;
|
||||
while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
|
||||
hash->update(ctx, seg, (unsigned char *)name);
|
||||
if (cp != end)
|
||||
hash->update(ctx, end - cp, cp);
|
||||
|
||||
/* Optimisation for RR types which need no cannonicalisation.
|
||||
This includes DNSKEY DS NSEC and NSEC3, which are also long, so
|
||||
it saves lots of calls to get_rdata, and avoids the pessimal
|
||||
segmented insertion, even with a small rrbuf[].
|
||||
|
||||
If canonicalisation is not needed, a simple insertion into the hash works.
|
||||
*/
|
||||
if (*rr_desc == (u16)-1)
|
||||
{
|
||||
len = htons(rdlen);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
hash->update(ctx, rdlen, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* canonicalise rdata and calculate length of same, use
|
||||
name buffer as workspace for get_rdata. */
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
state.buff = name;
|
||||
state.end = p + rdlen;
|
||||
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
if (j < RRBUFLEN)
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
len = htons((u16)j);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
|
||||
/* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
go back to the start and do it in chunks. */
|
||||
if (j >= RRBUFLEN)
|
||||
{
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
{
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
if (j == RRBUFLEN - 1)
|
||||
{
|
||||
hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
j = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (j != 0)
|
||||
hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
|
||||
/* namebuff used for workspace above, restore to leave unchanged on exit */
|
||||
p = (unsigned char*)(rrset[0]);
|
||||
extract_name(header, plen, &p, name, 1, 0);
|
||||
if (!extract_name(header, plen, &p, name, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (key)
|
||||
{
|
||||
@@ -656,7 +745,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_BOGUS;
|
||||
/* If we reach this point, no verifying key was found */
|
||||
return STAT_BOGUS | failflags | DNSSEC_FAIL_NOKEY;
|
||||
}
|
||||
|
||||
|
||||
@@ -677,17 +767,18 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
unsigned long ttl, sig_ttl;
|
||||
struct blockdata *key;
|
||||
union all_addr a;
|
||||
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NODSSUP | DNSSEC_FAIL_NOZONE | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
|
||||
!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
/* See if we have cached a DS record which validates this key */
|
||||
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
|
||||
@@ -721,14 +812,17 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
GETSHORT(flags, p);
|
||||
if (*p++ != 3)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
algo = *p++;
|
||||
keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
|
||||
key = NULL;
|
||||
|
||||
/* key must have zone key flag set */
|
||||
if (flags & 0x100)
|
||||
key = blockdata_alloc((char*)p, rdlen - 4);
|
||||
{
|
||||
key = blockdata_alloc((char*)p, rdlen - 4);
|
||||
failflags &= ~DNSSEC_FAIL_NOZONE;
|
||||
}
|
||||
|
||||
p = psave;
|
||||
|
||||
@@ -749,15 +843,23 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
unsigned char *digest, *ds_digest;
|
||||
const struct nettle_hash *hash;
|
||||
int sigcnt, rrcnt;
|
||||
|
||||
int wire_len;
|
||||
|
||||
if (recp1->addr.ds.algo == algo &&
|
||||
recp1->addr.ds.keytag == keytag &&
|
||||
recp1->uid == (unsigned int)class &&
|
||||
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
|
||||
hash_init(hash, &ctx, &digest))
|
||||
|
||||
recp1->uid == (unsigned int)class)
|
||||
{
|
||||
int wire_len = to_wire(name);
|
||||
failflags &= ~DNSSEC_FAIL_NOKEY;
|
||||
|
||||
if (!(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))))
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NODSSUP;
|
||||
|
||||
if (!hash_init(hash, &ctx, &digest))
|
||||
continue;
|
||||
|
||||
wire_len = to_wire(name);
|
||||
|
||||
/* Note that digest may be different between DSs, so
|
||||
we can't move this outside the loop. */
|
||||
@@ -772,12 +874,23 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
(ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
|
||||
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
||||
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
||||
sigcnt != 0 && rrcnt != 0 &&
|
||||
validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl) == STAT_SECURE)
|
||||
rrcnt != 0)
|
||||
{
|
||||
valid = 1;
|
||||
break;
|
||||
if (sigcnt == 0)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NOSIG;
|
||||
|
||||
rc = validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl);
|
||||
|
||||
failflags &= rc;
|
||||
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,9 +955,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
a.log.keytag = keytag;
|
||||
a.log.algo = algo;
|
||||
if (algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -861,8 +974,8 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return STAT_OK;
|
||||
}
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
|
||||
return STAT_BOGUS;
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY", 0);
|
||||
return STAT_BOGUS | failflags;
|
||||
}
|
||||
|
||||
/* The DNS packet is expected to contain the answer to a DS query
|
||||
@@ -897,26 +1010,29 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
rc = STAT_BOGUS;
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
|
||||
p += 4; /* qtype, qclass */
|
||||
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS", 0);
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (rc != STAT_SECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
return rc;
|
||||
|
||||
if (!neganswer)
|
||||
@@ -968,9 +1084,9 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.log.algo = algo;
|
||||
a.log.digest = digest;
|
||||
if (ds_digest_name(digest) && algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu", 0);
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1003,7 +1119,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
|
||||
cache_end_insert();
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "no DS");
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no DS/cut" : "no DS", 0);
|
||||
}
|
||||
|
||||
return STAT_OK;
|
||||
@@ -1382,7 +1498,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
algo = *p++;
|
||||
|
||||
if ((hash = hash_find(nsec3_digest_name(algo))))
|
||||
@@ -1780,7 +1896,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
/* Find all the targets we're looking for answers to.
|
||||
The zeroth array element is for the query, subsequent ones
|
||||
for CNAME targets, unless the query is for a CNAME. */
|
||||
for CNAME targets, unless the query is for a CNAME or ANY. */
|
||||
|
||||
if (!expand_workspace(&targets, &target_sz, 0))
|
||||
return STAT_BOGUS;
|
||||
@@ -1799,7 +1915,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (qtype == T_RRSIG)
|
||||
return STAT_INSECURE;
|
||||
|
||||
if (qtype != T_CNAME)
|
||||
if (qtype != T_CNAME && qtype != T_ANY)
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
{
|
||||
if (!(p1 = skip_name(p1, header, plen, 10)))
|
||||
@@ -1885,15 +2001,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (check_unsigned && i < ntohs(header->ancount))
|
||||
{
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (rc != STAT_INSECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -1904,7 +2020,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
@@ -1912,13 +2028,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (rc == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
unsigned long sig_ttl;
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
@@ -1951,21 +2067,21 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD &&
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE_WILDCARD) &&
|
||||
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
|
||||
|
||||
rc = STAT_SECURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
if (secure == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(secure, STAT_SECURE))
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
@@ -1983,16 +2099,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
|
||||
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
if (STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC; /* signed zone, no NSECs */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2056,35 +2172,31 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
int errflags_to_ede(int status)
|
||||
{
|
||||
int q;
|
||||
unsigned int len;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
const struct nettle_hash *hash;
|
||||
void *ctx;
|
||||
unsigned char *digest;
|
||||
|
||||
if (!(hash = hash_find("sha1")) || !hash_init(hash, &ctx, &digest))
|
||||
return NULL;
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
break; /* bad packet */
|
||||
|
||||
len = to_wire(name);
|
||||
hash->update(ctx, len, (unsigned char *)name);
|
||||
/* CRC the class and type as well */
|
||||
hash->update(ctx, 4, p);
|
||||
/* We can end up with more than one flag set for some errors,
|
||||
so this encodes a rough priority so the (eg) No sig is reported
|
||||
before no-unexpired-sig. */
|
||||
|
||||
p += 4;
|
||||
if (!CHECK_LEN(header, p, plen, 0))
|
||||
break; /* bad packet */
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
return digest;
|
||||
if (status & DNSSEC_FAIL_NYV)
|
||||
return EDE_SIG_NYV;
|
||||
else if (status & DNSSEC_FAIL_EXP)
|
||||
return EDE_SIG_EXP;
|
||||
else if (status & DNSSEC_FAIL_NOKEYSUP)
|
||||
return EDE_USUPDNSKEY;
|
||||
else if (status & DNSSEC_FAIL_NOZONE)
|
||||
return EDE_NO_ZONEKEY;
|
||||
else if (status & DNSSEC_FAIL_NOKEY)
|
||||
return EDE_NO_DNSKEY;
|
||||
else if (status & DNSSEC_FAIL_NODSSUP)
|
||||
return EDE_USUPDS;
|
||||
else if (status & DNSSEC_FAIL_NONSEC)
|
||||
return EDE_NO_NSEC;
|
||||
else if (status & DNSSEC_FAIL_INDET)
|
||||
return EDE_DNSSEC_IND;
|
||||
else if (status & DNSSEC_FAIL_NOSIG)
|
||||
return EDE_NO_RRSIG;
|
||||
else
|
||||
return EDE_UNSET;
|
||||
}
|
||||
|
||||
#endif /* HAVE_DNSSEC */
|
||||
@@ -0,0 +1,707 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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 int order(char *qdomain, size_t qlen, struct server *serv);
|
||||
static int order_qsort(const void *a, const void *b);
|
||||
static int order_servers(struct server *s, struct server *s2);
|
||||
|
||||
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
|
||||
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
|
||||
|
||||
void build_server_array(void)
|
||||
{
|
||||
struct server *serv;
|
||||
int count = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
{
|
||||
count++;
|
||||
if (serv->flags & SERV_WILDCARD)
|
||||
daemon->server_has_wildcard = 1;
|
||||
}
|
||||
|
||||
daemon->serverarraysz = count;
|
||||
|
||||
if (count > daemon->serverarrayhwm)
|
||||
{
|
||||
struct server **new;
|
||||
|
||||
count += 10; /* A few extra without re-allocating. */
|
||||
|
||||
if ((new = whine_malloc(count * sizeof(struct server *))))
|
||||
{
|
||||
if (daemon->serverarray)
|
||||
free(daemon->serverarray);
|
||||
|
||||
daemon->serverarray = new;
|
||||
daemon->serverarrayhwm = count;
|
||||
}
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
#ifdef HAVE_LOOP
|
||||
if (!(serv->flags & SERV_LOOP))
|
||||
#endif
|
||||
{
|
||||
daemon->serverarray[count] = serv;
|
||||
serv->serial = count;
|
||||
serv->last_server = -1;
|
||||
count++;
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
|
||||
daemon->serverarray[count] = serv;
|
||||
|
||||
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
|
||||
|
||||
/* servers need the location in the array to find all the whole
|
||||
set of equivalent servers from a pointer to a single one. */
|
||||
for (count = 0; count < daemon->serverarraysz; count++)
|
||||
if (!(daemon->serverarray[count]->flags & SERV_IS_LOCAL))
|
||||
daemon->serverarray[count]->arrayposn = count;
|
||||
}
|
||||
|
||||
/* we're looking for the server whose domain is the longest exact match
|
||||
to the RH end of qdomain, or a local address if the flags match.
|
||||
Add '.' to the LHS of the query string so
|
||||
server=/.example.com/ works.
|
||||
|
||||
A flag of F_SERVER returns an upstream server only.
|
||||
A flag of F_DNSSECOK returns a DNSSEC capable server only and
|
||||
also disables NODOTS servers from consideration.
|
||||
A flag of F_DOMAINSRV returns a domain-specific server only.
|
||||
A flag of F_CONFIG returns anything that generates a local
|
||||
reply of IPv4 or IPV6.
|
||||
return 0 if nothing found, 1 otherwise.
|
||||
*/
|
||||
int lookup_domain(char *domain, int flags, int *lowout, int *highout)
|
||||
{
|
||||
int rc, crop_query, nodots;
|
||||
ssize_t qlen;
|
||||
int try, high, low = 0;
|
||||
int nlow = 0, nhigh = 0;
|
||||
char *cp, *qdomain = domain;
|
||||
|
||||
/* may be no configured servers. */
|
||||
if (daemon->serverarraysz == 0)
|
||||
return 0;
|
||||
|
||||
/* find query length and presence of '.' */
|
||||
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
|
||||
if (*cp == '.')
|
||||
nodots = 0;
|
||||
|
||||
/* Handle empty name, and searches for DNSSEC queries without
|
||||
diverting to NODOTS servers. */
|
||||
if (qlen == 0 || flags & F_DNSSECOK)
|
||||
nodots = 0;
|
||||
|
||||
/* Search shorter and shorter RHS substrings for a match */
|
||||
while (qlen >= 0)
|
||||
{
|
||||
/* Note that when we chop off a label, all the possible matches
|
||||
MUST be at a larger index than the nearest failing match with one more
|
||||
character, since the array is sorted longest to smallest. Hence
|
||||
we don't reset low to zero here, we can go further below and crop the
|
||||
search string to the size of the largest remaining server
|
||||
when this match fails. */
|
||||
high = daemon->serverarraysz;
|
||||
crop_query = 1;
|
||||
|
||||
/* binary search */
|
||||
while (1)
|
||||
{
|
||||
try = (low + high)/2;
|
||||
|
||||
if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
|
||||
break;
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
if (high == try)
|
||||
{
|
||||
/* qdomain is longer or same length as longest domain, and try == 0
|
||||
crop the query to the longest domain. */
|
||||
crop_query = qlen - daemon->serverarray[try]->domain_len;
|
||||
break;
|
||||
}
|
||||
high = try;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (low == try)
|
||||
{
|
||||
/* try now points to the last domain that sorts before the query, so
|
||||
we know that a substring of the query shorter than it is required to match, so
|
||||
find the largest domain that's shorter than try. Note that just going to
|
||||
try+1 is not optimal, consider searching bbb in (aaa,ccc,bb). try will point
|
||||
to aaa, since ccc sorts after bbb, but the first domain that has a chance to
|
||||
match is bb. So find the length of the first domain later than try which is
|
||||
is shorter than it.
|
||||
There's a nasty edge case when qdomain sorts before _any_ of the
|
||||
server domains, where try _doesn't point_ to the last domain that sorts
|
||||
before the query, since no such domain exists. In that case, the loop
|
||||
exits via the rc < 0 && high == try path above and this code is
|
||||
not executed. */
|
||||
ssize_t len, old = daemon->serverarray[try]->domain_len;
|
||||
while (++try != daemon->serverarraysz)
|
||||
{
|
||||
if (old != (len = daemon->serverarray[try]->domain_len))
|
||||
{
|
||||
crop_query = qlen - len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
low = try;
|
||||
}
|
||||
};
|
||||
|
||||
if (rc == 0)
|
||||
{
|
||||
int found = 1;
|
||||
|
||||
if (daemon->server_has_wildcard)
|
||||
{
|
||||
/* if we have example.com and *example.com we need to check against *example.com,
|
||||
but the binary search may have found either. Use the fact that example.com is sorted before *example.com
|
||||
We favour example.com in the case that both match (ie www.example.com) */
|
||||
while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
|
||||
try--;
|
||||
|
||||
if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
|
||||
{
|
||||
while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
|
||||
try++;
|
||||
|
||||
if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (found && filter_servers(try, flags, &nlow, &nhigh))
|
||||
/* We have a match, but it may only be (say) an IPv6 address, and
|
||||
if the query wasn't for an AAAA record, it's no good, and we need
|
||||
to continue generalising */
|
||||
{
|
||||
/* We've matched a setting which says to use servers without a domain.
|
||||
Continue the search with empty query */
|
||||
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
|
||||
crop_query = qlen;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* crop_query must be at least one always. */
|
||||
if (crop_query == 0)
|
||||
crop_query = 1;
|
||||
|
||||
/* strip chars off the query based on the largest possible remaining match,
|
||||
then continue to the start of the next label unless we have a wildcard
|
||||
domain somewhere, in which case we have to go one at a time. */
|
||||
qlen -= crop_query;
|
||||
qdomain += crop_query;
|
||||
if (!daemon->server_has_wildcard)
|
||||
while (qlen > 0 && (*(qdomain-1) != '.'))
|
||||
qlen--, qdomain++;
|
||||
}
|
||||
|
||||
/* domain has no dots, and we have at least one server configured to handle such,
|
||||
These servers always sort to the very end of the array.
|
||||
A configured server eg server=/lan/ will take precdence. */
|
||||
if (nodots &&
|
||||
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
|
||||
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
|
||||
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
|
||||
|
||||
if (lowout)
|
||||
*lowout = nlow;
|
||||
|
||||
if (highout)
|
||||
*highout = nhigh;
|
||||
|
||||
if (nlow == nhigh)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return first server in group of equivalent servers; this is the "master" record. */
|
||||
int server_samegroup(struct server *a, struct server *b)
|
||||
{
|
||||
return order_servers(a, b) == 0;
|
||||
}
|
||||
|
||||
int filter_servers(int seed, int flags, int *lowout, int *highout)
|
||||
{
|
||||
int nlow = seed, nhigh = seed;
|
||||
int i;
|
||||
|
||||
/* expand nlow and nhigh to cover all the records with the same domain
|
||||
nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
|
||||
which can happen below. */
|
||||
while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
|
||||
nlow--;
|
||||
|
||||
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
|
||||
nhigh++;
|
||||
|
||||
nhigh++;
|
||||
|
||||
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
|
||||
|
||||
if (flags & F_CONFIG)
|
||||
{
|
||||
/* We're just lookin for any matches that return an RR. */
|
||||
for (i = nlow; i < nhigh; i++)
|
||||
if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
|
||||
break;
|
||||
|
||||
/* failed, return failure. */
|
||||
if (i == nhigh)
|
||||
nhigh = nlow;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now the servers are on order between low and high, in the order
|
||||
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
|
||||
|
||||
See which of those match our query in that priority order and narrow (low, high) */
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
|
||||
|
||||
if (i != nlow && (flags & F_IPV6))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
|
||||
|
||||
if (i != nlow && (flags & F_IPV4))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
|
||||
|
||||
if (i != nlow && (flags & (F_IPV4 | F_IPV6)))
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
nlow = i;
|
||||
|
||||
/* Short to resolv.conf servers */
|
||||
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
|
||||
|
||||
if (i != nlow)
|
||||
nhigh = i;
|
||||
else
|
||||
{
|
||||
/* now look for a server */
|
||||
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
|
||||
|
||||
if (i != nlow)
|
||||
{
|
||||
/* If we want a server that can do DNSSEC, and this one can't,
|
||||
return nothing, similarly if were looking only for a server
|
||||
for a particular domain. */
|
||||
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
|
||||
nlow = nhigh;
|
||||
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
|
||||
nlow = nhigh;
|
||||
else
|
||||
nhigh = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* --local=/domain/, only return if we don't need a server. */
|
||||
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
|
||||
nhigh = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*lowout = nlow;
|
||||
*highout = nhigh;
|
||||
|
||||
return (nlow != nhigh);
|
||||
}
|
||||
|
||||
int is_local_answer(time_t now, int first, char *name)
|
||||
{
|
||||
int flags = 0;
|
||||
int rc = 0;
|
||||
|
||||
if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (flags & SERV_4ADDR)
|
||||
rc = F_IPV4;
|
||||
else if (flags & SERV_6ADDR)
|
||||
rc = F_IPV6;
|
||||
else if (flags & SERV_ALL_ZEROS)
|
||||
rc = F_IPV4 | F_IPV6;
|
||||
else
|
||||
{
|
||||
/* argument first is the first struct server which matches the query type;
|
||||
now roll back to the server which is just the same domain, to check if that
|
||||
provides an answer of a different type. */
|
||||
|
||||
for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
|
||||
|
||||
if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
|
||||
check_for_local_domain(name, now))
|
||||
rc = F_NOERR;
|
||||
else
|
||||
rc = F_NXDOMAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
|
||||
{
|
||||
int trunc = 0, anscount = 0;
|
||||
unsigned char *p;
|
||||
int start;
|
||||
union all_addr addr;
|
||||
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
|
||||
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
if (!(p = skip_questions(header, size)))
|
||||
return 0;
|
||||
|
||||
if (flags & gotname & F_IPV4)
|
||||
for (start = first; start != last; start++)
|
||||
{
|
||||
struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
|
||||
|
||||
if (srv->flags & SERV_ALL_ZEROS)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
else
|
||||
addr.addr4 = srv->addr;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (flags & gotname & F_IPV6)
|
||||
for (start = first; start != last; start++)
|
||||
{
|
||||
struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
|
||||
|
||||
if (srv->flags & SERV_ALL_ZEROS)
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
else
|
||||
addr.addr6 = srv->addr;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
|
||||
anscount++;
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
|
||||
}
|
||||
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
header->ancount = htons(anscount);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
|
||||
{
|
||||
int first, last, index;
|
||||
|
||||
/* Find server to send DNSSEC query to. This will normally be the
|
||||
same as for the original query, but may be another if
|
||||
servers for domains are involved. */
|
||||
if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
|
||||
return -1;
|
||||
|
||||
for (index = first; index != last; index++)
|
||||
if (daemon->serverarray[index] == server)
|
||||
break;
|
||||
|
||||
/* No match to server used for original query.
|
||||
Use newly looked up set. */
|
||||
if (index == last)
|
||||
index = daemon->serverarray[first]->last_server == -1 ?
|
||||
first : daemon->serverarray[first]->last_server;
|
||||
|
||||
if (firstp)
|
||||
*firstp = first;
|
||||
|
||||
if (lastp)
|
||||
*lastp = last;
|
||||
|
||||
return index;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* order by size, then by dictionary order */
|
||||
static int order(char *qdomain, size_t qlen, struct server *serv)
|
||||
{
|
||||
size_t dlen = 0;
|
||||
|
||||
/* servers for dotless names always sort last
|
||||
searched for name is never dotless. */
|
||||
if (serv->flags & SERV_FOR_NODOTS)
|
||||
return -1;
|
||||
|
||||
dlen = serv->domain_len;
|
||||
|
||||
if (qlen < dlen)
|
||||
return 1;
|
||||
|
||||
if (qlen > dlen)
|
||||
return -1;
|
||||
|
||||
return strcmp(qdomain, serv->domain);
|
||||
}
|
||||
|
||||
static int order_servers(struct server *s1, struct server *s2)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* need full comparison of dotless servers in
|
||||
order_qsort() and filter_servers() */
|
||||
|
||||
if (s1->flags & SERV_FOR_NODOTS)
|
||||
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
|
||||
|
||||
if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
|
||||
return rc;
|
||||
|
||||
/* For identical domains, sort wildcard ones first */
|
||||
if (s1->flags & SERV_WILDCARD)
|
||||
return (s2->flags & SERV_WILDCARD) ? 0 : 1;
|
||||
|
||||
return (s2->flags & SERV_WILDCARD) ? -1 : 0;
|
||||
}
|
||||
|
||||
static int order_qsort(const void *a, const void *b)
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct server *s1 = *((struct server **)a);
|
||||
struct server *s2 = *((struct server **)b);
|
||||
|
||||
rc = order_servers(s1, s2);
|
||||
|
||||
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
|
||||
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
|
||||
so the order is IPv6 literal, IPv4 literal, all-zero literal,
|
||||
unqualified servers, upstream server, NXDOMAIN literal. */
|
||||
if (rc == 0)
|
||||
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
|
||||
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
|
||||
|
||||
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
|
||||
if (rc == 0)
|
||||
if (!(s1->flags & SERV_LITERAL_ADDRESS))
|
||||
rc = s1->serial - s2->serial;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mark_servers(int flag)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* mark everything with argument flag */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
for (serv = daemon->local_domains; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
else
|
||||
serv->flags &= ~SERV_MARK;
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
{
|
||||
up = &serv->next;
|
||||
daemon->servers_tail = serv;
|
||||
}
|
||||
}
|
||||
|
||||
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
*up = serv->next;
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
int add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain,
|
||||
union all_addr *local_addr)
|
||||
{
|
||||
struct server *serv = NULL;
|
||||
char *alloc_domain;
|
||||
|
||||
if (!domain)
|
||||
domain = "";
|
||||
|
||||
/* .domain == domain, for historical reasons. */
|
||||
if (*domain == '.')
|
||||
while (*domain == '.') domain++;
|
||||
else if (*domain == '*')
|
||||
{
|
||||
domain++;
|
||||
if (*domain != 0)
|
||||
flags |= SERV_WILDCARD;
|
||||
}
|
||||
|
||||
if (*domain == 0)
|
||||
alloc_domain = whine_malloc(1);
|
||||
else
|
||||
alloc_domain = canonicalise((char *)domain, NULL);
|
||||
|
||||
if (!alloc_domain)
|
||||
return 0;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark
|
||||
only do this for forwarding servers, not
|
||||
address or local, to avoid delays on large numbers. */
|
||||
if (!(flags & SERV_IS_LOCAL))
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_MARK) &&
|
||||
hostname_isequal(alloc_domain, serv->domain))
|
||||
break;
|
||||
|
||||
if (serv)
|
||||
{
|
||||
free(alloc_domain);
|
||||
alloc_domain = serv->domain;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size;
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
if (flags & SERV_6ADDR)
|
||||
size = sizeof(struct serv_addr6);
|
||||
else if (flags & SERV_4ADDR)
|
||||
size = sizeof(struct serv_addr4);
|
||||
else
|
||||
size = sizeof(struct serv_local);
|
||||
}
|
||||
else
|
||||
size = sizeof(struct server);
|
||||
|
||||
if (!(serv = whine_malloc(size)))
|
||||
{
|
||||
free(alloc_domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & SERV_IS_LOCAL)
|
||||
{
|
||||
serv->next = daemon->local_domains;
|
||||
daemon->local_domains = serv;
|
||||
|
||||
if (flags & SERV_4ADDR)
|
||||
((struct serv_addr4*)serv)->addr = local_addr->addr4;
|
||||
|
||||
if (flags & SERV_6ADDR)
|
||||
((struct serv_addr6*)serv)->addr = local_addr->addr6;
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
/* Add to the end of the chain, for order */
|
||||
if (daemon->servers_tail)
|
||||
daemon->servers_tail->next = serv;
|
||||
else
|
||||
daemon->servers = serv;
|
||||
daemon->servers_tail = serv;
|
||||
|
||||
#ifdef HAVE_LOOP
|
||||
serv->uid = rand32();
|
||||
#endif
|
||||
|
||||
if (interface)
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
|
||||
serv->flags = flags;
|
||||
serv->domain = alloc_domain;
|
||||
serv->domain_len = strlen(alloc_domain);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
+37
-33
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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,8 +18,9 @@
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c);
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
|
||||
int is_name_synthetic(int flags, char *name, union all_addr *addr)
|
||||
{
|
||||
@@ -135,28 +136,9 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr)
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
|
||||
}
|
||||
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
@@ -246,14 +228,22 @@ int is_rev_synth(int flag, union all_addr *addr, char *name)
|
||||
}
|
||||
|
||||
|
||||
static int match_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return 1;
|
||||
|
||||
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))
|
||||
if (match_domain(addr, c))
|
||||
return c;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -267,16 +257,30 @@ char *get_domain(struct in_addr addr)
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
if (c->is6)
|
||||
{
|
||||
if (c->prefixlen >= 64)
|
||||
{
|
||||
if (is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return 1;
|
||||
}
|
||||
else if (is_same_net6(addr, &c->start6, c->prefixlen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
if (match_domain6(addr, c))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+111
-29
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -264,7 +264,8 @@ static void encoder(unsigned char *in, char *out)
|
||||
out[3] = char64(in[2]);
|
||||
}
|
||||
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen, replace = 2; /* can't get mac address, just delete any incoming. */
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
@@ -273,6 +274,7 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
|
||||
{
|
||||
replace = 1;
|
||||
*cacheablep = 0;
|
||||
|
||||
if (option_bool(OPT_MAC_HEX))
|
||||
print_mac(encode, mac, maclen);
|
||||
@@ -288,14 +290,18 @@ static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned ch
|
||||
}
|
||||
|
||||
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *l3, time_t now)
|
||||
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *l3, time_t now, int *cacheablep)
|
||||
{
|
||||
int maclen;
|
||||
unsigned char mac[DHCP_CHADDR_MAX];
|
||||
|
||||
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
|
||||
{
|
||||
*cacheablep = 0;
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 0);
|
||||
}
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
@@ -313,17 +319,18 @@ static void *get_addrp(union mysockaddr *addr, const short family)
|
||||
return &addr->in.sin_addr;
|
||||
}
|
||||
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
void *addrp = NULL;
|
||||
int sa_family = source->sa.sa_family;
|
||||
|
||||
int cacheable = 0;
|
||||
|
||||
opt->source_netmask = 0;
|
||||
opt->scope_netmask = 0;
|
||||
|
||||
|
||||
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
|
||||
{
|
||||
opt->source_netmask = daemon->add_subnet6->mask;
|
||||
@@ -331,6 +338,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet6->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
|
||||
cacheable = 1;
|
||||
}
|
||||
else
|
||||
addrp = &source->in6.sin6_addr;
|
||||
@@ -343,6 +351,7 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
{
|
||||
sa_family = daemon->add_subnet4->addr.sa.sa_family;
|
||||
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
|
||||
cacheable = 1; /* Address is constant */
|
||||
}
|
||||
else
|
||||
addrp = &source->in.sin_addr;
|
||||
@@ -350,8 +359,6 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
|
||||
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
|
||||
|
||||
len = 0;
|
||||
|
||||
if (addrp && opt->source_netmask != 0)
|
||||
{
|
||||
len = ((opt->source_netmask - 1) >> 3) + 1;
|
||||
@@ -359,18 +366,26 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source)
|
||||
if (opt->source_netmask & 7)
|
||||
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
|
||||
}
|
||||
else
|
||||
{
|
||||
cacheable = 1; /* No address ever supplied. */
|
||||
len = 0;
|
||||
}
|
||||
|
||||
if (cacheablep)
|
||||
*cacheablep = cacheable;
|
||||
|
||||
return len + 4;
|
||||
}
|
||||
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source)
|
||||
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
|
||||
|
||||
int len;
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
len = calc_subnet_opt(&opt, source, cacheable);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
|
||||
}
|
||||
|
||||
@@ -383,18 +398,18 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
unsigned char *p;
|
||||
int code, i, rdlen;
|
||||
|
||||
calc_len = calc_subnet_opt(&opt, peer);
|
||||
calc_len = calc_subnet_opt(&opt, peer, NULL);
|
||||
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
if (!(p = skip_name(pseudoheader, header, plen, 10)))
|
||||
return 1;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return 1; /* bad packet */
|
||||
|
||||
/* check if option there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
@@ -412,24 +427,91 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
|
||||
* detailed information on packet formating.
|
||||
*/
|
||||
#define UMBRELLA_VERSION 1
|
||||
#define UMBRELLA_TYPESZ 2
|
||||
|
||||
#define UMBRELLA_ASSET 0x0004
|
||||
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
|
||||
#define UMBRELLA_ORG 0x0008
|
||||
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
|
||||
#define UMBRELLA_IPV4 0x0010
|
||||
#define UMBRELLA_IPV6 0x0020
|
||||
#define UMBRELLA_DEVICE 0x0040
|
||||
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
|
||||
|
||||
struct umbrella_opt {
|
||||
u8 magic[4];
|
||||
u8 version;
|
||||
u8 flags;
|
||||
/* We have 4 possible fields since we'll never send both IPv4 and
|
||||
* IPv6, so using the larger of the two to calculate max buffer size.
|
||||
* Each field also has a type header. So the following accounts for
|
||||
* the type headers and each field size to get a max buffer size.
|
||||
*/
|
||||
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
|
||||
};
|
||||
|
||||
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
|
||||
{
|
||||
*cacheable = 0;
|
||||
|
||||
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
|
||||
u8 *u = &opt.fields[0];
|
||||
|
||||
if (daemon->umbrella_org) {
|
||||
PUTSHORT(UMBRELLA_ORG, u);
|
||||
PUTLONG(daemon->umbrella_org, u);
|
||||
}
|
||||
|
||||
int family = source->sa.sa_family;
|
||||
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
|
||||
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
|
||||
memcpy(u, get_addrp(source, family), size);
|
||||
u += size;
|
||||
|
||||
if (option_bool(OPT_UMBRELLA_DEVID)) {
|
||||
PUTSHORT(UMBRELLA_DEVICE, u);
|
||||
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
|
||||
u += UMBRELLA_DEVICESZ;
|
||||
}
|
||||
|
||||
if (daemon->umbrella_asset) {
|
||||
PUTSHORT(UMBRELLA_ASSET, u);
|
||||
PUTLONG(daemon->umbrella_asset, u);
|
||||
}
|
||||
|
||||
int len = u - &opt.magic[0];
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
|
||||
}
|
||||
|
||||
/* Set *check_subnet if we add a client subnet option, which needs to checked
|
||||
in the reply. Set *cacheable to zero if we add an option which the answer
|
||||
may depend on. */
|
||||
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
union mysockaddr *source, time_t now, int *check_subnet)
|
||||
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable)
|
||||
{
|
||||
*check_subnet = 0;
|
||||
|
||||
*cacheable = 1;
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, limit, source, now);
|
||||
plen = add_mac(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
|
||||
plen = add_dns_client(header, plen, limit, source, now);
|
||||
|
||||
plen = add_dns_client(header, plen, limit, source, now, cacheable);
|
||||
|
||||
if (daemon->dns_client_id)
|
||||
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
|
||||
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
|
||||
|
||||
if (option_bool(OPT_UMBRELLA))
|
||||
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
|
||||
|
||||
if (option_bool(OPT_CLIENT_SUBNET))
|
||||
{
|
||||
plen = add_source_addr(header, plen, limit, source);
|
||||
plen = add_source_addr(header, plen, limit, source, cacheable);
|
||||
*check_subnet = 1;
|
||||
}
|
||||
|
||||
|
||||
+1560
-1366
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,284 @@
|
||||
/* Copyright (c) 2012-2020 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/>.
|
||||
*/
|
||||
|
||||
|
||||
/* Hash the question section. This is used to safely detect query
|
||||
retransmission and to detect answers to questions we didn't ask, which
|
||||
might be poisoning attacks. Note that we decode the name rather
|
||||
than CRC the raw bytes, since replies might be compressed differently.
|
||||
We ignore case in the names for the same reason.
|
||||
|
||||
The hash used is SHA-256. If we're building with DNSSEC support,
|
||||
we use the Nettle cypto library. If not, we prefer not to
|
||||
add a dependency on Nettle, and use a stand-alone implementaion.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
|
||||
|
||||
static const struct nettle_hash *hash;
|
||||
static void *ctx;
|
||||
static unsigned char *digest;
|
||||
|
||||
void hash_questions_init(void)
|
||||
{
|
||||
if (!(hash = hash_find("sha256")))
|
||||
die(_("Failed to create SHA-256 hash object"), NULL, EC_MISC);
|
||||
|
||||
ctx = safe_malloc(hash->context_size);
|
||||
digest = safe_malloc(hash->digest_size);
|
||||
}
|
||||
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
char *cp, c;
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
break; /* bad packet */
|
||||
|
||||
for (cp = name; (c = *cp); cp++)
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
*cp += 'a' - 'A';
|
||||
|
||||
hash->update(ctx, cp - name, (unsigned char *)name);
|
||||
/* CRC the class and type as well */
|
||||
hash->update(ctx, 4, p);
|
||||
|
||||
p += 4;
|
||||
if (!CHECK_LEN(header, p, plen, 0))
|
||||
break; /* bad packet */
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
return digest;
|
||||
}
|
||||
|
||||
#else /* HAVE_DNSSEC || HAVE_CRYPTOHASH */
|
||||
|
||||
#define SHA256_BLOCK_SIZE 32 /* SHA256 outputs a 32 byte digest */
|
||||
typedef unsigned char BYTE; /* 8-bit byte */
|
||||
typedef unsigned int WORD; /* 32-bit word, change to "long" for 16-bit machines */
|
||||
|
||||
typedef struct {
|
||||
BYTE data[64];
|
||||
WORD datalen;
|
||||
unsigned long long bitlen;
|
||||
WORD state[8];
|
||||
} SHA256_CTX;
|
||||
|
||||
static void sha256_init(SHA256_CTX *ctx);
|
||||
static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len);
|
||||
static void sha256_final(SHA256_CTX *ctx, BYTE hash[]);
|
||||
|
||||
void hash_questions_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
SHA256_CTX ctx;
|
||||
static BYTE digest[SHA256_BLOCK_SIZE];
|
||||
|
||||
sha256_init(&ctx);
|
||||
|
||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
||||
{
|
||||
char *cp, c;
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 4))
|
||||
break; /* bad packet */
|
||||
|
||||
for (cp = name; (c = *cp); cp++)
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
*cp += 'a' - 'A';
|
||||
|
||||
sha256_update(&ctx, (BYTE *)name, cp - name);
|
||||
/* CRC the class and type as well */
|
||||
sha256_update(&ctx, (BYTE *)p, 4);
|
||||
|
||||
p += 4;
|
||||
if (!CHECK_LEN(header, p, plen, 0))
|
||||
break; /* bad packet */
|
||||
}
|
||||
|
||||
sha256_final(&ctx, digest);
|
||||
return (unsigned char *)digest;
|
||||
}
|
||||
|
||||
/* Code from here onwards comes from https://github.com/B-Con/crypto-algorithms
|
||||
and was written by Brad Conte (brad@bradconte.com), to whom all credit is given.
|
||||
|
||||
This code is in the public domain, and the copyright notice at the head of this
|
||||
file does not apply to it.
|
||||
*/
|
||||
|
||||
|
||||
/****************************** MACROS ******************************/
|
||||
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
|
||||
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
|
||||
|
||||
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
|
||||
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||||
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
|
||||
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
|
||||
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
|
||||
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
|
||||
|
||||
/**************************** VARIABLES *****************************/
|
||||
static const WORD k[64] = {
|
||||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
};
|
||||
|
||||
/*********************** FUNCTION DEFINITIONS ***********************/
|
||||
static void sha256_transform(SHA256_CTX *ctx, const BYTE data[])
|
||||
{
|
||||
WORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
|
||||
|
||||
for (i = 0, j = 0; i < 16; ++i, j += 4)
|
||||
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
|
||||
for ( ; i < 64; ++i)
|
||||
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
|
||||
|
||||
a = ctx->state[0];
|
||||
b = ctx->state[1];
|
||||
c = ctx->state[2];
|
||||
d = ctx->state[3];
|
||||
e = ctx->state[4];
|
||||
f = ctx->state[5];
|
||||
g = ctx->state[6];
|
||||
h = ctx->state[7];
|
||||
|
||||
for (i = 0; i < 64; ++i)
|
||||
{
|
||||
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
|
||||
t2 = EP0(a) + MAJ(a,b,c);
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = d + t1;
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
ctx->state[0] += a;
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += c;
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
ctx->state[5] += f;
|
||||
ctx->state[6] += g;
|
||||
ctx->state[7] += h;
|
||||
}
|
||||
|
||||
static void sha256_init(SHA256_CTX *ctx)
|
||||
{
|
||||
ctx->datalen = 0;
|
||||
ctx->bitlen = 0;
|
||||
ctx->state[0] = 0x6a09e667;
|
||||
ctx->state[1] = 0xbb67ae85;
|
||||
ctx->state[2] = 0x3c6ef372;
|
||||
ctx->state[3] = 0xa54ff53a;
|
||||
ctx->state[4] = 0x510e527f;
|
||||
ctx->state[5] = 0x9b05688c;
|
||||
ctx->state[6] = 0x1f83d9ab;
|
||||
ctx->state[7] = 0x5be0cd19;
|
||||
}
|
||||
|
||||
static void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
|
||||
{
|
||||
WORD i;
|
||||
|
||||
for (i = 0; i < len; ++i)
|
||||
{
|
||||
ctx->data[ctx->datalen] = data[i];
|
||||
ctx->datalen++;
|
||||
if (ctx->datalen == 64) {
|
||||
sha256_transform(ctx, ctx->data);
|
||||
ctx->bitlen += 512;
|
||||
ctx->datalen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sha256_final(SHA256_CTX *ctx, BYTE hash[])
|
||||
{
|
||||
WORD i;
|
||||
|
||||
i = ctx->datalen;
|
||||
|
||||
/* Pad whatever data is left in the buffer. */
|
||||
if (ctx->datalen < 56)
|
||||
{
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 56)
|
||||
ctx->data[i++] = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx->data[i++] = 0x80;
|
||||
while (i < 64)
|
||||
ctx->data[i++] = 0x00;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
memset(ctx->data, 0, 56);
|
||||
}
|
||||
|
||||
/* Append to the padding the total message's length in bits and transform. */
|
||||
ctx->bitlen += ctx->datalen * 8;
|
||||
ctx->data[63] = ctx->bitlen;
|
||||
ctx->data[62] = ctx->bitlen >> 8;
|
||||
ctx->data[61] = ctx->bitlen >> 16;
|
||||
ctx->data[60] = ctx->bitlen >> 24;
|
||||
ctx->data[59] = ctx->bitlen >> 32;
|
||||
ctx->data[58] = ctx->bitlen >> 40;
|
||||
ctx->data[57] = ctx->bitlen >> 48;
|
||||
ctx->data[56] = ctx->bitlen >> 56;
|
||||
sha256_transform(ctx, ctx->data);
|
||||
|
||||
/* Since this implementation uses little endian byte ordering and SHA uses big endian,
|
||||
reverse all the bytes when copying the final state to the output hash. */
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
|
||||
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+11
-9
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -235,7 +235,6 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
|
||||
/* stringify MAC into dhcp_buff */
|
||||
p = daemon->dhcp_buff;
|
||||
@@ -433,7 +432,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
@@ -611,8 +611,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", data.giaddr.s_addr != 0 ? inet_ntoa(data.giaddr) : NULL, &err);
|
||||
else
|
||||
{
|
||||
const char *giaddr = NULL;
|
||||
if (data.giaddr.s_addr != 0)
|
||||
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", giaddr, &err);
|
||||
}
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
@@ -882,7 +887,4 @@ void helper_write(void)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_SCRIPT */
|
||||
+9
-3
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -148,12 +148,19 @@ void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revh
|
||||
if (!(ah->flags & flag))
|
||||
continue;
|
||||
|
||||
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
|
||||
if (stat(ah->fname, &buf) == -1)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(S_ISDIR(buf.st_mode)))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("bad dynamic directory %s: %s"),
|
||||
ah->fname, _("not a directory"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(ah->flags & AH_WD_DONE))
|
||||
{
|
||||
@@ -295,4 +302,3 @@ int inotify_check(time_t now)
|
||||
}
|
||||
|
||||
#endif /* INOTIFY */
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -31,4 +31,3 @@
|
||||
&& ((__const uint32_t *) (a))[1] == 0 \
|
||||
&& ((__const uint32_t *) (a))[2] == 0 \
|
||||
&& ((__const uint32_t *) (a))[3] == 0)
|
||||
|
||||
+1
-16
@@ -22,9 +22,7 @@
|
||||
#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
|
||||
@@ -87,20 +85,7 @@ static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, con
|
||||
|
||||
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));
|
||||
old_kernel = (daemon->kernel_version < KERNEL_VERSION(2,6,32));
|
||||
|
||||
if (old_kernel && (ipset_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1)
|
||||
return;
|
||||
|
||||
+4
-7
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -378,7 +378,7 @@ void lease_update_file(time_t now)
|
||||
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
|
||||
next_event = LEASE_RETRY + now;
|
||||
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
|
||||
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %u s)"),
|
||||
daemon->lease_file, strerror(err),
|
||||
(unsigned int)difftime(next_event, now));
|
||||
}
|
||||
@@ -1021,6 +1021,7 @@ void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, ch
|
||||
}
|
||||
|
||||
kill_name(lease_tmp);
|
||||
lease_tmp->flags |= LEASE_CHANGED; /* run script on change */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1201,8 +1202,4 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP */
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -273,7 +273,7 @@ static void log_write(void)
|
||||
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
|
||||
OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
|
||||
DNS, DHCP and TFTP services.
|
||||
*/
|
||||
If OR'd with MS_DEBUG, the messages are suppressed unless --log-debug is set. */
|
||||
void my_syslog(int priority, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -290,7 +290,13 @@ void my_syslog(int priority, const char *format, ...)
|
||||
func = "-dhcp";
|
||||
else if ((LOG_FACMASK & priority) == MS_SCRIPT)
|
||||
func = "-script";
|
||||
|
||||
else if ((LOG_FACMASK & priority) == MS_DEBUG)
|
||||
{
|
||||
if (!option_bool(OPT_LOG_DEBUG))
|
||||
return;
|
||||
func = "-debug";
|
||||
}
|
||||
|
||||
#ifdef LOG_PRI
|
||||
priority = LOG_PRI(priority);
|
||||
#else
|
||||
|
||||
+20
-24
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -22,6 +22,7 @@ static ssize_t loop_make_probe(u32 uid);
|
||||
void loop_send_probes()
|
||||
{
|
||||
struct server *serv;
|
||||
struct randfd_list *rfds = NULL;
|
||||
|
||||
if (!option_bool(OPT_LOOP_DETECT))
|
||||
return;
|
||||
@@ -29,34 +30,29 @@ void loop_send_probes()
|
||||
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
|
||||
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
|
||||
if (strlen(serv->domain) == 0 &&
|
||||
!(serv->flags & (SERV_FOR_NODOTS)))
|
||||
{
|
||||
ssize_t len = loop_make_probe(serv->uid);
|
||||
int fd;
|
||||
struct randfd *rfd = NULL;
|
||||
|
||||
if (serv->sfd)
|
||||
fd = serv->sfd->fd;
|
||||
else
|
||||
{
|
||||
if (!(rfd = allocate_rfd(serv->addr.sa.sa_family)))
|
||||
continue;
|
||||
fd = rfd->fd;
|
||||
}
|
||||
serv->flags &= ~SERV_LOOP;
|
||||
|
||||
if ((fd = allocate_rfd(&rfds, serv)) == -1)
|
||||
continue;
|
||||
|
||||
while (retry_send(sendto(fd, daemon->packet, len, 0,
|
||||
&serv->addr.sa, sa_len(&serv->addr))));
|
||||
|
||||
free_rfd(rfd);
|
||||
}
|
||||
|
||||
free_rfds(&rfds);
|
||||
}
|
||||
|
||||
static ssize_t loop_make_probe(u32 uid)
|
||||
{
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
@@ -102,15 +98,15 @@ int detect_loop(char *query, int type)
|
||||
uid = strtol(query, NULL, 16);
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
|
||||
uid == serv->uid)
|
||||
{
|
||||
serv->flags |= SERV_LOOP;
|
||||
check_servers(); /* log new state */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(serv->domain) == 0 &&
|
||||
!(serv->flags & SERV_LOOP) &&
|
||||
uid == serv->uid)
|
||||
{
|
||||
serv->flags |= SERV_LOOP;
|
||||
check_servers(1); /* log new state - don't send more probes. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+61
-37
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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,6 +27,9 @@
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
#ifndef NETLINK_NO_ENOBUFS
|
||||
#define NETLINK_NO_ENOBUFS 5
|
||||
#endif
|
||||
|
||||
/* linux 2.6.19 buggers up the headers, patch it up here. */
|
||||
#ifndef IFA_RTA
|
||||
@@ -38,19 +41,26 @@
|
||||
|
||||
#ifndef NDA_RTA
|
||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Used to request refresh of addresses or routes just once,
|
||||
* when multiple changes might be announced. */
|
||||
enum async_states {
|
||||
STATE_NEWADDR = (1 << 0),
|
||||
STATE_NEWROUTE = (1 << 1),
|
||||
};
|
||||
|
||||
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
static void nl_async(struct nlmsghdr *h);
|
||||
static unsigned nl_async(struct nlmsghdr *h, unsigned state);
|
||||
static void nl_multicast_state(unsigned state);
|
||||
|
||||
void netlink_init(void)
|
||||
char *netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
int opt = 1;
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
@@ -79,18 +89,20 @@ void netlink_init(void)
|
||||
}
|
||||
|
||||
if (daemon->netlinkfd == -1 ||
|
||||
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1 ||
|
||||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
|
||||
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
|
||||
/* save pid assigned by bind() and retrieved by getsockname() */
|
||||
netlink_pid = addr.nl_pid;
|
||||
|
||||
iov.iov_len = 100;
|
||||
iov.iov_base = safe_malloc(iov.iov_len);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(void)
|
||||
static ssize_t netlink_recv(int flags)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct sockaddr_nl nladdr;
|
||||
@@ -106,7 +118,8 @@ static ssize_t netlink_recv(void)
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 &&
|
||||
errno == EINTR);
|
||||
|
||||
/* make buffer big enough */
|
||||
if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
|
||||
@@ -123,7 +136,7 @@ static ssize_t netlink_recv(void)
|
||||
|
||||
/* read it for real */
|
||||
msg.msg_flags = 0;
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
|
||||
while ((rc = recvmsg(daemon->netlinkfd, &msg, flags)) == -1 && errno == EINTR);
|
||||
|
||||
/* Make sure this is from the kernel */
|
||||
if (rc == -1 || nladdr.nl_pid == 0)
|
||||
@@ -142,7 +155,9 @@ static ssize_t netlink_recv(void)
|
||||
|
||||
|
||||
/* family = AF_UNSPEC finds ARP table entries.
|
||||
family = AF_LOCAL finds MAC addresses. */
|
||||
family = AF_LOCAL finds MAC addresses.
|
||||
returns 0 on failure, 1 on success, -1 when restart is required
|
||||
*/
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
@@ -150,6 +165,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int callback_ok = 1;
|
||||
unsigned state = 0;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -161,7 +177,6 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
|
||||
again:
|
||||
if (family == AF_UNSPEC)
|
||||
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||
else if (family == AF_LOCAL)
|
||||
@@ -184,12 +199,12 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
|
||||
while (1)
|
||||
{
|
||||
if ((len = netlink_recv()) == -1)
|
||||
if ((len = netlink_recv(0)) == -1)
|
||||
{
|
||||
if (errno == ENOBUFS)
|
||||
{
|
||||
sleep(1);
|
||||
goto again;
|
||||
nl_multicast_state(state);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -198,7 +213,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
nl_async(h);
|
||||
state = nl_async(h, state);
|
||||
}
|
||||
else if (h->nlmsg_seq != seq)
|
||||
{
|
||||
@@ -332,26 +347,28 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
}
|
||||
}
|
||||
|
||||
void netlink_multicast(void)
|
||||
static void nl_multicast_state(unsigned state)
|
||||
{
|
||||
ssize_t len;
|
||||
struct nlmsghdr *h;
|
||||
int flags;
|
||||
|
||||
do {
|
||||
/* don't risk blocking reading netlink messages here. */
|
||||
while ((len = netlink_recv(MSG_DONTWAIT)) != -1)
|
||||
|
||||
/* don't risk blocking reading netlink messages here. */
|
||||
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
return;
|
||||
|
||||
if ((len = netlink_recv()) != -1)
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
nl_async(h);
|
||||
|
||||
/* restore non-blocking status */
|
||||
fcntl(daemon->netlinkfd, F_SETFL, flags);
|
||||
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
|
||||
state = nl_async(h, state);
|
||||
} while (errno == ENOBUFS);
|
||||
}
|
||||
|
||||
static void nl_async(struct nlmsghdr *h)
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
unsigned state = 0;
|
||||
nl_multicast_state(state);
|
||||
}
|
||||
|
||||
|
||||
static unsigned nl_async(struct nlmsghdr *h, unsigned state)
|
||||
{
|
||||
if (h->nlmsg_type == NLMSG_ERROR)
|
||||
{
|
||||
@@ -359,7 +376,8 @@ static void nl_async(struct nlmsghdr *h)
|
||||
if (err->error != 0)
|
||||
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
|
||||
}
|
||||
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
|
||||
else if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE &&
|
||||
(state & STATE_NEWROUTE)==0)
|
||||
{
|
||||
/* 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.
|
||||
@@ -371,11 +389,17 @@ static void nl_async(struct nlmsghdr *h)
|
||||
if (rtm->rtm_type == RTN_UNICAST && rtm->rtm_scope == RT_SCOPE_LINK &&
|
||||
(rtm->rtm_table == RT_TABLE_MAIN ||
|
||||
rtm->rtm_table == RT_TABLE_LOCAL))
|
||||
queue_event(EVENT_NEWROUTE);
|
||||
{
|
||||
queue_event(EVENT_NEWROUTE);
|
||||
state |= STATE_NEWROUTE;
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
queue_event(EVENT_NEWADDR);
|
||||
else if ((h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR) &&
|
||||
(state & STATE_NEWADDR)==0)
|
||||
{
|
||||
queue_event(EVENT_NEWADDR);
|
||||
state |= STATE_NEWADDR;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HAVE_LINUX_NETWORK */
|
||||
+441
-369
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,94 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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"
|
||||
|
||||
#if defined (HAVE_NFTSET) && defined (HAVE_LINUX_NETWORK)
|
||||
|
||||
#include <nftables/libnftables.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static struct nft_ctx *ctx = NULL;
|
||||
static const char *cmd_add = "add element %s { %s }";
|
||||
static const char *cmd_del = "delete element %s { %s }";
|
||||
|
||||
void nftset_init()
|
||||
{
|
||||
ctx = nft_ctx_new(NFT_CTX_DEFAULT);
|
||||
if (ctx == NULL)
|
||||
die(_("failed to create nftset context"), NULL, EC_MISC);
|
||||
|
||||
/* disable libnftables output */
|
||||
nft_ctx_buffer_error(ctx);
|
||||
}
|
||||
|
||||
int add_to_nftset(const char *setname, const union all_addr *ipaddr, int flags, int remove)
|
||||
{
|
||||
const char *cmd = remove ? cmd_del : cmd_add;
|
||||
int ret, af = (flags & F_IPV4) ? AF_INET : AF_INET6;
|
||||
size_t new_sz;
|
||||
char *new, *err, *nl;
|
||||
static char *cmd_buf = NULL;
|
||||
static size_t cmd_buf_sz = 0;
|
||||
|
||||
inet_ntop(af, ipaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
if (setname[1] == ' ' && (setname[0] == '4' || setname[0] == '6'))
|
||||
{
|
||||
if (setname[0] == '4' && !(flags & F_IPV4))
|
||||
return -1;
|
||||
|
||||
if (setname[0] == '6' && !(flags & F_IPV6))
|
||||
return -1;
|
||||
|
||||
setname += 2;
|
||||
}
|
||||
|
||||
if (cmd_buf_sz == 0)
|
||||
new_sz = 150; /* initial allocation */
|
||||
else
|
||||
new_sz = snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
|
||||
if (new_sz > cmd_buf_sz)
|
||||
{
|
||||
if (!(new = whine_malloc(new_sz + 10)))
|
||||
return 0;
|
||||
|
||||
if (cmd_buf)
|
||||
free(cmd_buf);
|
||||
cmd_buf = new;
|
||||
cmd_buf_sz = new_sz + 10;
|
||||
snprintf(cmd_buf, cmd_buf_sz, cmd, setname, daemon->addrbuff);
|
||||
}
|
||||
|
||||
ret = nft_run_cmd_from_buffer(ctx, cmd_buf);
|
||||
err = (char *)nft_ctx_get_error_buffer(ctx);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
/* Log only first line of error return. */
|
||||
if ((nl = strchr(err, '\n')))
|
||||
*nl = 0;
|
||||
my_syslog(LOG_ERR, "nftset %s %s", setname, err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
+696
-317
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+386
@@ -0,0 +1,386 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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_CONNTRACK
|
||||
|
||||
#define LOG(...) \
|
||||
do { \
|
||||
my_syslog(LOG_DEBUG, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT(condition) \
|
||||
do { \
|
||||
if (!(condition)) \
|
||||
my_syslog(LOG_ERR, _("[pattern.c:%d] Assertion failure: %s"), __LINE__, #condition); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Determines whether a given string value matches against a glob pattern
|
||||
* which may contain zero-or-more-character wildcards denoted by '*'.
|
||||
*
|
||||
* Based on "Glob Matching Can Be Simple And Fast Too" by Russ Cox,
|
||||
* See https://research.swtch.com/glob
|
||||
*
|
||||
* @param value A string value.
|
||||
* @param num_value_bytes The number of bytes of the string value.
|
||||
* @param pattern A glob pattern.
|
||||
* @param num_pattern_bytes The number of bytes of the glob pattern.
|
||||
*
|
||||
* @return 1 If the provided value matches against the glob pattern.
|
||||
* @return 0 Otherwise.
|
||||
*/
|
||||
static int is_string_matching_glob_pattern(
|
||||
const char *value,
|
||||
size_t num_value_bytes,
|
||||
const char *pattern,
|
||||
size_t num_pattern_bytes)
|
||||
{
|
||||
ASSERT(value);
|
||||
ASSERT(pattern);
|
||||
|
||||
size_t value_index = 0;
|
||||
size_t next_value_index = 0;
|
||||
size_t pattern_index = 0;
|
||||
size_t next_pattern_index = 0;
|
||||
while (value_index < num_value_bytes || pattern_index < num_pattern_bytes)
|
||||
{
|
||||
if (pattern_index < num_pattern_bytes)
|
||||
{
|
||||
char pattern_character = pattern[pattern_index];
|
||||
if ('a' <= pattern_character && pattern_character <= 'z')
|
||||
pattern_character -= 'a' - 'A';
|
||||
if (pattern_character == '*')
|
||||
{
|
||||
/* zero-or-more-character wildcard */
|
||||
/* Try to match at value_index, otherwise restart at value_index + 1 next. */
|
||||
next_pattern_index = pattern_index;
|
||||
pattern_index++;
|
||||
if (value_index < num_value_bytes)
|
||||
next_value_index = value_index + 1;
|
||||
else
|
||||
next_value_index = 0;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ordinary character */
|
||||
if (value_index < num_value_bytes)
|
||||
{
|
||||
char value_character = value[value_index];
|
||||
if ('a' <= value_character && value_character <= 'z')
|
||||
value_character -= 'a' - 'A';
|
||||
if (value_character == pattern_character)
|
||||
{
|
||||
pattern_index++;
|
||||
value_index++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (next_value_index)
|
||||
{
|
||||
pattern_index = next_pattern_index;
|
||||
value_index = next_value_index;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given string value represents a valid DNS name.
|
||||
*
|
||||
* - DNS names must adhere to RFC 1123: 1 to 253 characters in length, consisting of a sequence of labels
|
||||
* delimited by dots ("."). Each label must be 1 to 63 characters in length, contain only
|
||||
* ASCII letters ("a"-"Z"), digits ("0"-"9"), or hyphens ("-") and must not start or end with a hyphen.
|
||||
*
|
||||
* - A valid name must be fully qualified, i.e., consist of at least two labels.
|
||||
* The final label must not be fully numeric, and must not be the "local" pseudo-TLD.
|
||||
*
|
||||
* - Examples:
|
||||
* Valid: "example.com"
|
||||
* Invalid: "ipcamera", "ipcamera.local", "8.8.8.8"
|
||||
*
|
||||
* @param value A string value.
|
||||
*
|
||||
* @return 1 If the provided string value is a valid DNS name.
|
||||
* @return 0 Otherwise.
|
||||
*/
|
||||
int is_valid_dns_name(const char *value)
|
||||
{
|
||||
ASSERT(value);
|
||||
|
||||
size_t num_bytes = 0;
|
||||
size_t num_labels = 0;
|
||||
const char *label = NULL;
|
||||
int is_label_numeric = 1;
|
||||
for (const char *c = value;; c++)
|
||||
{
|
||||
if (*c &&
|
||||
*c != '-' && *c != '.' &&
|
||||
(*c < '0' || *c > '9') &&
|
||||
(*c < 'A' || *c > 'Z') &&
|
||||
(*c < 'a' || *c > 'z'))
|
||||
{
|
||||
LOG(_("Invalid DNS name: Invalid character %c."), *c);
|
||||
return 0;
|
||||
}
|
||||
if (*c)
|
||||
num_bytes++;
|
||||
if (!label)
|
||||
{
|
||||
if (!*c || *c == '.')
|
||||
{
|
||||
LOG(_("Invalid DNS name: Empty label."));
|
||||
return 0;
|
||||
}
|
||||
if (*c == '-')
|
||||
{
|
||||
LOG(_("Invalid DNS name: Label starts with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
label = c;
|
||||
}
|
||||
if (*c && *c != '.')
|
||||
{
|
||||
if (*c < '0' || *c > '9')
|
||||
is_label_numeric = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c[-1] == '-')
|
||||
{
|
||||
LOG(_("Invalid DNS name: Label ends with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
size_t num_label_bytes = (size_t) (c - label);
|
||||
if (num_label_bytes > 63)
|
||||
{
|
||||
LOG(_("Invalid DNS name: Label is too long (%zu)."), num_label_bytes);
|
||||
return 0;
|
||||
}
|
||||
num_labels++;
|
||||
if (!*c)
|
||||
{
|
||||
if (num_labels < 2)
|
||||
{
|
||||
LOG(_("Invalid DNS name: Not enough labels (%zu)."), num_labels);
|
||||
return 0;
|
||||
}
|
||||
if (is_label_numeric)
|
||||
{
|
||||
LOG(_("Invalid DNS name: Final label is fully numeric."));
|
||||
return 0;
|
||||
}
|
||||
if (num_label_bytes == 5 &&
|
||||
(label[0] == 'l' || label[0] == 'L') &&
|
||||
(label[1] == 'o' || label[1] == 'O') &&
|
||||
(label[2] == 'c' || label[2] == 'C') &&
|
||||
(label[3] == 'a' || label[3] == 'A') &&
|
||||
(label[4] == 'l' || label[4] == 'L'))
|
||||
{
|
||||
LOG(_("Invalid DNS name: \"local\" pseudo-TLD."));
|
||||
return 0;
|
||||
}
|
||||
if (num_bytes < 1 || num_bytes > 253)
|
||||
{
|
||||
LOG(_("DNS name has invalid length (%zu)."), num_bytes);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
label = NULL;
|
||||
is_label_numeric = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given string value represents a valid DNS name pattern.
|
||||
*
|
||||
* - DNS names must adhere to RFC 1123: 1 to 253 characters in length, consisting of a sequence of labels
|
||||
* delimited by dots ("."). Each label must be 1 to 63 characters in length, contain only
|
||||
* ASCII letters ("a"-"Z"), digits ("0"-"9"), or hyphens ("-") and must not start or end with a hyphen.
|
||||
*
|
||||
* - Patterns follow the syntax of DNS names, but additionally allow the wildcard character "*" to be used up to
|
||||
* twice per label to match 0 or more characters within that label. Note that the wildcard never matches a dot
|
||||
* (e.g., "*.example.com" matches "api.example.com" but not "api.us.example.com").
|
||||
*
|
||||
* - A valid name or pattern must be fully qualified, i.e., consist of at least two labels.
|
||||
* The final label must not be fully numeric, and must not be the "local" pseudo-TLD.
|
||||
* A pattern must end with at least two literal (non-wildcard) labels.
|
||||
*
|
||||
* - Examples:
|
||||
* Valid: "example.com", "*.example.com", "video*.example.com", "api*.*.example.com", "*-prod-*.example.com"
|
||||
* Invalid: "ipcamera", "ipcamera.local", "*", "*.com", "8.8.8.8"
|
||||
*
|
||||
* @param value A string value.
|
||||
*
|
||||
* @return 1 If the provided string value is a valid DNS name pattern.
|
||||
* @return 0 Otherwise.
|
||||
*/
|
||||
int is_valid_dns_name_pattern(const char *value)
|
||||
{
|
||||
ASSERT(value);
|
||||
|
||||
size_t num_bytes = 0;
|
||||
size_t num_labels = 0;
|
||||
const char *label = NULL;
|
||||
int is_label_numeric = 1;
|
||||
size_t num_wildcards = 0;
|
||||
int previous_label_has_wildcard = 1;
|
||||
for (const char *c = value;; c++)
|
||||
{
|
||||
if (*c &&
|
||||
*c != '*' && /* Wildcard. */
|
||||
*c != '-' && *c != '.' &&
|
||||
(*c < '0' || *c > '9') &&
|
||||
(*c < 'A' || *c > 'Z') &&
|
||||
(*c < 'a' || *c > 'z'))
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Invalid character %c."), *c);
|
||||
return 0;
|
||||
}
|
||||
if (*c && *c != '*')
|
||||
num_bytes++;
|
||||
if (!label)
|
||||
{
|
||||
if (!*c || *c == '.')
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Empty label."));
|
||||
return 0;
|
||||
}
|
||||
if (*c == '-')
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Label starts with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
label = c;
|
||||
}
|
||||
if (*c && *c != '.')
|
||||
{
|
||||
if (*c < '0' || *c > '9')
|
||||
is_label_numeric = 0;
|
||||
if (*c == '*')
|
||||
{
|
||||
if (num_wildcards >= 2)
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Wildcard character used more than twice per label."));
|
||||
return 0;
|
||||
}
|
||||
num_wildcards++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c[-1] == '-')
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Label ends with hyphen."));
|
||||
return 0;
|
||||
}
|
||||
size_t num_label_bytes = (size_t) (c - label) - num_wildcards;
|
||||
if (num_label_bytes > 63)
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Label is too long (%zu)."), num_label_bytes);
|
||||
return 0;
|
||||
}
|
||||
num_labels++;
|
||||
if (!*c)
|
||||
{
|
||||
if (num_labels < 2)
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Not enough labels (%zu)."), num_labels);
|
||||
return 0;
|
||||
}
|
||||
if (num_wildcards != 0 || previous_label_has_wildcard)
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Wildcard within final two labels."));
|
||||
return 0;
|
||||
}
|
||||
if (is_label_numeric)
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: Final label is fully numeric."));
|
||||
return 0;
|
||||
}
|
||||
if (num_label_bytes == 5 &&
|
||||
(label[0] == 'l' || label[0] == 'L') &&
|
||||
(label[1] == 'o' || label[1] == 'O') &&
|
||||
(label[2] == 'c' || label[2] == 'C') &&
|
||||
(label[3] == 'a' || label[3] == 'A') &&
|
||||
(label[4] == 'l' || label[4] == 'L'))
|
||||
{
|
||||
LOG(_("Invalid DNS name pattern: \"local\" pseudo-TLD."));
|
||||
return 0;
|
||||
}
|
||||
if (num_bytes < 1 || num_bytes > 253)
|
||||
{
|
||||
LOG(_("DNS name pattern has invalid length after removing wildcards (%zu)."), num_bytes);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
label = NULL;
|
||||
is_label_numeric = 1;
|
||||
previous_label_has_wildcard = num_wildcards != 0;
|
||||
num_wildcards = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given DNS name matches against a DNS name pattern.
|
||||
*
|
||||
* @param name A valid DNS name.
|
||||
* @param pattern A valid DNS name pattern.
|
||||
*
|
||||
* @return 1 If the provided DNS name matches against the DNS name pattern.
|
||||
* @return 0 Otherwise.
|
||||
*/
|
||||
int is_dns_name_matching_pattern(const char *name, const char *pattern)
|
||||
{
|
||||
ASSERT(name);
|
||||
ASSERT(is_valid_dns_name(name));
|
||||
ASSERT(pattern);
|
||||
ASSERT(is_valid_dns_name_pattern(pattern));
|
||||
|
||||
const char *n = name;
|
||||
const char *p = pattern;
|
||||
|
||||
do {
|
||||
const char *name_label = n;
|
||||
while (*n && *n != '.')
|
||||
n++;
|
||||
const char *pattern_label = p;
|
||||
while (*p && *p != '.')
|
||||
p++;
|
||||
if (!is_string_matching_glob_pattern(
|
||||
name_label, (size_t) (n - name_label),
|
||||
pattern_label, (size_t) (p - pattern_label)))
|
||||
break;
|
||||
if (*n)
|
||||
n++;
|
||||
if (*p)
|
||||
p++;
|
||||
} while (*n && *p);
|
||||
|
||||
return !*n && !*p;
|
||||
}
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+1
-4
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -53,6 +53,3 @@ struct prefix_opt {
|
||||
#define ICMP6_OPT_RT_INFO 24
|
||||
#define ICMP6_OPT_RDNSS 25
|
||||
#define ICMP6_OPT_DNSSL 31
|
||||
|
||||
|
||||
|
||||
+8
-3
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -626,8 +626,11 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
/* find floor time, don't reduce below 3 * RA interval.
|
||||
If the lease time has been left as default, don't
|
||||
use that as a floor. */
|
||||
if ((context->flags & CONTEXT_SETLEASE) &&
|
||||
time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)(3 * param->adv_interval)))
|
||||
@@ -743,6 +746,8 @@ static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void
|
||||
add 7 to round up */
|
||||
int len = (maclen + 9) >> 3;
|
||||
unsigned char *p = expand(len << 3);
|
||||
if (!p)
|
||||
return 1;
|
||||
memset(p, 0, len << 3);
|
||||
*p++ = ICMP6_OPT_SOURCE_MAC;
|
||||
*p++ = len;
|
||||
|
||||
+602
-519
File diff suppressed because it is too large.
Load diff
+132
-72
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -30,7 +30,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
||||
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
|
||||
static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, int len, unsigned int val);
|
||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||
int opt, char *string, int null_term);
|
||||
int opt, const char *string, int null_term);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int offset, int size);
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
@@ -54,17 +54,19 @@ static void do_options(struct dhcp_context *context,
|
||||
int vendor_class_len,
|
||||
time_t now,
|
||||
unsigned int lease_time,
|
||||
unsigned short fuzz);
|
||||
unsigned short fuzz,
|
||||
const char *pxevendor);
|
||||
|
||||
|
||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor);
|
||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
||||
static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dhcp_packet *mess, struct in_addr local, time_t now, int pxe);
|
||||
static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid);
|
||||
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor);
|
||||
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int loopback,
|
||||
@@ -76,6 +78,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
||||
const char *pxevendor = NULL;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
unsigned char *end = (unsigned char *)(mess + 1);
|
||||
unsigned char *real_end = (unsigned char *)(mess + 1);
|
||||
@@ -369,9 +372,22 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!context)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
|
||||
subnet_addr.s_addr ? _("with subnet selector") : _("via"),
|
||||
subnet_addr.s_addr ? inet_ntoa(subnet_addr) : (mess->giaddr.s_addr ? inet_ntoa(mess->giaddr) : iface_name));
|
||||
const char *via;
|
||||
if (subnet_addr.s_addr)
|
||||
{
|
||||
via = _("with subnet selector");
|
||||
inet_ntop(AF_INET, &subnet_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
via = _("via");
|
||||
if (mess->giaddr.s_addr)
|
||||
inet_ntop(AF_INET, &mess->giaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
else
|
||||
safe_strncpy(daemon->addrbuff, iface_name, ADDRSTRLEN);
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("no address range available for DHCP request %s %s"),
|
||||
via, daemon->addrbuff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -380,13 +396,19 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_context *context_tmp;
|
||||
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(context_tmp->start));
|
||||
inet_ntop(AF_INET, &context_tmp->start, daemon->namebuff, MAXDNAME);
|
||||
if (context_tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
|
||||
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->netmask));
|
||||
{
|
||||
inet_ntop(AF_INET, &context_tmp->netmask, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP subnet: %s/%s"),
|
||||
ntohl(mess->xid), daemon->namebuff, daemon->addrbuff);
|
||||
}
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
|
||||
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
|
||||
{
|
||||
inet_ntop(AF_INET, &context_tmp->end, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u available DHCP range: %s -- %s"),
|
||||
ntohl(mess->xid), daemon->namebuff, daemon->addrbuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -647,7 +669,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,9 +857,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
clid = NULL;
|
||||
|
||||
/* Check if client is PXE client. */
|
||||
if (daemon->enable_pxe &&
|
||||
(opt = option_find(mess, sz, OPTION_VENDOR_ID, 9)) &&
|
||||
strncmp(option_ptr(opt, 0), "PXEClient", 9) == 0)
|
||||
if (daemon->enable_pxe &&
|
||||
is_pxe_client(mess, sz, &pxevendor))
|
||||
{
|
||||
if ((opt = option_find(mess, sz, OPTION_PXE_UUID, 17)))
|
||||
{
|
||||
@@ -899,7 +920,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
|
||||
prune_vendor_opts(tagif_netid);
|
||||
opt71.val = save71;
|
||||
@@ -979,7 +1000,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
if ((pxe && !workaround) || !redirect4011)
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
@@ -1029,8 +1050,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
config->addr.s_addr == option_addr(opt).s_addr)
|
||||
{
|
||||
prettyprint_time(daemon->dhcp_buff, DECLINE_BACKOFF);
|
||||
inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
|
||||
inet_ntoa(config->addr), daemon->dhcp_buff);
|
||||
daemon->addrbuff, daemon->dhcp_buff);
|
||||
config->flags |= CONFIG_DECLINED;
|
||||
config->decline_time = now;
|
||||
}
|
||||
@@ -1076,7 +1098,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (have_config(config, CONFIG_ADDR))
|
||||
{
|
||||
char *addrs = inet_ntoa(config->addr);
|
||||
inet_ntop(AF_INET, &config->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
if ((ltmp = lease_find_by_addr(config->addr)) &&
|
||||
ltmp != lease &&
|
||||
@@ -1086,7 +1108,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
unsigned char *mac = extended_hwaddr(ltmp->hwaddr_type, ltmp->hwaddr_len,
|
||||
ltmp->hwaddr, ltmp->clid_len, ltmp->clid, &len);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is leased to %s"),
|
||||
addrs, print_mac(daemon->namebuff, mac, len));
|
||||
daemon->addrbuff, print_mac(daemon->namebuff, mac, len));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1095,10 +1117,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (context->router.s_addr == config->addr.s_addr)
|
||||
break;
|
||||
if (tmp)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), addrs);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by the server or relay"), daemon->addrbuff);
|
||||
else if (have_config(config, CONFIG_DECLINED) &&
|
||||
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), daemon->addrbuff);
|
||||
else
|
||||
conf = config->addr;
|
||||
}
|
||||
@@ -1150,7 +1172,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
|
||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
@@ -1301,9 +1323,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
a lease from one of it's MACs to give the address to another. */
|
||||
if (config && config_has_mac(config, ltmp->hwaddr, ltmp->hwaddr_len, ltmp->hwaddr_type))
|
||||
{
|
||||
inet_ntop(AF_INET, <mp->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("abandoning lease to %s of %s"),
|
||||
print_mac(daemon->namebuff, ltmp->hwaddr, ltmp->hwaddr_len),
|
||||
inet_ntoa(ltmp->addr));
|
||||
daemon->addrbuff);
|
||||
lease = ltmp;
|
||||
}
|
||||
else
|
||||
@@ -1499,7 +1522,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (rapid_commit)
|
||||
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz, pxevendor);
|
||||
}
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1566,7 +1589,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0, pxevendor);
|
||||
|
||||
*is_inform = 1; /* handle reply differently */
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -1672,42 +1695,40 @@ static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
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 */
|
||||
daemon->addrbuff[0] = 0;
|
||||
if (addr)
|
||||
memcpy(&a, addr, sizeof(a));
|
||||
inet_ntop(AF_INET, addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
|
||||
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%s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
interface,
|
||||
addr ? inet_ntoa(a) : "",
|
||||
addr ? " " : "",
|
||||
daemon->namebuff,
|
||||
string ? string : "",
|
||||
err ? err : "");
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s%s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
interface,
|
||||
addr ? inet_ntoa(a) : "",
|
||||
daemon->addrbuff,
|
||||
addr ? " " : "",
|
||||
daemon->namebuff,
|
||||
string ? string : "",
|
||||
err ? err : "");
|
||||
|
||||
else
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%s(%s) %s%s%s %s%s",
|
||||
type,
|
||||
interface,
|
||||
daemon->addrbuff,
|
||||
addr ? " " : "",
|
||||
daemon->namebuff,
|
||||
string ? string : "",
|
||||
err ? err : "");
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (!strcmp(type, "DHCPACK"))
|
||||
ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
|
||||
else if (!strcmp(type, "DHCPRELEASE"))
|
||||
ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? inet_ntoa(a) : NULL, string ? string : NULL, interface);
|
||||
if (!strcmp(type, "DHCPACK"))
|
||||
ubus_event_bcast("dhcp.ack", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface);
|
||||
else if (!strcmp(type, "DHCPRELEASE"))
|
||||
ubus_event_bcast("dhcp.release", daemon->namebuff, addr ? daemon->addrbuff : NULL, string, interface);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1859,7 +1880,10 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (mess->siaddr.s_addr != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
|
||||
{
|
||||
inet_ntop(AF_INET, &mess->siaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), daemon->addrbuff);
|
||||
}
|
||||
|
||||
if ((mess->flags & htons(0x8000)) && mess->ciaddr.s_addr == 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u broadcast response"), ntohl(mess->xid));
|
||||
@@ -1948,7 +1972,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
|
||||
}
|
||||
|
||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end, int opt,
|
||||
char *string, int null_term)
|
||||
const char *string, int null_term)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t len = strlen(string);
|
||||
@@ -2026,15 +2050,32 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt)
|
||||
dopt->flags &= ~DHOPT_VENDOR_MATCH;
|
||||
if (opt && (dopt->flags & DHOPT_VENDOR))
|
||||
{
|
||||
int i, len = 0;
|
||||
if (dopt->u.vendor_class)
|
||||
len = strlen((char *)dopt->u.vendor_class);
|
||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||
if (len == 0 || memcmp(dopt->u.vendor_class, option_ptr(opt, i), len) == 0)
|
||||
{
|
||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||
break;
|
||||
}
|
||||
const struct dhcp_pxe_vendor *pv;
|
||||
struct dhcp_pxe_vendor dummy_vendor = {
|
||||
.data = (char *)dopt->u.vendor_class,
|
||||
.next = NULL,
|
||||
};
|
||||
if (dopt->flags & DHOPT_VENDOR_PXE)
|
||||
pv = daemon->dhcp_pxe_vendors;
|
||||
else
|
||||
pv = &dummy_vendor;
|
||||
for (; pv; pv = pv->next)
|
||||
{
|
||||
int i, len = 0, matched = 0;
|
||||
if (pv->data)
|
||||
len = strlen(pv->data);
|
||||
for (i = 0; i <= (option_len(opt) - len); i++)
|
||||
if (len == 0 || memcmp(pv->data, option_ptr(opt, i), len) == 0)
|
||||
{
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
if (matched)
|
||||
{
|
||||
dopt->flags |= DHOPT_VENDOR_MATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2087,11 +2128,13 @@ static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid)
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid, const char *pxevendor)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
option_put_string(mess, end, OPTION_VENDOR_ID, "PXEClient", 0);
|
||||
if (!pxevendor)
|
||||
pxevendor="PXEClient";
|
||||
option_put_string(mess, end, OPTION_VENDOR_ID, pxevendor, 0);
|
||||
if (uuid && (p = free_space(mess, end, OPTION_PXE_UUID, 17)))
|
||||
memcpy(p, uuid, 17);
|
||||
}
|
||||
@@ -2308,6 +2351,29 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid)
|
||||
return boot;
|
||||
}
|
||||
|
||||
static int is_pxe_client(struct dhcp_packet *mess, size_t sz, const char **pxe_vendor)
|
||||
{
|
||||
const unsigned char *opt = NULL;
|
||||
ssize_t conf_len = 0;
|
||||
const struct dhcp_pxe_vendor *conf = daemon->dhcp_pxe_vendors;
|
||||
opt = option_find(mess, sz, OPTION_VENDOR_ID, 0);
|
||||
if (!opt)
|
||||
return 0;
|
||||
for (; conf; conf = conf->next)
|
||||
{
|
||||
conf_len = strlen(conf->data);
|
||||
if (option_len(opt) < conf_len)
|
||||
continue;
|
||||
if (strncmp(option_ptr(opt, 0), conf->data, conf_len) == 0)
|
||||
{
|
||||
if (pxe_vendor)
|
||||
*pxe_vendor = conf->data;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *end,
|
||||
@@ -2322,7 +2388,8 @@ static void do_options(struct dhcp_context *context,
|
||||
int vendor_class_len,
|
||||
time_t now,
|
||||
unsigned int lease_time,
|
||||
unsigned short fuzz)
|
||||
unsigned short fuzz,
|
||||
const char *pxevendor)
|
||||
{
|
||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||
struct dhcp_boot *boot;
|
||||
@@ -2696,7 +2763,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (context && pxe_arch != -1)
|
||||
{
|
||||
pxe_misc(mess, end, uuid);
|
||||
pxe_misc(mess, end, uuid, pxevendor);
|
||||
if (!pxe_uefi_workaround(pxe_arch, tagif, mess, context->local, now, 0))
|
||||
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
|
||||
}
|
||||
@@ -2740,11 +2807,4 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* HAVE_DHCP */
|
||||
+43
-19
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -919,11 +919,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
|
||||
case DHCP6RENEW:
|
||||
case DHCP6REBIND:
|
||||
{
|
||||
int address_assigned = 0;
|
||||
|
||||
/* set reply message type */
|
||||
*outmsgtypep = DHCP6REPLY;
|
||||
|
||||
log6_quiet(state, "DHCPRENEW", NULL, NULL);
|
||||
log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
|
||||
|
||||
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
|
||||
{
|
||||
@@ -952,24 +955,35 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||
state->iaid, &req_addr)))
|
||||
{
|
||||
/* If the server cannot find a client entry for the IA the server
|
||||
returns the IA containing no addresses with a Status Code option set
|
||||
to NoBinding in the Reply message. */
|
||||
save_counter(iacntr);
|
||||
t1cntr = 0;
|
||||
|
||||
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
put_opt6_string(_("no binding found"));
|
||||
end_opt6(o1);
|
||||
|
||||
preferred_time = valid_time = 0;
|
||||
break;
|
||||
if (msg_type == DHCP6REBIND)
|
||||
{
|
||||
/* When rebinding, we can create a lease if it doesn't exist. */
|
||||
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
|
||||
if (lease)
|
||||
lease_set_iaid(lease, state->iaid);
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the server cannot find a client entry for the IA the server
|
||||
returns the IA containing no addresses with a Status Code option set
|
||||
to NoBinding in the Reply message. */
|
||||
save_counter(iacntr);
|
||||
t1cntr = 0;
|
||||
|
||||
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
put_opt6_string(_("no binding found"));
|
||||
end_opt6(o1);
|
||||
|
||||
preferred_time = valid_time = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
|
||||
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
|
||||
{
|
||||
@@ -1000,6 +1014,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
if (preferred_time == 0)
|
||||
message = _("deprecated");
|
||||
|
||||
address_assigned = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1022,10 +1038,18 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
end_ia(t1cntr, min_time, 1);
|
||||
end_opt6(o);
|
||||
}
|
||||
|
||||
if (!address_assigned && msg_type == DHCP6REBIND)
|
||||
{
|
||||
/* can't create lease for any address, return error */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string(_("no addresses available"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
|
||||
tagif = add_options(state, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case DHCP6CONFIRM:
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ int add_to_ipset(const char *setname, const union all_addr *ipaddr,
|
||||
io.pfrio_size = 1;
|
||||
if (ioctl(dev, DIOCRADDTABLES, &io))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
|
||||
my_syslog(LOG_WARNING, _("IPset: error: %s"), pfr_strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
+48
-27
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -22,7 +22,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
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 *message, char *file);
|
||||
static ssize_t tftp_err_oops(char *packet, char *file);
|
||||
static ssize_t tftp_err_oops(char *packet, const 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);
|
||||
@@ -39,6 +39,7 @@ static void sanitise(char *buf);
|
||||
#define ERR_PERM 2
|
||||
#define ERR_FULL 3
|
||||
#define ERR_ILL 4
|
||||
#define ERR_TID 5
|
||||
|
||||
void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
@@ -61,8 +62,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
union all_addr addra;
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
int check_dest = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
@@ -93,7 +95,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
if (!check_dest)
|
||||
{
|
||||
@@ -121,10 +123,10 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
addr.sa.sa_family = family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
@@ -138,7 +140,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -154,7 +156,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -171,7 +173,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
@@ -194,7 +196,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
addra.addr4 = addr.in.sin_addr;
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
addra.addr6 = addr.in6.sin6_addr;
|
||||
|
||||
if (daemon->tftp_interfaces)
|
||||
@@ -210,12 +212,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
else
|
||||
{
|
||||
/* Do the same as DHCP */
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
if (!iface_check(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))
|
||||
if (!loopback_exception(listen->tftpfd, family, &addra, name) &&
|
||||
!label_exception(if_index, family, &addra))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +283,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
prefix = pref->prefix;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -304,7 +306,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if (option_bool(OPT_SINGLE_PORT))
|
||||
transfer->sockfd = listen->tftpfd;
|
||||
else if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -322,7 +324,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&peer, daemon->addrbuff);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (!option_bool(OPT_SINGLE_PORT))
|
||||
@@ -337,7 +339,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
@@ -375,7 +377,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
|
||||
{
|
||||
/* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
|
||||
int overhead = (listen->family == AF_INET) ? 32 : 52;
|
||||
int overhead = (family == AF_INET) ? 32 : 52;
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
transfer->blocksize = 1;
|
||||
@@ -582,11 +584,27 @@ void check_tftp_listeners(time_t now)
|
||||
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
|
||||
if (poll_check(transfer->sockfd, POLLIN))
|
||||
{
|
||||
union mysockaddr peer;
|
||||
socklen_t addr_len = sizeof(union mysockaddr);
|
||||
ssize_t len;
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));
|
||||
}
|
||||
|
||||
if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
|
||||
{
|
||||
if (sockaddr_isequal(&peer, &transfer->peer))
|
||||
handle_tftp(now, transfer, len);
|
||||
else
|
||||
{
|
||||
/* Wrong source address. See rfc1350 para 4. */
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
|
||||
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
|
||||
{
|
||||
tmp = transfer->next;
|
||||
@@ -601,7 +619,7 @@ void check_tftp_listeners(time_t now)
|
||||
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
|
||||
if ((len = get_block(daemon->packet, transfer)) == -1)
|
||||
{
|
||||
len = tftp_err_oops(daemon->packet, transfer->file->filename);
|
||||
@@ -624,7 +642,7 @@ void check_tftp_listeners(time_t now)
|
||||
{
|
||||
strcpy(daemon->namebuff, transfer->file->filename);
|
||||
sanitise(daemon->namebuff);
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
@@ -667,7 +685,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
@@ -735,22 +753,25 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
|
||||
char *errstr = strerror(errno);
|
||||
|
||||
memset(packet, 0, daemon->packet_buff_sz);
|
||||
sanitise(file);
|
||||
if (file)
|
||||
sanitise(file);
|
||||
|
||||
mess->op = htons(OP_ERR);
|
||||
mess->err = htons(err);
|
||||
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
|
||||
ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
|
||||
|
||||
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
|
||||
if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
|
||||
my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t tftp_err_oops(char *packet, char *file)
|
||||
static ssize_t tftp_err_oops(char *packet, const char *file)
|
||||
{
|
||||
/* May have >1 refs to file, so potentially mangle a copy of the name */
|
||||
strcpy(daemon->namebuff, file);
|
||||
if (file != daemon->namebuff)
|
||||
strcpy(daemon->namebuff, file);
|
||||
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
|
||||
}
|
||||
|
||||
|
||||
+227
-44
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -21,24 +21,51 @@
|
||||
#include <libubus.h>
|
||||
|
||||
static struct blob_buf b;
|
||||
static int notify;
|
||||
static int error_logged = 0;
|
||||
|
||||
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
enum {
|
||||
SET_CONNMARK_ALLOWLIST_MARK,
|
||||
SET_CONNMARK_ALLOWLIST_MASK,
|
||||
SET_CONNMARK_ALLOWLIST_PATTERNS
|
||||
};
|
||||
static const struct blobmsg_policy set_connmark_allowlist_policy[] = {
|
||||
[SET_CONNMARK_ALLOWLIST_MARK] = {
|
||||
.name = "mark",
|
||||
.type = BLOBMSG_TYPE_INT32
|
||||
},
|
||||
[SET_CONNMARK_ALLOWLIST_MASK] = {
|
||||
.name = "mask",
|
||||
.type = BLOBMSG_TYPE_INT32
|
||||
},
|
||||
[SET_CONNMARK_ALLOWLIST_PATTERNS] = {
|
||||
.name = "patterns",
|
||||
.type = BLOBMSG_TYPE_ARRAY
|
||||
}
|
||||
};
|
||||
static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
#endif
|
||||
|
||||
static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj);
|
||||
|
||||
static const struct ubus_method ubus_object_methods[] = {
|
||||
UBUS_METHOD_NOARG("metrics", ubus_handle_metrics),
|
||||
#ifdef HAVE_CONNTRACK
|
||||
UBUS_METHOD("set_connmark_allowlist", ubus_handle_set_connmark_allowlist, set_connmark_allowlist_policy),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct ubus_object_type ubus_object_type =
|
||||
UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
|
||||
|
||||
static struct ubus_object ubus_object = {
|
||||
.name = "dnsmasq",
|
||||
.name = NULL,
|
||||
.type = &ubus_object_type,
|
||||
.methods = ubus_object_methods,
|
||||
.n_methods = ARRAY_SIZE(ubus_object_methods),
|
||||
@@ -50,17 +77,16 @@ static void ubus_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
|
||||
(void)ctx;
|
||||
|
||||
my_syslog(LOG_DEBUG, _("UBus subscription callback: %s subscriber(s)"), obj->has_subscribers ? "1" : "0");
|
||||
notify = obj->has_subscribers;
|
||||
}
|
||||
|
||||
static void ubus_destroy(struct ubus_context *ubus)
|
||||
{
|
||||
// Forces re-initialization when we're reusing the same definitions later on.
|
||||
ubus_object.id = 0;
|
||||
ubus_object_type.id = 0;
|
||||
|
||||
ubus_free(ubus);
|
||||
daemon->ubus = NULL;
|
||||
|
||||
/* Forces re-initialization when we're reusing the same definitions later on. */
|
||||
ubus_object.id = 0;
|
||||
ubus_object_type.id = 0;
|
||||
}
|
||||
|
||||
static void ubus_disconnect_cb(struct ubus_context *ubus)
|
||||
@@ -76,40 +102,27 @@ static void ubus_disconnect_cb(struct ubus_context *ubus)
|
||||
}
|
||||
}
|
||||
|
||||
void ubus_init()
|
||||
char *ubus_init()
|
||||
{
|
||||
struct ubus_context *ubus = NULL;
|
||||
int ret = 0;
|
||||
|
||||
ubus = ubus_connect(NULL);
|
||||
if (!ubus)
|
||||
{
|
||||
if (!error_logged)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Cannot initialize UBus: connection failed"));
|
||||
error_logged = 1;
|
||||
}
|
||||
|
||||
ubus_destroy(ubus);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(ubus = ubus_connect(NULL)))
|
||||
return NULL;
|
||||
|
||||
ubus_object.name = daemon->ubus_name;
|
||||
ret = ubus_add_object(ubus, &ubus_object);
|
||||
if (ret)
|
||||
{
|
||||
if (!error_logged)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Cannot add object to UBus: %s"), ubus_strerror(ret));
|
||||
error_logged = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ubus_destroy(ubus);
|
||||
return (char *)ubus_strerror(ret);
|
||||
}
|
||||
|
||||
ubus->connection_lost = ubus_disconnect_cb;
|
||||
daemon->ubus = ubus;
|
||||
error_logged = 0;
|
||||
|
||||
my_syslog(LOG_INFO, _("Connected to system UBus"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_ubus_listeners()
|
||||
@@ -158,6 +171,16 @@ void check_ubus_listeners()
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK(stmt) \
|
||||
do { \
|
||||
int e = (stmt); \
|
||||
if (e) \
|
||||
{ \
|
||||
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
|
||||
return (UBUS_STATUS_UNKNOWN_ERROR); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
@@ -168,36 +191,196 @@ static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj
|
||||
(void)method;
|
||||
(void)msg;
|
||||
|
||||
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
||||
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
|
||||
|
||||
for (i=0; i < __METRIC_MAX; i++)
|
||||
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
|
||||
CHECK(blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]));
|
||||
|
||||
return ubus_send_reply(ctx, req, b.head);
|
||||
CHECK(ubus_send_reply(ctx, req, b.head));
|
||||
return UBUS_STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
static int ubus_handle_set_connmark_allowlist(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
const struct blobmsg_policy *policy = set_connmark_allowlist_policy;
|
||||
size_t policy_len = countof(set_connmark_allowlist_policy);
|
||||
struct allowlist *allowlists = NULL, **allowlists_pos;
|
||||
char **patterns = NULL, **patterns_pos;
|
||||
u32 mark, mask = UINT32_MAX;
|
||||
size_t num_patterns = 0;
|
||||
struct blob_attr *tb[policy_len];
|
||||
struct blob_attr *attr;
|
||||
|
||||
if (blobmsg_parse(policy, policy_len, tb, blob_data(msg), blob_len(msg)))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (!tb[SET_CONNMARK_ALLOWLIST_MARK])
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
mark = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MARK]);
|
||||
if (!mark)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
|
||||
if (tb[SET_CONNMARK_ALLOWLIST_MASK])
|
||||
{
|
||||
mask = blobmsg_get_u32(tb[SET_CONNMARK_ALLOWLIST_MASK]);
|
||||
if (!mask || (mark & ~mask))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
|
||||
{
|
||||
struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
|
||||
size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
|
||||
__blob_for_each_attr(attr, head, len)
|
||||
{
|
||||
char *pattern;
|
||||
if (blob_id(attr) != BLOBMSG_TYPE_STRING)
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
if (!(pattern = blobmsg_get_string(attr)))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
if (strcmp(pattern, "*") && !is_valid_dns_name_pattern(pattern))
|
||||
return UBUS_STATUS_INVALID_ARGUMENT;
|
||||
num_patterns++;
|
||||
}
|
||||
}
|
||||
|
||||
for (allowlists_pos = &daemon->allowlists; *allowlists_pos; allowlists_pos = &(*allowlists_pos)->next)
|
||||
if ((*allowlists_pos)->mark == mark && (*allowlists_pos)->mask == mask)
|
||||
{
|
||||
struct allowlist *allowlists_next = (*allowlists_pos)->next;
|
||||
for (patterns_pos = (*allowlists_pos)->patterns; *patterns_pos; patterns_pos++)
|
||||
{
|
||||
free(*patterns_pos);
|
||||
*patterns_pos = NULL;
|
||||
}
|
||||
free((*allowlists_pos)->patterns);
|
||||
(*allowlists_pos)->patterns = NULL;
|
||||
free(*allowlists_pos);
|
||||
*allowlists_pos = allowlists_next;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!num_patterns)
|
||||
return UBUS_STATUS_OK;
|
||||
|
||||
patterns = whine_malloc((num_patterns + 1) * sizeof(char *));
|
||||
if (!patterns)
|
||||
goto fail;
|
||||
patterns_pos = patterns;
|
||||
if (tb[SET_CONNMARK_ALLOWLIST_PATTERNS])
|
||||
{
|
||||
struct blob_attr *head = blobmsg_data(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
|
||||
size_t len = blobmsg_data_len(tb[SET_CONNMARK_ALLOWLIST_PATTERNS]);
|
||||
__blob_for_each_attr(attr, head, len)
|
||||
{
|
||||
char *pattern;
|
||||
if (!(pattern = blobmsg_get_string(attr)))
|
||||
goto fail;
|
||||
if (!(*patterns_pos = whine_malloc(strlen(pattern) + 1)))
|
||||
goto fail;
|
||||
strcpy(*patterns_pos++, pattern);
|
||||
}
|
||||
}
|
||||
|
||||
allowlists = whine_malloc(sizeof(struct allowlist));
|
||||
if (!allowlists)
|
||||
goto fail;
|
||||
memset(allowlists, 0, sizeof(struct allowlist));
|
||||
allowlists->mark = mark;
|
||||
allowlists->mask = mask;
|
||||
allowlists->patterns = patterns;
|
||||
allowlists->next = daemon->allowlists;
|
||||
daemon->allowlists = allowlists;
|
||||
return UBUS_STATUS_OK;
|
||||
|
||||
fail:
|
||||
if (patterns)
|
||||
{
|
||||
for (patterns_pos = patterns; *patterns_pos; patterns_pos++)
|
||||
{
|
||||
free(*patterns_pos);
|
||||
*patterns_pos = NULL;
|
||||
}
|
||||
free(patterns);
|
||||
patterns = NULL;
|
||||
}
|
||||
if (allowlists)
|
||||
{
|
||||
free(allowlists);
|
||||
allowlists = NULL;
|
||||
}
|
||||
return UBUS_STATUS_UNKNOWN_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CHECK
|
||||
|
||||
#define CHECK(stmt) \
|
||||
do { \
|
||||
int e = (stmt); \
|
||||
if (e) \
|
||||
{ \
|
||||
my_syslog(LOG_ERR, _("UBus command failed: %d (%s)"), e, #stmt); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
int ret;
|
||||
|
||||
if (!ubus || !notify)
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, BLOBMSG_TYPE_TABLE);
|
||||
CHECK(blob_buf_init(&b, BLOBMSG_TYPE_TABLE));
|
||||
if (mac)
|
||||
blobmsg_add_string(&b, "mac", mac);
|
||||
CHECK(blobmsg_add_string(&b, "mac", mac));
|
||||
if (ip)
|
||||
blobmsg_add_string(&b, "ip", ip);
|
||||
CHECK(blobmsg_add_string(&b, "ip", ip));
|
||||
if (name)
|
||||
blobmsg_add_string(&b, "name", name);
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
if (interface)
|
||||
blobmsg_add_string(&b, "interface", interface);
|
||||
CHECK(blobmsg_add_string(&b, "interface", interface));
|
||||
|
||||
ret = ubus_notify(ubus, &ubus_object, type, b.head, -1);
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("Failed to send UBus event: %s"), ubus_strerror(ret));
|
||||
CHECK(ubus_notify(ubus, &ubus_object, type, b.head, -1));
|
||||
}
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
void ubus_event_bcast_connmark_allowlist_refused(u32 mark, const char *name)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
CHECK(blob_buf_init(&b, 0));
|
||||
CHECK(blobmsg_add_u32(&b, "mark", mark));
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
|
||||
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.refused", b.head, -1));
|
||||
}
|
||||
|
||||
void ubus_event_bcast_connmark_allowlist_resolved(u32 mark, const char *name, const char *value, u32 ttl)
|
||||
{
|
||||
struct ubus_context *ubus = (struct ubus_context *)daemon->ubus;
|
||||
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
CHECK(blob_buf_init(&b, 0));
|
||||
CHECK(blobmsg_add_u32(&b, "mark", mark));
|
||||
CHECK(blobmsg_add_string(&b, "name", name));
|
||||
CHECK(blobmsg_add_string(&b, "value", value));
|
||||
CHECK(blobmsg_add_u32(&b, "ttl", ttl));
|
||||
|
||||
/* Set timeout to allow UBus subscriber to configure firewall rules before returning. */
|
||||
CHECK(ubus_notify(ubus, &ubus_object, "connmark-allowlist.resolved", b.head, /* timeout: */ 1000));
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CHECK
|
||||
|
||||
#endif /* HAVE_UBUS */
|
||||
+83
-31
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2021 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
|
||||
@@ -30,6 +30,10 @@
|
||||
#include <idna.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
static u32 seed[32];
|
||||
@@ -111,7 +115,8 @@ u64 rand64(void)
|
||||
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
|
||||
}
|
||||
|
||||
/* returns 2 if names is OK but contains one or more underscores */
|
||||
/* returns 1 if name is OK and ascii printable
|
||||
* returns 2 if name should be processed by IDN */
|
||||
static int check_name(char *in)
|
||||
{
|
||||
/* remove trailing .
|
||||
@@ -119,7 +124,9 @@ static int check_name(char *in)
|
||||
size_t dotgap = 0, l = strlen(in);
|
||||
char c;
|
||||
int nowhite = 0;
|
||||
int idn_encode = 0;
|
||||
int hasuscore = 0;
|
||||
int hasucase = 0;
|
||||
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
@@ -132,28 +139,49 @@ static int check_name(char *in)
|
||||
for (; (c = *in); in++)
|
||||
{
|
||||
if (c == '.')
|
||||
dotgap = 0;
|
||||
dotgap = 0;
|
||||
else if (++dotgap > MAXLABEL)
|
||||
return 0;
|
||||
return 0;
|
||||
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
else if (!isascii((unsigned char)c))
|
||||
return 0;
|
||||
#if !defined(HAVE_IDN) && !defined(HAVE_LIBIDN2)
|
||||
return 0;
|
||||
#else
|
||||
idn_encode = 1;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
{
|
||||
nowhite = 1;
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
}
|
||||
{
|
||||
nowhite = 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
#else
|
||||
(void)hasuscore;
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
hasucase = 1;
|
||||
#else
|
||||
(void)hasucase;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!nowhite)
|
||||
return 0;
|
||||
|
||||
return hasuscore ? 2 : 1;
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* Older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore unless it also has non-ascii characters. */
|
||||
idn_encode = idn_encode || (hasucase && !hasuscore);
|
||||
#else
|
||||
idn_encode = idn_encode || hasucase;
|
||||
#endif
|
||||
|
||||
return (idn_encode) ? 2 : 1;
|
||||
}
|
||||
|
||||
/* Hostnames have a more limited valid charset than domain names
|
||||
@@ -200,17 +228,11 @@ char *canonicalise(char *in, int *nomem)
|
||||
if (!(rc = check_name(in)))
|
||||
return NULL;
|
||||
|
||||
#if defined(HAVE_LIBIDN2) && (!defined(IDN2_VERSION_NUMBER) || IDN2_VERSION_NUMBER < 0x02000003)
|
||||
/* older libidn2 strips underscores, so don't do IDN processing
|
||||
if the name has an underscore (check_name() returned 2) */
|
||||
if (rc != 2)
|
||||
#endif
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
if (rc == 2)
|
||||
{
|
||||
# ifdef HAVE_LIBIDN2
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
|
||||
if (rc == IDN2_DISALLOWED)
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
|
||||
# else
|
||||
rc = idna_to_ascii_lz(in, &ret, 0);
|
||||
# endif
|
||||
@@ -230,12 +252,14 @@ char *canonicalise(char *in, int *nomem)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
(void)rc;
|
||||
#endif
|
||||
|
||||
if ((ret = whine_malloc(strlen(in)+1)))
|
||||
strcpy(ret, in);
|
||||
else if (nomem)
|
||||
*nomem = 1;
|
||||
*nomem = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -312,7 +336,7 @@ void *whine_malloc(size_t size)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
|
||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
||||
{
|
||||
if (s1->sa.sa_family == s2->sa.sa_family)
|
||||
{
|
||||
@@ -404,13 +428,12 @@ int hostname_issubdomain(char *a, char *b)
|
||||
time_t dnsmasq_time(void)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
struct tms dummy;
|
||||
static long tps = 0;
|
||||
struct timespec ts;
|
||||
|
||||
if (tps == 0)
|
||||
tps = sysconf(_SC_CLK_TCK);
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
||||
die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
|
||||
|
||||
return (time_t)(times(&dummy)/tps);
|
||||
return ts.tv_sec;
|
||||
#else
|
||||
return time(NULL);
|
||||
#endif
|
||||
@@ -432,7 +455,17 @@ int netmask_length(struct in_addr mask)
|
||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
||||
{
|
||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||
}
|
||||
}
|
||||
|
||||
int is_same_net_prefix(struct in_addr a, struct in_addr b, int prefix)
|
||||
{
|
||||
struct in_addr mask;
|
||||
|
||||
mask.s_addr = htonl(~((1 << (32 - prefix)) - 1));
|
||||
|
||||
return is_same_net(a, b, mask);
|
||||
}
|
||||
|
||||
|
||||
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||
{
|
||||
@@ -514,7 +547,7 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%um", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&buf[p], "%us", x);
|
||||
sprintf(&buf[p], "%us", x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +593,7 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
int j, bytes = (1 + (r - in))/2;
|
||||
for (j = 0; j < bytes; j++)
|
||||
{
|
||||
char sav = sav;
|
||||
char sav;
|
||||
if (j < bytes - 1)
|
||||
{
|
||||
sav = in[(j+1)*2];
|
||||
@@ -782,3 +815,22 @@ int wildcard_matchn(const char* wildcard, const char* match, int num)
|
||||
|
||||
return (!num) || (*wildcard == *match);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
int kernel_version(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, ".");
|
||||
return version * 256 + (split ? atoi(split) : 0);
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user