Compare commits
172 Commits
v2.78test2
...
v2.80test8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1791f36ea | ||
|
|
0fdf3c1f61 | ||
|
|
ee1df06aab | ||
|
|
1e87eba424 | ||
|
|
08933475ab | ||
|
|
7cbf497da4 | ||
|
|
3a610a007f | ||
|
|
48b090cb5c | ||
|
|
4139298d28 | ||
|
|
51cc10fa54 | ||
|
|
ea6cc33804 | ||
|
|
ad03967ee4 | ||
|
|
f4fd07d303 | ||
|
|
e3c08a34a7 | ||
|
|
118011fe2b | ||
|
|
af3bd07355 | ||
|
|
d68209978a | ||
|
|
47b45b2967 | ||
|
|
2b38e3823b | ||
|
|
282eab7952 | ||
|
|
c346f61535 | ||
|
|
03212e533b | ||
|
|
da8b6517de | ||
|
|
c5db8f93ec | ||
|
|
974a6d087a | ||
|
|
b758b67c37 | ||
|
|
9bafdc62b7 | ||
|
|
97f876b64c | ||
|
|
cbfbd173c4 | ||
|
|
b6f926fbef | ||
|
|
c822620967 | ||
|
|
397c0502e2 | ||
|
|
1682d15a74 | ||
|
|
dd33e98da0 | ||
|
|
c16d966ad3 | ||
|
|
1dfed16071 | ||
|
|
6f835ed6c8 | ||
|
|
9d6fd1727e | ||
|
|
8c1b6a5fd7 | ||
|
|
8dcdb33be9 | ||
|
|
aba8bbb6e3 | ||
|
|
caf4d571e6 | ||
|
|
3b6eb197a8 | ||
|
|
f3e57877ed | ||
|
|
c851c695db | ||
|
|
a3bd7e73d3 | ||
|
|
ab5ceaf74a | ||
|
|
1f2f69d4f6 | ||
|
|
f361b39dea | ||
|
|
eb1fe15ca8 | ||
|
|
45d8a2435e | ||
|
|
706d84fd10 | ||
|
|
a997ca0da0 | ||
|
|
9268b5d677 | ||
|
|
51e4eeeb04 | ||
|
|
05ff659a3c | ||
|
|
db0f488ea8 | ||
|
|
7dcca6c622 | ||
|
|
090856c7e6 | ||
|
|
cc5cc8f1e0 | ||
|
|
c488b68e75 | ||
|
|
1f1873aadd | ||
|
|
0a496f059c | ||
|
|
e27825b0ef | ||
|
|
1f60a18ea1 | ||
|
|
a0088e8364 | ||
|
|
34e26e14c5 | ||
|
|
6b17335209 | ||
|
|
07ed585c38 | ||
|
|
0669ee7a69 | ||
|
|
f84e674d8a | ||
|
|
7f0084316a | ||
|
|
a6918530ce | ||
|
|
4e72fec660 | ||
|
|
4441cf762c | ||
|
|
e83915d10d | ||
|
|
6d37924b86 | ||
|
|
f3d7974e86 | ||
|
|
734d53176f | ||
|
|
9a7be47614 | ||
|
|
26e27d0015 | ||
|
|
94b6878821 | ||
|
|
8b96552f0d | ||
|
|
ae290659de | ||
|
|
6b2b564ac3 | ||
|
|
4f7bb57e97 | ||
|
|
56f0623930 | ||
|
|
f3223fbff6 | ||
|
|
4c4f4c2649 | ||
|
|
773af304ea | ||
|
|
4cc944b0d6 | ||
|
|
87e00feb01 | ||
|
|
e7a4af8903 | ||
|
|
2d69d6146d | ||
|
|
30e4a9441e | ||
|
|
232a8f3569 | ||
|
|
1721453d51 | ||
|
|
499d8dde2b | ||
|
|
6f1cbfd000 | ||
|
|
55ecde7f1b | ||
|
|
6b54d69a85 | ||
|
|
246a31cd73 | ||
|
|
83e4b73596 | ||
|
|
6340ca734f | ||
|
|
baf553db0c | ||
|
|
486bcd5a7b | ||
|
|
be9a74d2f8 | ||
|
|
ffcbc0f011 | ||
|
|
a969ba6e2a | ||
|
|
f1781728af | ||
|
|
cd7df612b1 | ||
|
|
c1a4e257a3 | ||
|
|
4fe6744a22 | ||
|
|
3bd4c47f31 | ||
|
|
98196c4931 | ||
|
|
22cd860124 | ||
|
|
3c973ad92d | ||
|
|
faaf306a63 | ||
|
|
c7e6aea81b | ||
|
|
e541245987 | ||
|
|
84a01bee10 | ||
|
|
d1ced3ae38 | ||
|
|
a6cee69af4 | ||
|
|
0039920ab6 | ||
|
|
39d8550a80 | ||
|
|
ef3d137a64 | ||
|
|
8c707e1e37 | ||
|
|
373e917389 | ||
|
|
74f0f9a042 | ||
|
|
ed6bdb0967 | ||
|
|
c88af046b7 | ||
|
|
ae0187d454 | ||
|
|
0c50e3ddc8 | ||
|
|
075366ad6e | ||
|
|
8e8b2d6f63 | ||
|
|
087eb76140 | ||
|
|
ebedcbaeb8 | ||
|
|
0954a977c9 | ||
|
|
b77efc1948 | ||
|
|
3b0cb34710 | ||
|
|
aa6f832d61 | ||
|
|
ad9c6f06c5 | ||
|
|
a6004d7f17 | ||
|
|
c366717e66 | ||
|
|
22dee512f3 | ||
|
|
6fd5d79e73 | ||
|
|
9d6918d32c | ||
|
|
a49c5c2265 | ||
|
|
30858e3b9b | ||
|
|
30df7efc96 | ||
|
|
3e8c42cba5 | ||
|
|
62cb936cb7 | ||
|
|
39921d03ba | ||
|
|
6a0b00f0d6 | ||
|
|
51eadb692a | ||
|
|
897c113fda | ||
|
|
33e3f1029c | ||
|
|
3d4ff1ba84 | ||
|
|
24036ea507 | ||
|
|
0549c73b7e | ||
|
|
b697fbb7f1 | ||
|
|
96e063c43d | ||
|
|
4e841da1a6 | ||
|
|
09ce307bdb | ||
|
|
a3303e196e | ||
|
|
63437ffbb5 | ||
|
|
69a815aa8f | ||
|
|
1d224949cc | ||
|
|
391f708a09 | ||
|
|
cbd29e5da8 | ||
|
|
50a2841d34 | ||
|
|
9396752c11 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,9 +7,8 @@ src/.copts_*
|
||||
contrib/lease-tools/dhcp_lease_time
|
||||
contrib/lease-tools/dhcp_release
|
||||
contrib/lease-tools/dhcp_release6
|
||||
debian/base/
|
||||
debian/daemon/
|
||||
debian/files
|
||||
debian/substvars
|
||||
debian/utils-substvars
|
||||
debian/utils/
|
||||
debian/trees/
|
||||
debian/build/
|
||||
|
||||
213
CHANGELOG
213
CHANGELOG
@@ -1,3 +1,140 @@
|
||||
version 2.80
|
||||
Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method
|
||||
for the initial patch and motivation.
|
||||
|
||||
Alter the default for dnssec-check-unsigned. Versions of
|
||||
dnsmasq prior to 2.80 defaulted to not checking unsigned
|
||||
replies, and used --dnssec-check-unsigned to switch
|
||||
this on. Such configurations will continue to work as before,
|
||||
but those which used the default of no checking will need to be
|
||||
altered to explicitly select no checking. The new default is
|
||||
because switching off checking for unsigned replies is
|
||||
inherently dangerous. Not only does it open the possiblity of forged
|
||||
replies, but it allows everything to appear to be working even
|
||||
when the upstream namesevers do not support DNSSEC, and in this
|
||||
case no DNSSEC validation at all is occuring.
|
||||
|
||||
Fix DHCP broken-ness when --no-ping AND --dhcp-sequential-ip
|
||||
are set. Thanks to Daniel Miess for help with this.
|
||||
|
||||
Add a facilty to store DNS packets sent/recieved in a
|
||||
pcap-format file for later debugging. The file location
|
||||
is given by the --dumpfile option, and a bitmap controlling
|
||||
which packets should be dumped is given by the --dumpmask
|
||||
option.
|
||||
|
||||
Handle the case of both standard and constructed dhcp-ranges on the
|
||||
same interface better. We don't now contruct a dhcp-range if there's
|
||||
already one specified. This allows the specified interface to
|
||||
have different parameters and avoids advertising the same
|
||||
prefix twice. Thanks to Luis Marsano for spotting this case.
|
||||
|
||||
Allow zone transfer in authoritative mode if auth-peer is specified,
|
||||
even if auth-sec-servers is not. Thanks to Raphaël Halimi for
|
||||
the suggestion.
|
||||
|
||||
Fix bug which sometimes caused dnsmasq to wrongly return answers
|
||||
without DNSSEC RRs to queries with the do-bit set, but only when
|
||||
DNSSEC validation was not enabled.
|
||||
Thanks to Petr Menšík for spotting this.
|
||||
|
||||
Fix missing fatal errors with some malformed options
|
||||
(server, local, address, rebind-domain-ok, ipset, alias).
|
||||
Thanks to Eugene Lozovoy for spotting the problem.
|
||||
|
||||
Fix crash on startup with a --synth-domain which has no prefix.
|
||||
Introduced in 2.79. Thanks to Andreas Engel for the bug report.
|
||||
|
||||
Fix missing EDNS0 section in some replies generated by local
|
||||
DNS configuration which confused systemd-resolvd. Thanks to
|
||||
Steve Dodd for characterising the problem.
|
||||
|
||||
Add --dhcp-name-match config option.
|
||||
|
||||
Add --caa-record config option.
|
||||
|
||||
Implement --address=/example.com/# as (more efficient) syntactic
|
||||
sugar for --address=/example.com/0.0.0.0 and
|
||||
--address=/example.com/::
|
||||
Returning null addresses is a useful technique for ad-blocking.
|
||||
Thanks to Peter Russell for the suggestion.
|
||||
|
||||
Change anti cache-snooping behaviour with queries with the
|
||||
recursion-desired bit unset. Instead to returning SERVFAIL, we
|
||||
now always forward, and never answer from the cache. This
|
||||
allows "dig +trace" command to work.
|
||||
|
||||
Include in the example config file a formulation which
|
||||
stops DHCP clients from claiming the DNS name "wpad".
|
||||
This is a fix for the CERT Vulnerability VU#598349.
|
||||
|
||||
|
||||
version 2.79
|
||||
Fix parsing of CNAME arguments, which are confused by extra spaces.
|
||||
Thanks to Diego Aguirre for spotting the bug.
|
||||
|
||||
Where available, use IP_UNICAST_IF or IPV6_UNICAST_IF to bind
|
||||
upstream servers to an interface, rather than SO_BINDTODEVICE.
|
||||
Thanks to Beniamino Galvani for the patch.
|
||||
|
||||
Always return a SERVFAIL answer to DNS queries without the
|
||||
recursion desired bit set, UNLESS acting as an authoritative
|
||||
DNS server. This avoids a potential route to cache snooping.
|
||||
|
||||
Add support for Ed25519 signatures in DNSSEC validation.
|
||||
|
||||
No longer support RSA/MD5 signatures in DNSSEC validation,
|
||||
since these are not secure. This behaviour is mandated in
|
||||
RFC-6944.
|
||||
|
||||
Fix incorrect error exit code from dhcp_release6 utility.
|
||||
Thanks Gaudenz Steinlin for the bug report.
|
||||
|
||||
Use SIGINT (instead of overloading SIGHUP) to turn on DNSSEC
|
||||
time validation when --dnssec-no-timecheck is in use.
|
||||
Note that this is an incompatible change from earlier releases.
|
||||
|
||||
Allow more than one --bridge-interface option to refer to an
|
||||
interface, so that we can use
|
||||
--bridge-interface=int1,alias1
|
||||
--bridge-interface=int1,alias2
|
||||
as an alternative to
|
||||
--bridge-interface=int1,alias1,alias2
|
||||
Thanks to Neil Jerram for work on this.
|
||||
|
||||
Fix for DNSSEC with wildcard-derived NSEC records.
|
||||
It's OK for NSEC records to be expanded from wildcards,
|
||||
but in that case, the proof of non-existence is only valid
|
||||
starting at the wildcard name, *.<domain> NOT the name expanded
|
||||
from the wildcard. Without this check it's possible for an
|
||||
attacker to craft an NSEC which wrongly proves non-existence.
|
||||
Thanks to Ralph Dolmans for finding this, and co-ordinating
|
||||
the vulnerability tracking and fix release.
|
||||
CVE-2017-15107 applies.
|
||||
|
||||
Remove special handling of A-for-A DNS queries. These
|
||||
are no longer a significant problem in the global DNS.
|
||||
http://cs.northwestern.edu/~ychen/Papers/DNS_ToN15.pdf
|
||||
Thanks to Mattias Hellström for the initial patch.
|
||||
|
||||
Fix failure to delete dynamically created dhcp options
|
||||
from files in -dhcp-optsdir directories. Thanks to
|
||||
Lindgren Fredrik for the bug report.
|
||||
|
||||
Add to --synth-domain the ability to create names using
|
||||
sequential numbers, as well as encodings of IP addresses.
|
||||
For instance,
|
||||
--synth-domain=thekelleys.org.uk,192.168.0.50,192.168.0.70,internal-*
|
||||
creates 21 domain names of the form
|
||||
internal-4.thekelleys.org.uk over the address range given, with
|
||||
internal-0.thekelleys.org.uk being 192.168.0.50 and
|
||||
internal-20.thekelleys.org.uk being 192.168.0.70
|
||||
Thanks to Andy Hawkins for the suggestion.
|
||||
|
||||
Tidy up Crypto code, removing workarounds for ancient
|
||||
versions of libnettle. We now require libnettle 3.
|
||||
|
||||
|
||||
version 2.78
|
||||
Fix logic of appending ".<layer>" to PXE basename. Thanks to Chris
|
||||
Novakovic for the patch.
|
||||
@@ -13,6 +150,76 @@ version 2.78
|
||||
ff325644c7afae2588583f935f4ea9b9694eb52e. Thanks to
|
||||
John Fitzgibbon for the diagnosis and patch.
|
||||
|
||||
Try other servers if first returns REFUSED when
|
||||
--strict-order active. Thanks to Hans Dedecker
|
||||
for the patch
|
||||
|
||||
Fix regression in 2.77, ironically added as a security
|
||||
improvement, which resulted in a crash when a DNS
|
||||
query exceeded 512 bytes (or the EDNS0 packet size,
|
||||
if different.) Thanks to Christian Kujau, Arne Woerner
|
||||
Juan Manuel Fernandez and Kevin Darbyshire-Bryant for
|
||||
chasing this one down. CVE-2017-13704 applies.
|
||||
|
||||
Fix heap overflow in DNS code. This is a potentially serious
|
||||
security hole. It allows an attacker who can make DNS
|
||||
requests to dnsmasq, and who controls the contents of
|
||||
a domain, which is thereby queried, to overflow
|
||||
(by 2 bytes) a heap buffer and either crash, or
|
||||
even take control of, dnsmasq.
|
||||
CVE-2017-14491 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
Kevin Hamacher and Ron Bowes of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
Fix heap overflow in IPv6 router advertisement code.
|
||||
This is a potentially serious security hole, as a
|
||||
crafted RA request can overflow a buffer and crash or
|
||||
control dnsmasq. Attacker must be on the local network.
|
||||
CVE-2017-14492 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
and Kevin Hamacher of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
Fix stack overflow in DHCPv6 code. An attacker who can send
|
||||
a DHCPv6 request to dnsmasq can overflow the stack frame and
|
||||
crash or control dnsmasq.
|
||||
CVE-2017-14493 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
Kevin Hamacher and Ron Bowes of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
Fix information leak in DHCPv6. A crafted DHCPv6 packet can
|
||||
cause dnsmasq to forward memory from outside the packet
|
||||
buffer to a DHCPv6 server when acting as a relay.
|
||||
CVE-2017-14494 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
Kevin Hamacher and Ron Bowes of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
Fix DoS in DNS. Invalid boundary checks in the
|
||||
add_pseudoheader function allows a memcpy call with negative
|
||||
size An attacker which can send malicious DNS queries
|
||||
to dnsmasq can trigger a DoS remotely.
|
||||
dnsmasq is vulnerable only if one of the following option is
|
||||
specified: --add-mac, --add-cpe-id or --add-subnet.
|
||||
CVE-2017-14496 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
Kevin Hamacher and Ron Bowes of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
Fix out-of-memory Dos vulnerability. An attacker which can
|
||||
send malicious DNS queries to dnsmasq can trigger memory
|
||||
allocations in the add_pseudoheader function
|
||||
The allocated memory is never freed which leads to a DoS
|
||||
through memory exhaustion. dnsmasq is vulnerable only
|
||||
if one of the following option is specified:
|
||||
--add-mac, --add-cpe-id or --add-subnet.
|
||||
CVE-2017-14495 applies.
|
||||
Credit to Felix Wilhelm, Fermin J. Serna, Gabriel Campana
|
||||
Kevin Hamacher and Ron Bowes of the Google Security Team for
|
||||
finding this.
|
||||
|
||||
|
||||
version 2.77
|
||||
Generate an error when configured with a CNAME loop,
|
||||
@@ -1456,7 +1663,7 @@ version 2.56
|
||||
|
||||
By default, setting an IPv4 address for a domain but not
|
||||
an IPv6 address causes dnsmasq to return
|
||||
an NODATA reply for IPv6 (or vice-versa). So
|
||||
a NODATA reply for IPv6 (or vice-versa). So
|
||||
--address=/google.com/1.2.3.4 stops IPv6 queries for
|
||||
*google.com from being forwarded. Make it possible to
|
||||
override this behaviour by defining the semantics if the
|
||||
@@ -1962,13 +2169,13 @@ version 2.47
|
||||
|
||||
Support arbitrarily encapsulated DHCP options, suggestion
|
||||
and initial patch from Samium Gromoff. This is useful for
|
||||
(eg) gPXE, which expect all its private options to be
|
||||
(eg) iPXE, which expect all its private options to be
|
||||
encapsulated inside a single option 175. So, eg,
|
||||
|
||||
dhcp-option = encap:175, 190, "iscsi-client0"
|
||||
dhcp-option = encap:175, 191, "iscsi-client0-secret"
|
||||
|
||||
will provide iSCSI parameters to gPXE.
|
||||
will provide iSCSI parameters to iPXE.
|
||||
|
||||
Enhance --dhcp-match to allow testing of the contents of a
|
||||
client-sent option, as well as its presence. This
|
||||
|
||||
@@ -1010,7 +1010,7 @@ release 2.9
|
||||
but to the address of another interface were ignored
|
||||
unless the loopback interface was explicitly configured.
|
||||
2) on OpenBSD failure to configure one interface now
|
||||
causes a fatal error on startup rather than an huge
|
||||
causes a fatal error on startup rather than a huge
|
||||
stream of log messages. Thanks to Erik Jan Tromp for
|
||||
finding that bug.
|
||||
|
||||
@@ -2067,7 +2067,7 @@ version 2.36
|
||||
kernel. Thanks to Philip Wall for the bug report.
|
||||
|
||||
Added --dhcp-bridge option, but only to the FreeBSD
|
||||
build. This fixes an oddity with a a particular bridged
|
||||
build. This fixes an oddity with a particular bridged
|
||||
network configuration on FreeBSD. Thanks to Luigi Rizzo
|
||||
for the patch.
|
||||
|
||||
@@ -2273,7 +2273,7 @@ version 2.40
|
||||
this.
|
||||
|
||||
Use client-id as hash-seed for DHCP address allocation
|
||||
with Firewire and InfiniBand, as these don't supply an MAC
|
||||
with Firewire and InfiniBand, as these don't supply a MAC
|
||||
address.
|
||||
|
||||
Tweaked TFTP file-open code to make it behave sensibly
|
||||
@@ -2433,7 +2433,7 @@ version 2.41
|
||||
|
||||
Add --dhcp-match flag, to check for arbitrary options in
|
||||
DHCP messages from clients. This enables use of dnsmasq
|
||||
with gPXE. Thanks to Rance Hall for the suggestion.
|
||||
with iPXE. Thanks to Rance Hall for the suggestion.
|
||||
|
||||
Added --dhcp-broadcast, to force broadcast replies to DHCP
|
||||
clients which need them but are too dumb or too old to
|
||||
|
||||
6
FAQ
6
FAQ
@@ -9,7 +9,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
from port 53 the replies would be _to_ port 53 and get blocked.
|
||||
|
||||
This is not a security hole since dnsmasq will only accept replies to that
|
||||
port: queries are dropped. The replies must be to oustanding queries
|
||||
port: queries are dropped. The replies must be to outstanding queries
|
||||
which dnsmasq has forwarded, otherwise they are dropped too.
|
||||
|
||||
Addendum: dnsmasq now has the option "query-port" (-Q), which allows
|
||||
@@ -297,7 +297,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
|
||||
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
|
||||
mode, such interfaces are handled normally.
|
||||
|
||||
A --interface specification for a non-existent interface is a fatal
|
||||
An --interface specification for a non-existent interface is a fatal
|
||||
error at start-up when in --bind-interfaces mode, by just generates a
|
||||
warning in wildcard or bind-dynamic mode.
|
||||
|
||||
@@ -320,7 +320,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
||||
|
||||
Q: What does the dhcp-authoritative option do?
|
||||
|
||||
A: The DHCP spec says that when a DHCP server recieves a renewal request
|
||||
A: The DHCP spec says that when a DHCP server receives a renewal request
|
||||
from a client it has no knowledge of, it should just ignore it.
|
||||
This is because it's supported to have more than one DHCP server
|
||||
on a network, and another DHCP server may be dealing with the client.
|
||||
|
||||
10
Makefile
10
Makefile
@@ -53,6 +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 $(PKG_CONFIG) --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`
|
||||
@@ -76,16 +77,16 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
|
||||
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
|
||||
poll.o rrfilter.o edns0.o arp.o
|
||||
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o metrics.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h ip6addr.h
|
||||
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
|
||||
|
||||
all : $(BUILDDIR)
|
||||
@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)" \
|
||||
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs)" \
|
||||
-f $(top)/Makefile dnsmasq
|
||||
|
||||
mostly_clean :
|
||||
@@ -100,7 +101,8 @@ clean : mostly_clean
|
||||
install : all install-common
|
||||
|
||||
install-common :
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c domain.c \
|
||||
dnssec.c dnssec-openssl.c blockdata.c tables.c \
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c
|
||||
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
|
||||
crypto.c dump.c ubus.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
|
||||
if (p >= end - 2)
|
||||
return NULL; /* malformed packet */
|
||||
opt_len = option_len(p);
|
||||
if (p >= end - (2 + opt_len))
|
||||
if (end - p >= (2 + opt_len))
|
||||
return NULL; /* malformed packet */
|
||||
if (*p == opt && opt_len >= minsize)
|
||||
return p;
|
||||
@@ -206,13 +206,13 @@ int main(int argc, char **argv)
|
||||
{
|
||||
unsigned int x;
|
||||
if ((x = t/86400))
|
||||
printf("%dd", x);
|
||||
printf("%ud", x);
|
||||
if ((x = (t/3600)%24))
|
||||
printf("%dh", x);
|
||||
printf("%uh", x);
|
||||
if ((x = (t/60)%60))
|
||||
printf("%dm", x);
|
||||
printf("%um", x);
|
||||
if ((x = t%60))
|
||||
printf("%ds", x);
|
||||
printf("%us", x);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,7 +270,8 @@ int main(int argc, char **argv)
|
||||
|
||||
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
|
||||
a DHCP server */
|
||||
strcpy(ifr.ifr_name, argv[1]);
|
||||
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
|
||||
{
|
||||
perror("cannot setup interface");
|
||||
|
||||
@@ -46,7 +46,8 @@ typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
enum DHCP6_TYPES{
|
||||
enum DHCP6_TYPES
|
||||
{
|
||||
SOLICIT = 1,
|
||||
ADVERTISE = 2,
|
||||
REQUEST = 3,
|
||||
@@ -61,8 +62,10 @@ enum DHCP6_TYPES{
|
||||
RELAY_FORW = 12,
|
||||
RELAY_REPL = 13
|
||||
|
||||
};
|
||||
enum DHCP6_OPTIONS{
|
||||
};
|
||||
|
||||
enum DHCP6_OPTIONS
|
||||
{
|
||||
CLIENTID = 1,
|
||||
SERVERID = 2,
|
||||
IA_NA = 3,
|
||||
@@ -82,25 +85,27 @@ enum DHCP6_OPTIONS{
|
||||
INTERFACE_ID = 18,
|
||||
RECONF_MSG = 19,
|
||||
RECONF_ACCEPT = 20,
|
||||
};
|
||||
};
|
||||
|
||||
enum DHCP6_STATUSES{
|
||||
enum DHCP6_STATUSES
|
||||
{
|
||||
SUCCESS = 0,
|
||||
UNSPEC_FAIL = 1,
|
||||
NOADDR_AVAIL=2,
|
||||
NO_BINDING = 3,
|
||||
NOT_ON_LINK = 4,
|
||||
USE_MULTICAST =5
|
||||
};
|
||||
};
|
||||
|
||||
static struct option longopts[] = {
|
||||
{"ip", required_argument, 0, 'a'},
|
||||
{"server-id", required_argument, 0, 's'},
|
||||
{"client-id", required_argument, 0, 'c'},
|
||||
{"iface", required_argument, 0, 'n'},
|
||||
{"iaid", required_argument, 0, 'i'},
|
||||
{"dry-run", no_argument, 0, 'd'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
{"ip", required_argument, 0, 'a' },
|
||||
{"server-id", required_argument, 0, 's' },
|
||||
{"client-id", required_argument, 0, 'c' },
|
||||
{"iface", required_argument, 0, 'n' },
|
||||
{"iaid", required_argument, 0, 'i' },
|
||||
{"dry-run", no_argument, 0, 'd' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
const short DHCP6_CLIENT_PORT = 546;
|
||||
@@ -108,207 +113,230 @@ const short DHCP6_SERVER_PORT = 547;
|
||||
|
||||
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
|
||||
|
||||
struct dhcp6_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
char value[1024];
|
||||
struct dhcp6_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
char value[1024];
|
||||
};
|
||||
|
||||
struct dhcp6_iaaddr_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
struct in6_addr ip;
|
||||
uint32_t preferred_lifetime;
|
||||
uint32_t valid_lifetime;
|
||||
|
||||
|
||||
struct dhcp6_iaaddr_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
struct in6_addr ip;
|
||||
uint32_t preferred_lifetime;
|
||||
uint32_t valid_lifetime;
|
||||
};
|
||||
|
||||
struct dhcp6_iana_option{
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t iaid;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
char options[1024];
|
||||
struct dhcp6_iana_option {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint32_t iaid;
|
||||
uint32_t t1;
|
||||
uint32_t t2;
|
||||
char options[1024];
|
||||
};
|
||||
|
||||
|
||||
struct dhcp6_packet{
|
||||
size_t len;
|
||||
char buf[2048];
|
||||
|
||||
} ;
|
||||
struct dhcp6_packet {
|
||||
size_t len;
|
||||
char buf[2048];
|
||||
};
|
||||
|
||||
size_t pack_duid(const char* str, char* dst){
|
||||
|
||||
char* tmp = strdup(str);
|
||||
char* tmp_to_free = tmp;
|
||||
char *ptr;
|
||||
uint8_t write_pos = 0;
|
||||
while ((ptr = strtok (tmp, ":"))) {
|
||||
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
|
||||
write_pos += 1;
|
||||
tmp = NULL;
|
||||
|
||||
size_t pack_duid(const char* str, char* dst)
|
||||
{
|
||||
char* tmp = strdup(str);
|
||||
char* tmp_to_free = tmp;
|
||||
char *ptr;
|
||||
uint8_t write_pos = 0;
|
||||
while ((ptr = strtok (tmp, ":")))
|
||||
{
|
||||
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
|
||||
write_pos += 1;
|
||||
tmp = NULL;
|
||||
}
|
||||
free(tmp_to_free);
|
||||
return write_pos;
|
||||
|
||||
free(tmp_to_free);
|
||||
return write_pos;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_client_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(CLIENTID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
struct dhcp6_option create_client_id_option(const char* duid)
|
||||
{
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(CLIENTID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_option create_server_id_option(const char* duid){
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(SERVERID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
struct dhcp6_option create_server_id_option(const char* duid)
|
||||
{
|
||||
struct dhcp6_option option;
|
||||
option.type = htons(SERVERID);
|
||||
bzero(option.value, sizeof(option.value));
|
||||
option.len = htons(pack_duid(duid, option.value));
|
||||
return option;
|
||||
}
|
||||
|
||||
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip){
|
||||
struct dhcp6_iaaddr_option result;
|
||||
result.type =htons(IAADDR);
|
||||
/* no suboptions needed here, so length is 24 */
|
||||
result.len = htons(24);
|
||||
result.preferred_lifetime = 0;
|
||||
result.valid_lifetime = 0;
|
||||
int s = inet_pton(AF_INET6, ip, &(result.ip));
|
||||
if (s <= 0) {
|
||||
if (s == 0)
|
||||
fprintf(stderr, "Not in presentation format");
|
||||
else
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr){
|
||||
struct dhcp6_iana_option result;
|
||||
result.type = htons(IA_NA);
|
||||
result.iaid = htonl(atoi(iaid));
|
||||
result.t1 = 0;
|
||||
result.t2 = 0;
|
||||
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
return result;
|
||||
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip)
|
||||
{
|
||||
struct dhcp6_iaaddr_option result;
|
||||
result.type =htons(IAADDR);
|
||||
/* no suboptions needed here, so length is 24 */
|
||||
result.len = htons(24);
|
||||
result.preferred_lifetime = 0;
|
||||
result.valid_lifetime = 0;
|
||||
int s = inet_pton(AF_INET6, ip, &(result.ip));
|
||||
if (s <= 0) {
|
||||
if (s == 0)
|
||||
fprintf(stderr, "Not in presentation format");
|
||||
else
|
||||
perror("inet_pton");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id){
|
||||
struct dhcp6_packet result;
|
||||
bzero(result.buf, sizeof(result.buf));
|
||||
/* message_type */
|
||||
result.buf[0] = RELEASE;
|
||||
/* tx_id */
|
||||
bzero(result.buf+1, 3);
|
||||
|
||||
struct dhcp6_option client_option = create_client_id_option(client_id);
|
||||
struct dhcp6_option server_option = create_server_id_option(server_id);
|
||||
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
|
||||
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
|
||||
int offset = 4;
|
||||
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
|
||||
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
|
||||
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
|
||||
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
|
||||
result.len = offset;
|
||||
return result;
|
||||
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr)
|
||||
{
|
||||
struct dhcp6_iana_option result;
|
||||
result.type = htons(IA_NA);
|
||||
result.iaid = htonl(atoi(iaid));
|
||||
result.t1 = 0;
|
||||
result.t2 = 0;
|
||||
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t parse_iana_suboption(char* buf, size_t len){
|
||||
size_t current_pos = 0;
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
|
||||
option_value[option_len-sizeof(uint16_t)] ='\0';
|
||||
fprintf(stderr, "Error: %s\n", option_value);
|
||||
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id)
|
||||
{
|
||||
struct dhcp6_packet result;
|
||||
bzero(result.buf, sizeof(result.buf));
|
||||
/* message_type */
|
||||
result.buf[0] = RELEASE;
|
||||
/* tx_id */
|
||||
bzero(result.buf+1, 3);
|
||||
|
||||
struct dhcp6_option client_option = create_client_id_option(client_id);
|
||||
struct dhcp6_option server_option = create_server_id_option(server_id);
|
||||
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
|
||||
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
|
||||
int offset = 4;
|
||||
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
|
||||
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
|
||||
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
|
||||
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
|
||||
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
|
||||
result.len = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t parse_iana_suboption(char* buf, size_t len)
|
||||
{
|
||||
size_t current_pos = 0;
|
||||
char option_value[1024];
|
||||
while (current_pos < len)
|
||||
{
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE)
|
||||
{
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
|
||||
option_value[option_len-sizeof(uint16_t)] ='\0';
|
||||
fprintf(stderr, "Error: %s\n", option_value);
|
||||
}
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return -2;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
int16_t parse_packet(char* buf, size_t len){
|
||||
uint8_t type = buf[0];
|
||||
/*skipping tx id. you need it, uncomment following line
|
||||
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
|
||||
*/
|
||||
size_t current_pos = 4;
|
||||
if (type != REPLY ){
|
||||
return NOT_REPLY_CODE;
|
||||
}
|
||||
char option_value[1024];
|
||||
while (current_pos < len) {
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE){
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS){
|
||||
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
|
||||
fprintf(stderr, "Error: %d %s\n", status, option_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
int16_t parse_packet(char* buf, size_t len)
|
||||
{
|
||||
int16_t ret = -1;
|
||||
uint8_t type = buf[0];
|
||||
/*skipping tx id. you need it, uncomment following line
|
||||
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
|
||||
*/
|
||||
size_t current_pos = 4;
|
||||
if (type != REPLY )
|
||||
return NOT_REPLY_CODE;
|
||||
|
||||
char option_value[1024];
|
||||
while (current_pos < len)
|
||||
{
|
||||
uint16_t option_type, option_len;
|
||||
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
|
||||
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
|
||||
option_type = ntohs(option_type);
|
||||
option_len = ntohs(option_len);
|
||||
current_pos += 2 * sizeof(uint16_t);
|
||||
if (option_type == STATUS_CODE)
|
||||
{
|
||||
uint16_t status;
|
||||
memcpy(&status, buf + current_pos, sizeof(uint16_t));
|
||||
status = ntohs(status);
|
||||
if (status != SUCCESS)
|
||||
{
|
||||
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
|
||||
fprintf(stderr, "Error: %d %s\n", status, option_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Got success status, return that if there's no specific error in an IA_NA. */
|
||||
ret = SUCCESS;
|
||||
}
|
||||
if (option_type == IA_NA ){
|
||||
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
|
||||
if (result){
|
||||
return result;
|
||||
}
|
||||
}
|
||||
current_pos += option_len;
|
||||
|
||||
if (option_type == IA_NA )
|
||||
{
|
||||
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
current_pos += option_len;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void usage(const char* arg, FILE* stream){
|
||||
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
|
||||
void usage(const char* arg, FILE* stream)
|
||||
{
|
||||
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
|
||||
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
|
||||
}
|
||||
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet){
|
||||
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
char response[1400];
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
int i = 0;
|
||||
if (sock < 0) {
|
||||
perror("creating socket");
|
||||
return -1;
|
||||
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
|
||||
{
|
||||
struct sockaddr_in6 server_addr, client_addr;
|
||||
char response[1400];
|
||||
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
int i = 0;
|
||||
if (sock < 0)
|
||||
{
|
||||
perror("creating socket");
|
||||
return -1;
|
||||
}
|
||||
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1) {
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1)
|
||||
{
|
||||
perror("SO_BINDTODEVICE");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
server_addr.sin6_family = AF_INET6;
|
||||
client_addr.sin6_family = AF_INET6;
|
||||
@@ -320,126 +348,152 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet){
|
||||
inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr);
|
||||
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
|
||||
int16_t recv_size = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (sendto(sock, packet->buf, packet->len, 0,
|
||||
(struct sockaddr *)&server_addr,
|
||||
sizeof(server_addr)) < 0) {
|
||||
perror("sendto failed");
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
|
||||
{
|
||||
perror("sendto failed");
|
||||
exit(4);
|
||||
}
|
||||
}
|
||||
|
||||
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
|
||||
if (recv_size == -1){
|
||||
if (errno == EAGAIN){
|
||||
sleep(1);
|
||||
continue;
|
||||
}else {
|
||||
if (recv_size == -1)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("recvfrom");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t result = parse_packet(response, recv_size);
|
||||
if (result == NOT_REPLY_CODE){
|
||||
if (result == NOT_REPLY_CODE)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
close(sock);
|
||||
fprintf(stderr, "Response timed out\n");
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char * const argv[]) {
|
||||
const char* UNINITIALIZED = "";
|
||||
const char* iface = UNINITIALIZED;
|
||||
const char* ip = UNINITIALIZED;
|
||||
const char* client_id = UNINITIALIZED;
|
||||
const char* server_id = UNINITIALIZED;
|
||||
const char* iaid = UNINITIALIZED;
|
||||
int dry_run = 0;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
|
||||
if (c == -1){
|
||||
break;
|
||||
}
|
||||
switch(c){
|
||||
case 0:
|
||||
if (longopts[option_index].flag !=0){
|
||||
break;
|
||||
}
|
||||
printf ("option %s", longopts[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
case 'i':
|
||||
iaid = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
ip = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
client_id = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 's':
|
||||
server_id = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
return 0;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
default:
|
||||
abort();
|
||||
|
||||
}
|
||||
int main(int argc, char * const argv[])
|
||||
{
|
||||
const char* UNINITIALIZED = "";
|
||||
const char* iface = UNINITIALIZED;
|
||||
const char* ip = UNINITIALIZED;
|
||||
const char* client_id = UNINITIALIZED;
|
||||
const char* server_id = UNINITIALIZED;
|
||||
const char* iaid = UNINITIALIZED;
|
||||
int dry_run = 0;
|
||||
while (1)
|
||||
{
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case 0:
|
||||
if (longopts[option_index].flag !=0)
|
||||
break;
|
||||
|
||||
printf ("option %s", longopts[option_index].name);
|
||||
if (optarg)
|
||||
printf (" with arg %s", optarg);
|
||||
printf ("\n");
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
iaid = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
ip = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
client_id = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
dry_run = 1;
|
||||
break;
|
||||
case 's':
|
||||
server_id = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0], stdout);
|
||||
return 0;
|
||||
case '?':
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
default:
|
||||
abort();
|
||||
|
||||
}
|
||||
}
|
||||
if (iaid == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iaid parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
|
||||
if (iaid == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required iaid parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (server_id == UNINITIALIZED){
|
||||
|
||||
if (server_id == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required server-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (client_id == UNINITIALIZED){
|
||||
}
|
||||
|
||||
if (client_id == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required client-id parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (ip == UNINITIALIZED){
|
||||
}
|
||||
|
||||
if (ip == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required ip parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
if (iface == UNINITIALIZED){
|
||||
fprintf(stderr, "Missing required iface parameter\n");
|
||||
}
|
||||
|
||||
if (iface == UNINITIALIZED)
|
||||
{
|
||||
fprintf(stderr, "Missing required iface parameter\n");
|
||||
usage(argv[0], stderr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
|
||||
if (dry_run){
|
||||
|
||||
if (dry_run)
|
||||
{
|
||||
uint16_t i;
|
||||
for(i=0;i<packet.len;i++){
|
||||
printf("%hhx", packet.buf[i]);
|
||||
}
|
||||
|
||||
for(i=0; i<packet.len; i++)
|
||||
printf("%hhx", packet.buf[i]);
|
||||
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return send_release_packet(iface, &packet);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
|
||||
|
||||
# Script for dnsmasq lease-change hook.
|
||||
# Maintains the above file with a IP address/MAC address pairs,
|
||||
# Maintains the above file with an IP address/MAC address pairs,
|
||||
# one lease per line. Works with IPv4 and IPv6 leases, file is
|
||||
# atomically updated, so no races for users of the data.
|
||||
|
||||
|
||||
10
contrib/try-all-ns/README-2.78
Normal file
10
contrib/try-all-ns/README-2.78
Normal file
@@ -0,0 +1,10 @@
|
||||
Hi,
|
||||
I updated the try-all-ns patch to work with the latest version of git. Ended up implementing it on top of master, 2.78test2-7-g63437ff. As that specific if-clause has been changed in the last few commits, it's not compatible for 2.77, sadly.
|
||||
|
||||
Find the patch attached.
|
||||
|
||||
Regards,
|
||||
|
||||
Rasmus Ahlberg
|
||||
Software Developer, R&D
|
||||
Electrolux Small Appliances
|
||||
20
contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
Normal file
20
contrib/try-all-ns/dnsmasq-2.78xx-try-all-ns.patch
Normal file
@@ -0,0 +1,20 @@
|
||||
diff --git a/src/forward.c b/src/forward.c
|
||||
index e3fa94b..ecf3b98 100644
|
||||
--- a/src/forward.c
|
||||
+++ b/src/forward.c
|
||||
@@ -789,9 +789,12 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
/* Note: if we send extra options in the EDNS0 header, we can't recreate
|
||||
the query from the reply. */
|
||||
- if (RCODE(header) == REFUSED &&
|
||||
- forward->forwardall == 0 &&
|
||||
- !(forward->flags & FREC_HAS_EXTRADATA))
|
||||
+ if ((RCODE(header) == REFUSED &&
|
||||
+ forward->forwardall == 0 &&
|
||||
+ !(forward->flags & FREC_HAS_EXTRADATA)) ||
|
||||
+ /* If strict-order is set, try next server on NXDOMAIN reply */
|
||||
+ (RCODE(header) == NXDOMAIN && option_bool(OPT_ORDER) &&
|
||||
+ server->next != NULL))
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
unsigned char *pheader;
|
||||
@@ -243,6 +243,10 @@ IPv4 or IPv6 address of the lease to remove.
|
||||
Note that this function will trigger the DhcpLeaseRemoved signal and the
|
||||
configured DHCP lease script will be run with the "del" action.
|
||||
|
||||
GetMetrics
|
||||
----------
|
||||
|
||||
Returns an array with various metrics for DNS and DHCP.
|
||||
|
||||
|
||||
2. SIGNALS
|
||||
|
||||
42
debian/changelog
vendored
42
debian/changelog
vendored
@@ -1,8 +1,44 @@
|
||||
dnsmasq (2.78-1) unstable; urgency=low
|
||||
dnsmasq (2.80-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #837602) (closes: #794640) (closes: #794636)
|
||||
* Close old bugs, long agp fixed. (closes: #802845) (closes: #754299)
|
||||
* Provide usr/lib/tmpfiles.d/dnsmasq.conf. (closes: #872396)
|
||||
* Run restorecon on /run/dnsmasq for SE Linux. (closes: #872397)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 17 Sep 2018 23:11:25 +0000
|
||||
|
||||
dnsmasq (2.79-1) unstable; urgency=low
|
||||
|
||||
* New upstream. (closes: #888200)
|
||||
* Fix trust-anchor regex in init script. (closes: #884347)
|
||||
* Fix exit code for dhcp_release6 (closes: #883596)
|
||||
* Add project homepage to control file. (closes: #887764)
|
||||
* New binary package dnsmasq-base-lua, includes Lua support.
|
||||
* Remove hardwired shlibs dependency for libnettle 3.3 and
|
||||
fix code to avoid ABI breakage as long as compiled against
|
||||
libnettle 3.4 or later. (closes: #891315)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 Feb 2018 19:54:22 +0000
|
||||
|
||||
dnsmasq (2.78-3) unstable; urgency=high
|
||||
|
||||
* Make failure of pidfile chown a warning. (closes: #889857)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 8 Feb 2018 21:26:30 +0000
|
||||
|
||||
dnsmasq (2.78-2) unstable; urgency=high
|
||||
|
||||
* Change ownership of pid file, to keep systemd happy. (closes: #889336)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Feb 2018 17:21:30 +0000
|
||||
|
||||
dnsmasq (2.78-1) unstable; urgency=high
|
||||
|
||||
* New upstream.
|
||||
Security fixes for CVE-2017-13704 (closes: #877102)
|
||||
Security fixes for CVE-2017-14491 - CVE-2017-14496 inclusive.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 25 Jun 2017 21:34:00 +0000
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 29 Sep 2017 21:34:00 +0000
|
||||
|
||||
dnsmasq (2.77-2) unstable; urgency=low
|
||||
|
||||
@@ -17,7 +53,7 @@ dnsmasq (2.77-1) unstable; urgency=low
|
||||
includes port=0 to disable DNS.
|
||||
* Handle gratuitous format change in /usr/share/dns/root.ds
|
||||
(closes: #858506) (closes: #860064)
|
||||
* Add lsb-base dependancy.
|
||||
* Add lsb-base dependency.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
|
||||
|
||||
|
||||
24
debian/control
vendored
24
debian/control
vendored
@@ -3,13 +3,15 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
|
||||
liblua5.2-dev
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Standards-Version: 3.9.8
|
||||
|
||||
Package: dnsmasq
|
||||
Architecture: all
|
||||
Depends: netbase, dnsmasq-base(>= ${binary:Version}),
|
||||
Depends: netbase, dnsmasq-base,
|
||||
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6)
|
||||
Suggests: resolvconf
|
||||
Conflicts: resolvconf (<<1.15)
|
||||
@@ -27,13 +29,29 @@ Package: dnsmasq-base
|
||||
Architecture: any
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
|
||||
Recommends: dns-root-data
|
||||
Provides: dnsmasq-base
|
||||
Conflicts: dnsmasq-base-lua
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
that, install the dnsmasq package.
|
||||
|
||||
Package: dnsmasq-base-lua
|
||||
Architecture: any
|
||||
Depends: adduser, ${shlibs:Depends}
|
||||
Breaks: dnsmasq (<< 2.63-1~)
|
||||
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
|
||||
Recommends: dns-root-data
|
||||
Provides: dnsmasq-base
|
||||
Conflicts: dnsmasq-base
|
||||
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||
This package contains the dnsmasq executable and documentation, but
|
||||
not the infrastructure required to run it as a system daemon. For
|
||||
that, install the dnsmasq package. This package is an alternative
|
||||
to dnsmasq-base which includes the LUA interpreter.
|
||||
|
||||
Package: dnsmasq-utils
|
||||
Architecture: linux-any
|
||||
Depends: ${shlibs:Depends}
|
||||
|
||||
2
debian/copyright
vendored
2
debian/copyright
vendored
@@ -1,4 +1,4 @@
|
||||
dnsmasq is Copyright (c) 2000-2016 Simon Kelley
|
||||
dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||
|
||||
|
||||
5
debian/init
vendored
5
debian/init
vendored
@@ -111,7 +111,7 @@ DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
ROOT_DS="/usr/share/dns/root.ds"
|
||||
|
||||
if [ -f $ROOT_DS ]; then
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `sed -rne "s/^([.a-ZA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
|
||||
fi
|
||||
|
||||
start()
|
||||
@@ -127,7 +127,8 @@ start()
|
||||
mkdir /run/dnsmasq || return 2
|
||||
chown dnsmasq:nogroup /run/dnsmasq || return 2
|
||||
fi
|
||||
|
||||
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
|
||||
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||
-x /run/dnsmasq/$NAME.pid \
|
||||
|
||||
3
debian/lintian-override
vendored
Normal file
3
debian/lintian-override
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# dnsmasq-base and dnsmasq-base-lua are mutually exclusive and both
|
||||
# provide /usr/share/doc/dnsmasq-base
|
||||
dnsmasq-base-lua binary: usr-share-doc-symlink-without-dependency dnsmasq-base
|
||||
2
debian/readme
vendored
2
debian/readme
vendored
@@ -54,7 +54,7 @@ Notes on configuring dnsmasq as packaged for Debian.
|
||||
nodhcp : omit DHCP support.
|
||||
nodhcp6 : omit DHCPv6 support.
|
||||
noscript : omit lease-change script support.
|
||||
use_lua : provide support for lease-change scripts written
|
||||
uselua : provide support for lease-change scripts written
|
||||
in Lua.
|
||||
noipv6 : omit IPv6 support.
|
||||
nodbus : omit DBus support.
|
||||
|
||||
266
debian/rules
vendored
266
debian/rules
vendored
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
# debian/rules file - for dnsmasq.
|
||||
# Copyright 2001-2011 by Simon Kelley
|
||||
# Copyright 2001-2018 by Simon Kelley
|
||||
# Based on the sample in the debian hello package which carries the following:
|
||||
# Copyright 1994,1995 by Ian Jackson.
|
||||
# I hereby give you perpetual unlimited permission to copy,
|
||||
@@ -103,128 +103,172 @@ ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
LDFLAGS += -lbsd
|
||||
endif
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
make clean
|
||||
make -C contrib/lease-tools clean
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/daemon
|
||||
define build_tree
|
||||
rm -rf $1
|
||||
install -m 755 \
|
||||
-d debian/daemon/DEBIAN \
|
||||
-d debian/daemon/usr/share/doc \
|
||||
-d debian/daemon/etc/init.d \
|
||||
-d debian/daemon/etc/dnsmasq.d \
|
||||
-d debian/daemon/etc/resolvconf/update.d \
|
||||
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/daemon/usr/share/dnsmasq \
|
||||
-d debian/daemon/etc/default \
|
||||
-d debian/daemon/lib/systemd/system \
|
||||
-d debian/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/installed-marker debian/daemon/usr/share/dnsmasq
|
||||
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
|
||||
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/daemon
|
||||
chmod -R g-ws debian/daemon
|
||||
dpkg --build debian/daemon ..
|
||||
-d $1/DEBIAN \
|
||||
-d $1/etc/dbus-1/system.d \
|
||||
-d $1/usr/share/doc/$(package) \
|
||||
-d $1/usr/share/doc/$(package)/examples \
|
||||
-d $1/usr/share/$(package) \
|
||||
-d $1/var/lib/misc
|
||||
|
||||
binary-arch: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/base
|
||||
install -m 755 \
|
||||
-d debian/base/DEBIAN \
|
||||
-d debian/base/etc/dbus-1/system.d \
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/usr/share/$(package) \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
endef
|
||||
|
||||
define add_docs
|
||||
# Need to remove paypal links in Debian Package for policy reasons.
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >debian/base/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>debian/base/usr/share/doc/$(package)/doc.html
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/DBus-interface
|
||||
endif
|
||||
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
|
||||
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
|
||||
gzip -9n debian/base/usr/share/man/man8/dnsmasq.8
|
||||
for f in debian/base/usr/share/man/*; do \
|
||||
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >$1/usr/share/doc/$(package)/doc.html
|
||||
echo "</BODY>" >>$1/usr/share/doc/$(package)/doc.html
|
||||
install -m 644 setup.html $1/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example $1/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 FAQ $1/usr/share/doc/$(package)/.
|
||||
gzip -9n $1/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG $1/usr/share/doc/$(package)/changelog
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog
|
||||
install -m 644 CHANGELOG.archive $1/usr/share/doc/$(package)/changelog.archive
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog.archive
|
||||
install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
|
||||
gzip -9n $1/usr/share/doc/$(package)/DBus-interface
|
||||
gzip -9n $1/usr/share/man/man8/dnsmasq.8
|
||||
for f in $1/usr/share/man/*; do \
|
||||
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||
gzip -9n $$f/man8/dnsmasq.8 ; \
|
||||
fi \
|
||||
done
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||
endef
|
||||
|
||||
define add_files
|
||||
install -m 644 trust-anchors.conf $1/usr/share/$(package)/.
|
||||
install -m 644 debian/dnsmasq-base.conffiles $1/DEBIAN/conffiles
|
||||
install -m 755 debian/dnsmasq-base.postinst $1/DEBIAN/postinst
|
||||
install -m 755 debian/dnsmasq-base.postrm $1/DEBIAN/postrm
|
||||
install -m 644 debian/changelog $1/usr/share/doc/$(package)/changelog.Debian
|
||||
gzip -9n $1/usr/share/doc/$(package)/changelog.Debian
|
||||
install -m 644 debian/readme $1/usr/share/doc/$(package)/README.Debian
|
||||
install -m 644 debian/copyright $1/usr/share/doc/$(package)/copyright
|
||||
install -m 644 debian/dbus.conf $1/etc/dbus-1/system.d/dnsmasq.conf
|
||||
endef
|
||||
|
||||
clean:
|
||||
$(checkdir)
|
||||
make BUILDDIR=debian/build/no-lua clean
|
||||
make BUILDDIR=debian/build/lua clean
|
||||
make -C contrib/lease-tools clean
|
||||
rm -rf debian/build debian/trees debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||
|
||||
binary-indep: checkroot
|
||||
$(checkdir)
|
||||
rm -rf debian/trees/daemon
|
||||
install -m 755 \
|
||||
-d debian/trees/daemon/DEBIAN \
|
||||
-d debian/trees/daemon/usr/share/doc \
|
||||
-d debian/trees/daemon/etc/init.d \
|
||||
-d debian/trees/daemon/etc/dnsmasq.d \
|
||||
-d debian/trees/daemon/etc/resolvconf/update.d \
|
||||
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/trees/daemon/usr/share/dnsmasq \
|
||||
-d debian/trees/daemon/etc/default \
|
||||
-d debian/trees/daemon/lib/systemd/system \
|
||||
-d debian/trees/daemon/usr/lib/tmpfiles.d \
|
||||
-d debian/trees/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
install -m 644 debian/installed-marker debian/trees/daemon/usr/share/dnsmasq
|
||||
install -m 644 debian/default debian/trees/daemon/etc/default/dnsmasq
|
||||
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
|
||||
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
|
||||
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
|
||||
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
|
||||
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
|
||||
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/trees/daemon
|
||||
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/daemon
|
||||
chmod -R g-ws debian/trees/daemon
|
||||
dpkg --build debian/trees/daemon ..
|
||||
|
||||
binary-arch: checkroot
|
||||
$(call build_tree,debian/trees/base)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/base)
|
||||
else
|
||||
rm -rf debian/trees/base/usr/share/man
|
||||
endif
|
||||
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
|
||||
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/base
|
||||
chmod -R g-ws debian/base
|
||||
dpkg --build debian/base ..
|
||||
$(call add_files,debian/trees/base)
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/base/usr/sbin/dnsmasq
|
||||
endif
|
||||
cd debian/trees/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/trees/base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/trees/base
|
||||
find debian/trees/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/base
|
||||
chmod -R g-ws debian/trees/base
|
||||
dpkg --build debian/trees/base ..
|
||||
|
||||
$(call build_tree,debian/trees/lua-base)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/lua-base)
|
||||
else
|
||||
rm -rf debian/trees/lua-base/usr/share/man
|
||||
endif
|
||||
$(call add_files,debian/trees/lua-base)
|
||||
install -m 755 -d debian/trees/lua-base/usr/share/lintian/overrides
|
||||
install -m 644 debian/lintian-override debian/trees/lua-base/usr/share/lintian/overrides/dnsmasq-base-lua
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/lua-base/usr/sbin/dnsmasq
|
||||
endif
|
||||
ln -s $(package) debian/trees/lua-base/usr/share/doc/dnsmasq-base-lua
|
||||
cd debian/trees/lua-base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps --warnings=1 debian/trees/lua-base/usr/sbin/dnsmasq
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base-lua -Pdebian/trees/lua-base
|
||||
find debian/trees/lua-base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/lua-base
|
||||
chmod -R g-ws debian/trees/lua-base
|
||||
dpkg --build debian/trees/lua-base ..
|
||||
|
||||
|
||||
ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
rm -rf debian/utils
|
||||
install -m 755 -d debian/utils/DEBIAN \
|
||||
-d debian/utils/usr/share/man/man1 \
|
||||
-d debian/utils/usr/bin \
|
||||
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||
install -m 644 contrib/lease-tools/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/utils/usr/bin/dhcp_release6
|
||||
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_release6.1
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
rm -rf debian/trees/utils
|
||||
install -m 755 -d debian/trees/utils/DEBIAN \
|
||||
-d debian/trees/utils/usr/bin \
|
||||
-d debian/trees/utils/usr/share/doc/dnsmasq-utils
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 755 -d debian/trees/utils/usr/share/man/man1
|
||||
endif
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 contrib/lease-tools/dhcp_release.1 debian/trees/utils/usr/share/man/man1/dhcp_release.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release.1
|
||||
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/trees/utils/usr/share/man/man1/dhcp_release6.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release6.1
|
||||
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||
endif
|
||||
install -m 644 debian/copyright debian/trees/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||
install -m 644 debian/changelog debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
gzip -9n debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_release6
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release6
|
||||
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
endif
|
||||
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/utils
|
||||
chmod -R g-ws debian/utils
|
||||
dpkg --build debian/utils ..
|
||||
cd debian/trees/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-shlibdeps -Tdebian/utils-substvars debian/trees/utils/usr/bin/dhcp_release debian/trees/utils/usr/bin/dhcp_release6 debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/trees/utils
|
||||
find debian/trees/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
chown -R root.root debian/trees/utils
|
||||
chmod -R g-ws debian/trees/utils
|
||||
dpkg --build debian/trees/utils ..
|
||||
endif
|
||||
|
||||
define checkdir
|
||||
|
||||
1
debian/shlibs.local
vendored
1
debian/shlibs.local
vendored
@@ -1 +0,0 @@
|
||||
libnettle 6 libnettle6 (>= 3.3)
|
||||
1
debian/tmpfiles.conf
vendored
Normal file
1
debian/tmpfiles.conf
vendored
Normal file
@@ -0,0 +1 @@
|
||||
d /run/dnsmasq 755 dnsmasq nogroup
|
||||
@@ -90,7 +90,7 @@
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
@@ -288,7 +288,7 @@
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also the they [] around the IPv6 address are obligatory.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
@@ -354,11 +354,11 @@
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1:1m
|
||||
#dhcp-option=option:T1,1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2:2m
|
||||
#dhcp-option=option:T2,2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
@@ -436,22 +436,22 @@
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# this if you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built-in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for Etherboot gPXE. The idea is to send two different
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
# Boot for iPXE. The idea is to send two different
|
||||
# filenames, the first loads iPXE, and the second tells iPXE what to
|
||||
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
|
||||
#dhcp-boot=undionly.kpxe
|
||||
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
|
||||
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# Encapsulated options for iPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
@@ -547,6 +547,14 @@
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
@@ -664,3 +672,8 @@
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/,*.conf
|
||||
|
||||
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||
#dhcp-name-match=set:wpad-ignore,wpad
|
||||
#dhcp-ignore-names=tag:wpad-ignore
|
||||
|
||||
4
doc.html
4
doc.html
@@ -66,6 +66,10 @@ the repo, or get a copy using git protocol with the command
|
||||
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
or
|
||||
|
||||
<PRE><TT>git clone http://thekelleys.org.uk/git/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
|
||||
for details.
|
||||
|
||||
394
man/dnsmasq.8
394
man/dnsmasq.8
File diff suppressed because it is too large
Load Diff
@@ -478,7 +478,8 @@ la traza reversa direcci
|
||||
.TP
|
||||
.B \-c, --cache-size=<tamaño de caché>
|
||||
Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres.
|
||||
Fijar el tamaño a cero deshabilita el caché.
|
||||
Fijar el tamaño a cero deshabilita el caché. Nota: el gran tamaño de
|
||||
caché afecta el rendimiento.
|
||||
.TP
|
||||
.B \-N, --no-negcache
|
||||
Deshabilitar caché negativo. El caché negativo le permite a dnsmasq
|
||||
|
||||
238
man/fr/dnsmasq.8
238
man/fr/dnsmasq.8
@@ -10,7 +10,7 @@ est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
|
||||
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
|
||||
local (LAN).
|
||||
.PP
|
||||
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
|
||||
Dnsmasq accepte les requêtes DNS et y répond soit en utilisant un petit cache
|
||||
local, soit en effectuant une requête à un serveur DNS récursif externe (par
|
||||
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
|
||||
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
|
||||
@@ -19,25 +19,25 @@ pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
|
||||
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
|
||||
noms locaux d'apparaitre dans le DNS global.
|
||||
.PP
|
||||
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
|
||||
Le serveur DHCP de Dnsmasq supporte les définitions d'adresses statiques et les
|
||||
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
|
||||
et peut être configuré pour fournir n'importe quelle option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
|
||||
support PXE est complet, et comprend un mode proxy permettant de fournir des
|
||||
informations PXE aux clients alors que l'allocation DHCP est effectuée par un
|
||||
autre serveur.
|
||||
informations PXE aux clients alors que l'allocation d'adresse via DHCP est
|
||||
effectuée par un autre serveur.
|
||||
.PP
|
||||
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
|
||||
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionnalités
|
||||
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
|
||||
qu'une fonctionalité permettant l'addition de ressources AAAA pour des
|
||||
qu'une fonctionnalité permettant l'addition de ressources AAAA pour des
|
||||
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
|
||||
autoconfiguration).
|
||||
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
|
||||
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
|
||||
une délégation de préfixe DHCPv6.
|
||||
.PP
|
||||
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
|
||||
Dnsmasq est développé pour de petits systèmes embarqués. Il tend à avoir
|
||||
l'empreinte mémoire la plus faible possible pour les fonctions supportées,
|
||||
et permet d'exclure les fonctions inutiles du binaire compilé.
|
||||
.SH OPTIONS
|
||||
@@ -46,16 +46,23 @@ Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
.B --pid-file=
|
||||
(sans paramètre après le =) désactive l'écriture du fichier PID.
|
||||
Sur BSD, à moins que le logiciel ne soit compilé avec la bibliothèque GNU
|
||||
getopt, la forme longue des options ne fonctionne pas en ligne de commande; Elle
|
||||
getopt, la forme longue des options ne fonctionne pas en ligne de commande; elle
|
||||
est toujours supportée dans le fichier de configuration.
|
||||
.TP
|
||||
.B --test
|
||||
Vérifie la syntaxe du ou des fichiers de configurations. Se termine avec le
|
||||
Vérifie la syntaxe du ou des fichiers de configuration. Se termine avec le
|
||||
code de retour 0 si tout est OK, ou un code différent de 0 dans le cas
|
||||
contraire. Ne démarre pas Dnsmasq.
|
||||
.TP
|
||||
.B \-w, --help
|
||||
Affiche toutes les options de ligne de commande.
|
||||
.B --help dhcp
|
||||
affiche les options de configuration connues pour DHCPv4, et
|
||||
.B --help dhcp6
|
||||
affiche les options de configuration connues pour DHCPv6.
|
||||
.TP
|
||||
.B \-h, --no-hosts
|
||||
Ne pas charger les noms du fichier /etc/hosts.
|
||||
Ne pas charger les noms d'hôtes du fichier /etc/hosts.
|
||||
.TP
|
||||
.B \-H, --addn-hosts=<fichier>
|
||||
Fichiers d'hôtes additionnels. Lire le fichier spécifié en plus de /etc/hosts.
|
||||
@@ -68,7 +75,7 @@ fichiers contenus dans ce répertoire.
|
||||
.B \-E, --expand-hosts
|
||||
Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le
|
||||
nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service
|
||||
DHCP. Notez que cela ne s'applique pas au nom de domaine dans les CNAME, les
|
||||
DHCP. Notez que cela ne s'applique pas aux noms de domaine dans les CNAME, les
|
||||
enregistrements PTR, TXT, etc...
|
||||
.TP
|
||||
.B \-T, --local-ttl=<durée>
|
||||
@@ -86,7 +93,7 @@ Les réponses négatives provenant des serveurs amonts contiennent normalement
|
||||
une information de durée de vie (time-to-live) dans les enregistrements SOA,
|
||||
information dont dnsmasq se sert pour mettre la réponse en cache. Si la réponse
|
||||
du serveur amont omet cette information, dnsmasq ne cache pas la réponse. Cette
|
||||
option permet de doner une valeur de durée de vie par défaut (en secondes) que
|
||||
option permet de donner une valeur de durée de vie par défaut (en secondes) que
|
||||
dnsmasq utilise pour mettre les réponses négatives dans son cache, même en
|
||||
l'absence d'enregistrement SOA.
|
||||
.TP
|
||||
@@ -194,7 +201,7 @@ au dessus de la valeur spécifiée. Utile pour des systèmes derrière des dispo
|
||||
garde-barrières ("firewalls").
|
||||
.TP
|
||||
.B \-i, --interface=<nom d'interface>
|
||||
N'écouter que sur l'interface réseau spécifiée. Dnsmasq aujoute automatiquement
|
||||
N'écouter que sur l'interface réseau spécifiée. Dnsmasq ajoute automatiquement
|
||||
l'interface locale ("loopback") à la liste des interfaces lorsque l'option
|
||||
.B --interface
|
||||
est utilisée.
|
||||
@@ -205,13 +212,13 @@ ou
|
||||
n'est donnée, Dnsmasq écoutera sur toutes les interfaces disponibles sauf
|
||||
celle(s) spécifiée(s) par l'option
|
||||
.B --except-interface.
|
||||
Les alias d'interfaces IP (e-g "eth1:0") ne peuvent être utilisés ni avec
|
||||
Les alias d'interfaces IP (par exemple "eth1:0") ne peuvent être utilisés ni avec
|
||||
.B --interface
|
||||
ni
|
||||
.B \--except-interface.
|
||||
Utiliser l'option
|
||||
.B --listen-address
|
||||
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
|
||||
à la place. Un simple joker, consistant en un '*' final, peut être utilisé dans
|
||||
les options
|
||||
.B \--interface
|
||||
et
|
||||
@@ -229,10 +236,10 @@ sont fournies n'importe pas, et que l'option
|
||||
.B --except-interface
|
||||
l'emporte toujours sur les autres.
|
||||
.TP
|
||||
.B --auth-server=<domaine>,<interface>|<addresse IP>
|
||||
.B --auth-server=<domaine>,<interface>|<adresse IP>
|
||||
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
|
||||
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
|
||||
pas besoin d'être mentionées ni dans
|
||||
pas besoin d'être mentionnées ni dans
|
||||
.B --interface
|
||||
ni dans
|
||||
.B --listen-address
|
||||
@@ -253,7 +260,7 @@ Ecouter sur la ou les adresse(s) IP spécifiée(s). Les options
|
||||
.B \--interface
|
||||
et
|
||||
.B \--listen-address
|
||||
peuvent-être spécifiées simultanément, auquel cas un jeu d'interfaces et
|
||||
peuvent être spécifiées simultanément, auquel cas un jeu d'interfaces et
|
||||
d'adresses seront utilisées. Notez que si
|
||||
aucune option
|
||||
.B \--interface
|
||||
@@ -265,7 +272,7 @@ nécessaire de fournir explicitement son adresse IP, 127.0.0.1 via l'option
|
||||
.B \--listen-address.
|
||||
.TP
|
||||
.B \-z, --bind-interfaces
|
||||
Sur les systèmes qui le supporte, Dnsmasq s'associe avec l'interface joker
|
||||
Sur les systèmes qui le supportent, Dnsmasq s'associe avec l'interface joker
|
||||
("wildcard"), même lorsqu'il ne doit écouter que sur certaines interfaces. Par
|
||||
la suite, il rejette les requêtes auxquelles il ne doit pas répondre. Cette
|
||||
situation présente l'avantage de fonctionner même lorsque les interfaces vont
|
||||
@@ -302,7 +309,7 @@ le réseau auquel ils sont attachés). Cette possibilité est actuellement limit
|
||||
.TP
|
||||
.B \-b, --bogus-priv
|
||||
Fausse résolution inverse pour les réseaux privés. Toutes les requêtes DNS
|
||||
inverses pour des adresses IP privées (ie 192.168.x.x, etc...) qui ne sont pas
|
||||
inverses pour des adresses IP privées (192.168.x.x, etc...) qui ne sont pas
|
||||
trouvées dans /etc/hosts ou dans le fichier de baux DHCP se voient retournées
|
||||
une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises
|
||||
aux serveurs de nom amont ("upstream server").
|
||||
@@ -317,7 +324,7 @@ modifiera 1.2.3.56 en 6.7.8.56 et 1.2.3.67 en 6.7.8.67.
|
||||
Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent
|
||||
"bidouillage DNS" ("DNS doctoring"). Si l'ancienne IP est donnée sous la forme
|
||||
d'une gamme d'adresses, alors seules les adresses dans cette gamme seront
|
||||
réecrites, et non le sous-réseau dans son ensemble. Ainsi,
|
||||
réécrites, et non le sous-réseau dans son ensemble. Ainsi,
|
||||
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||
fait correspondre 192.168.0.10->192.168.0.40 à 10.0.0.10->10.0.0.40
|
||||
.TP
|
||||
@@ -380,7 +387,7 @@ effectuer ses requêtes à tous les serveurs disponibles. Le résultat renvoyé
|
||||
au client sera celui fournit par le premier serveur ayant répondu.
|
||||
.TP
|
||||
.B --stop-dns-rebind
|
||||
Rejete (et enregistre dans le journal d'activité) les adresses dans la gamme
|
||||
Rejette (et enregistre dans le journal d'activité) les adresses dans la gamme
|
||||
d'adresses IP privée (au sens RFC1918) qui pourraient être renvoyées par les
|
||||
serveurs amonts suite à une résolution de nom. Cela bloque les attaques cherchant
|
||||
à détourner de leur usage les logiciels de navigation web ('browser') en s'en
|
||||
@@ -389,13 +396,13 @@ servant pour découvrir les machines situées sur le réseau local.
|
||||
.B --rebind-localhost-ok
|
||||
Exclue 127.0.0/8 des vérifications de réassociation DNS. Cette gamme d'adresses
|
||||
est retournée par les serveurs Realtime Blackhole (RBL, utilisés dans la
|
||||
lutte contre le spam), la bloquer peut entraîner des disfonctionnements de ces
|
||||
lutte contre le spam), la bloquer peut entraîner des dysfonctionnements de ces
|
||||
services.
|
||||
.TP
|
||||
.B --rebind-domain-ok=[<domaine>]|[[/<domaine>/[<domaine>/]
|
||||
Ne pas détecter ni bloquer les actions de type dns-rebind pour ces domaines.
|
||||
Cette option peut prendre comme valeur soit un nom de domaine soit plusieurs
|
||||
noms de domains entourés par des '/', selon une syntaxe similaire à l'option
|
||||
noms de domaine entourés par des '/', selon une syntaxe similaire à l'option
|
||||
--server, c-à-d :
|
||||
.B --rebind-domain-ok=/domaine1/domaine2/domaine3/
|
||||
.TP
|
||||
@@ -474,7 +481,7 @@ serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine s
|
||||
laquelle tourne Dnsmasq ou sinon la ligne sera ignorée et une erreur sera
|
||||
consignée dans le journal des événements, ou alors d'un nom d'interface. Si un nom
|
||||
d'interface est donné, alors les requêtes vers le serveur de nom seront envoyées
|
||||
depuis cette interface; si une adresse ip est donnée, alors l'adresse source de
|
||||
depuis cette interface; si une adresse IP est donnée, alors l'adresse source de
|
||||
la requête sera l'adresse en question. L'option query-port est ignorée pour tous
|
||||
les serveurs ayant une adresse source spécifiée, mais il est possible de la donner
|
||||
directement dans la spécification de l'adresse source. Forcer les requêtes à être
|
||||
@@ -510,7 +517,7 @@ d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
|
||||
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
|
||||
ipset(8) pour plus de détails.
|
||||
.TP
|
||||
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
|
||||
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préférence>]
|
||||
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
|
||||
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
|
||||
l'option
|
||||
@@ -612,7 +619,7 @@ l'enregistrement est donnée dans les données hexadécimales, qui peuvent
|
||||
être de la forme 01:23:45, 01 23 45,+012345 ou n'importe quelle combinaison.
|
||||
.TP
|
||||
.B --interface-name=<nom>,<interface>
|
||||
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
|
||||
Définit un enregistrement DNS associant le nom avec l'adresse primaire sur
|
||||
l'interface donnée en argument. Cette option spécifie un enregistrement de type
|
||||
A pour le nom donné en argument de la même façon que s'il était défini par une
|
||||
ligne de /etc/hosts, sauf que l'adresse n'est pas constante mais dépendante de
|
||||
@@ -638,7 +645,7 @@ IPv6 pouvant commencer par '::', mais les noms DNS ne pouvant pas commencer
|
||||
par '-', si aucun préfixe n'est donné, un zéro est ajouté en début de nom.
|
||||
Ainsi, ::1 devient 0--1.
|
||||
|
||||
La plage d'adresses peut-être de la forme
|
||||
La plage d'adresses peut être de la forme
|
||||
<adresse IP>,<adresse IP> ou <adresse IP>/<masque réseau>
|
||||
.TP
|
||||
.B --add-mac
|
||||
@@ -647,7 +654,7 @@ amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
|
||||
amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le
|
||||
même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
|
||||
utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
|
||||
aussi cette fonctionalité doit être considérée comme expérimentale. Notez
|
||||
aussi cette fonctionnalité doit être considérée comme expérimentale. Notez
|
||||
également qu'exposer les adresses MAC de la sorte peut avoir des implications
|
||||
en termes de sécurité et de vie privée. L'avertissement donné pour --add-subnet
|
||||
s'applique également ici.
|
||||
@@ -659,19 +666,20 @@ longueur du préfixe : 32 (ou 128 dans le cas d'IPv6) transmet la totalité
|
||||
de l'adresse, 0 n'en transmet aucun mais marque néanmoins la requête ce qui
|
||||
fait qu'aucun serveur amont ne rajoutera d'adresse client. La valeur par
|
||||
défaut est zéro et pour IPv4 et pour IPv6. A noter que les serveurs amonts
|
||||
peuvent-être configurés pour retourner des valeurs différentes en fonction
|
||||
peuvent être configurés pour retourner des valeurs différentes en fonction
|
||||
de cette information mais que le cache de dnsmasq n'en tient pas compte.
|
||||
Si une instance de dnsmasq est configurée de telle maniêre que des valeurs
|
||||
différentes pourraient-être rencontrés, alors le cache devrait être désactivé.
|
||||
Si une instance de dnsmasq est configurée de telle manière que des valeurs
|
||||
différentes pourraient être rencontrées, alors le cache devrait être désactivé.
|
||||
.TP
|
||||
.B \-c, --cache-size=<taille>
|
||||
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
|
||||
Définir une valeur de zéro désactive le cache.
|
||||
Définir une valeur de zéro désactive le cache. Remarque: la taille importante
|
||||
du cache a un impact sur les performances.
|
||||
.TP
|
||||
.B \-N, --no-negcache
|
||||
Désactive le "cache négatif". Le "cache négatif" permet à Dnsmasq de se souvenir
|
||||
des réponses de type "no such domain" fournies par les serveurs DNS en amont et
|
||||
de fournir les réponses sans avoir à re-transmettre les requêtes aux serveurs
|
||||
de fournir les réponses sans avoir à retransmettre les requêtes aux serveurs
|
||||
amont.
|
||||
.TP
|
||||
.B \-0, --dns-forward-max=<nombre de requêtes>
|
||||
@@ -683,17 +691,17 @@ son journal des requêtes, ce qui peut générer un nombre important de requête
|
||||
simultanées.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Un resolveur sur une machine cliente peut effectuer la validation DNSSEC de
|
||||
Un résolveur sur une machine cliente peut effectuer la validation DNSSEC de
|
||||
deux façons : il peut effectuer lui-même les opérations de chiffrements sur
|
||||
la réponse reçue, ou il peut laisser le serveur récursif amont faire la
|
||||
validation et positionner un drapeau dans la réponse au cas où celle-ci est
|
||||
correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer
|
||||
la validation comme un serveur de nom récursif, cependant il peut retransmettre
|
||||
les résultats de validation de ses serveurs amonts. Cette option permet
|
||||
l'activation de cette fonctionalité. Vous ne devriez utiliser cela que si vous
|
||||
l'activation de cette fonctionnalité. Vous ne devriez utiliser cela que si vous
|
||||
faites confiance aux serveurs amonts
|
||||
.I ainsi que le réseau entre vous et eux.
|
||||
Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
||||
Si vous utilisez le premier mode DNSSEC, la validation par le résolveur des
|
||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.TP
|
||||
@@ -703,12 +711,12 @@ Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
|
||||
autorité. Les enregistrements DNS définis localement et correspondant à ce
|
||||
domaine seront fournis. Les enregistrements A et AAAA doivent se situer dans
|
||||
l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage DHCP
|
||||
(ce comportement peut-être désactivé par
|
||||
(ce comportement peut être désactivé par
|
||||
.B constructor-noauth:
|
||||
). Le ou les sous-réseaux sont également utilisé(s) pour définir les domaines
|
||||
in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
|
||||
IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait-être de 8, 16
|
||||
IPv6. Dans le cas d'IPv4, la longueur du masque de réseau devrait être de 8, 16
|
||||
ou 24, sauf si en cas de mise en place d'une délégation de la zone in-addr.arpa
|
||||
conforme au RFC 2317.
|
||||
.TP
|
||||
@@ -719,7 +727,7 @@ optionnel, les valeurs par défaut devant convenir à la majorité des cas.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
|
||||
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
|
||||
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
|
||||
laquelle dnsmasq fait autorité. Ces serveurs doivent être configurés pour
|
||||
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
|
||||
transfert de zone, et répondre aux requêtes pour toutes les zones pour
|
||||
lesquelles dnsmasq fait autorité.
|
||||
@@ -733,7 +741,7 @@ seront acceptées pour tous les serveurs secondaires.
|
||||
.B --conntrack
|
||||
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
|
||||
requêtes. Cela permet au trafic généré par Dnsmasq d'être associé aux requêtes
|
||||
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
|
||||
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
|
||||
avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||
@@ -742,7 +750,7 @@ configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
|
||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||
@@ -755,7 +763,7 @@ durée indéterminée. Si aucune valeur n'est donnée, une durée de bail par d
|
||||
de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2
|
||||
minutes.
|
||||
|
||||
Pour les plages IPv6, la durée de bail peut-être égale au mot-clef "deprecated"
|
||||
Pour les plages IPv6, la durée de bail peut être égale au mot-clef "deprecated"
|
||||
(obsolète); Cela positionne la durée de vie préférée envoyée dans les baux DHCP
|
||||
ou les annonces routeurs à zéro, ce qui incite les clients à utiliser d'autres
|
||||
adresses autant que possible, pour toute nouvelle connexion, en préalable à
|
||||
@@ -795,7 +803,7 @@ adresses assignées à l'interface. Par exemple
|
||||
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
|
||||
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
|
||||
plus d'un réseau, les plages correspondantes seront automatiquement créées,
|
||||
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
|
||||
rendues obsolètes puis supprimées lorsque l'adresse est rendue obsolète puis
|
||||
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
|
||||
final.
|
||||
|
||||
@@ -809,7 +817,7 @@ obsolètes ne conviennent pas.
|
||||
|
||||
Si une plage dhcp-range est uniquement utilisée pour du DHCP sans-état
|
||||
("stateless") ou de l'autoconfiguration sans état ("SLAAC"), alors l'adresse
|
||||
peut-être indiquée sous la forme '::'
|
||||
peut être indiquée sous la forme '::'
|
||||
|
||||
.B --dhcp-range=::,constructor:eth0
|
||||
|
||||
@@ -851,7 +859,7 @@ et
|
||||
.B pxe-service
|
||||
pour plus de détails).
|
||||
|
||||
Pour IPv6, le mode peut-être une combinaison des valeurs
|
||||
Pour IPv6, le mode peut être une combinaison des valeurs
|
||||
.B ra-only, slaac, ra-names, ra-stateless, off-link.
|
||||
|
||||
.B ra-only
|
||||
@@ -883,7 +891,7 @@ connectés (et non ceux pour lesquels DHCP se fait via relai), et ne
|
||||
fonctionnera pas si un hôte utilise les "extensions de vie privée"
|
||||
("privacy extensions").
|
||||
.B ra-names
|
||||
peut-être combiné avec
|
||||
peut être combiné avec
|
||||
.B ra-stateless
|
||||
et
|
||||
.B slaac.
|
||||
@@ -914,7 +922,7 @@ sous-réseau qu'une plage dhcp-range valide. Pour les sous-réseaux qui n'ont pa
|
||||
besoin d'adresses dynamiquement allouées, utiliser le mot-clef "static" dans la
|
||||
déclaration de plage d'adresses dhcp-range.
|
||||
|
||||
Il est possible d'utiliser des identifiants clients (appellé "DUID client" dans
|
||||
Il est possible d'utiliser des identifiants clients (appelés "DUID client" dans
|
||||
le monde IPv6) plutôt que des adresses matérielles pour identifier les hôtes,
|
||||
en préfixant ceux-ci par 'id:'. Ainsi,
|
||||
.B --dhcp-host=id:01:02:03:04,.....
|
||||
@@ -926,7 +934,7 @@ ceci :
|
||||
Un seul
|
||||
.B dhcp-host
|
||||
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
|
||||
Les adresses IPv6 doivent-être mises entre crochets comme suit :
|
||||
Les adresses IPv6 doivent être mises entre crochets comme suit :
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
@@ -945,7 +953,7 @@ identifiant client mais pas les autres.
|
||||
Si un nom apparaît dans /etc/hosts, l'adresse associée peut être allouée à un
|
||||
bail DHCP mais seulement si une option
|
||||
.B --dhcp-host
|
||||
spécifiant le nom existe par ailleurs. Seul un nom d'hôte peut-être donné dans
|
||||
spécifiant le nom existe par ailleurs. Seul un nom d'hôte peut être donné dans
|
||||
une option
|
||||
.B dhcp-host
|
||||
, mais les alias sont possibles au travers de l'utilisation des CNAMEs. (Voir
|
||||
@@ -973,7 +981,7 @@ Les adresses ethernet (mais pas les identifiants clients) peuvent être définie
|
||||
avec des octets joker, ainsi par exemple
|
||||
.B --dhcp-host=00:20:e0:3b:13:*,ignore
|
||||
demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est à noter
|
||||
que "*" doit-être précédé d'un caractère d'échappement ou mis entre guillemets
|
||||
que "*" doit être précédé d'un caractère d'échappement ou mis entre guillemets
|
||||
lorsque spécifié en option de ligne de commande, mais pas dans le fichier de
|
||||
configuration.
|
||||
|
||||
@@ -1059,14 +1067,14 @@ qu'aux réseaux dont tous les labels coïncident avec ceux de la requête.
|
||||
Un traitement spécial est effectué sur les chaînes de caractères fournies pour
|
||||
l'option 119, conformément à la RFC 3397. Les chaînes de caractères ou les
|
||||
adresses IP sous forme de 4 chiffres séparés par des points donnés en arguments
|
||||
de l'option 120 sont traités conforméments à la RFC 3361. Les adresses IP sous
|
||||
de l'option 120 sont traités conformément à la RFC 3361. Les adresses IP sous
|
||||
forme de 4 chiffres séparés par des points suivies par une barre montante "/",
|
||||
puis une taille de masque sont encodés conforméments à la RFC 3442.
|
||||
puis une taille de masque sont encodés conformément à la RFC 3442.
|
||||
|
||||
Les options IPv6 sont fournies en utilisant le mot-clef
|
||||
.B option6:
|
||||
suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options
|
||||
IPv6 est disjint de l'espace de nommage des options IPv4. Les adresses IPv6
|
||||
IPv6 est disjoint de l'espace de nommage des options IPv4. Les adresses IPv6
|
||||
en option doivent être entourées de crochets, comme par exemple :
|
||||
.B --dhcp-option=option6:ntp-server,[1234::56]
|
||||
|
||||
@@ -1075,7 +1083,7 @@ adéquat sont envoyées pour un numéro d'option donné, il est tout à fait pos
|
||||
de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
|
||||
incorrecte de cette option. Lorsque la valeur est un nombre décimal, Dnsmasq
|
||||
doit déterminer la taille des données. Cela est fait en examinant le numéro de
|
||||
l'option et/ou la valeur, mais peut-être évité en rajoutant un suffixe d'une
|
||||
l'option et/ou la valeur, mais peut être évité en rajoutant un suffixe d'une
|
||||
lettre comme suit :
|
||||
b = un octet, s = 2 octets, i = 4 octets. Cela sert essentiellement pour des
|
||||
options encapsulées de classes de vendeurs (voir plus bas), pour lesquelles
|
||||
@@ -1088,7 +1096,7 @@ d'une chaîne de caractères comme nom de serveur TFTP, il est nécessaire de fa
|
||||
comme suit :
|
||||
.B --dhcp-option=66,"1.2.3.4"
|
||||
|
||||
Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées
|
||||
Les options encapsulées de classes de vendeurs peuvent être aussi spécifiées
|
||||
(pour IPv4 seulement) en utilisant
|
||||
.B --dhcp-option
|
||||
: par exemple
|
||||
@@ -1105,7 +1113,7 @@ par le client. Il est possible d'omettre complètement une classe de vendeur :
|
||||
.B --dhcp-option=vendor:,1,0.0.0.0
|
||||
Dans ce cas l'option encapsulée est toujours envoyée.
|
||||
|
||||
En IPv4, les options peuvent-être encapsulées au sein d'autres options :
|
||||
En IPv4, les options peuvent être encapsulées au sein d'autres options :
|
||||
par exemple
|
||||
.B --dhcp-option=encap:175, 190, "iscsi-client0"
|
||||
enverra l'option 175, au sein de laquelle se trouve l'option 190.
|
||||
@@ -1128,7 +1136,7 @@ une option encapsulée.
|
||||
Cela fonctionne exactement de la même façon que
|
||||
.B --dhcp-option
|
||||
sauf que cette option sera toujours envoyée, même si le client ne la demande pas
|
||||
dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple lors
|
||||
dans la liste de paramètres requis. Cela est parfois nécessaire, par exemple lors
|
||||
de la fourniture d'options à PXELinux.
|
||||
.TP
|
||||
.B --dhcp-no-override
|
||||
@@ -1149,10 +1157,10 @@ Toutes les requêtes DHCP arrivant sur cette interface seront relayées au
|
||||
serveur DHCP distant correspondant à l'adresse de serveur indiquée. Il est
|
||||
possible de relayer depuis une unique adresse locale vers différents serveurs
|
||||
distant en spécifiant plusieurs fois l'option dhcp-relay avec la même adresse
|
||||
locale et différentes adresses de serveur. L'adresse de serveur doit-être
|
||||
sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut-être
|
||||
locale et différentes adresses de serveur. L'adresse de serveur doit être
|
||||
sous forme numérique. Dans le cas de DHCPv6, l'adresse de serveur peut être
|
||||
l'adresse de multicast ff05::1:3 correspondant à tous les serveurs DHCP. Dans
|
||||
ce cas, l'interface doit-étre spécifiée et ne peut comporter de caractère
|
||||
ce cas, l'interface doit être spécifiée et ne peut comporter de caractère
|
||||
joker. Elle sera utilisée pour indiquer l'interface à partir de laquelle le
|
||||
multicast pourra atteindre le serveur DHCP.
|
||||
|
||||
@@ -1181,14 +1189,14 @@ vice-versa.
|
||||
Associe une chaîne de classe de vendeur à un label. La plupart
|
||||
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
|
||||
représente, d'une certaine façon, le type d'hôte. Cette option associe des
|
||||
classes de vendeur à des labels, de telle sorte que des options DHCP peuvent-être
|
||||
fournie de manière sélective aux différentes classes d'hôtes. Par exemple,
|
||||
classes de vendeur à des labels, de telle sorte que des options DHCP peuvent être
|
||||
fournies de manière sélective aux différentes classes d'hôtes. Par exemple,
|
||||
.B dhcp-vendorclass=set:printers,Hewlett-Packard JetDirect
|
||||
ou
|
||||
.B dhcp-vendorclass=printers,Hewlett-Packard JetDirect
|
||||
permet de n'allouer des options qu'aux imprimantes HP de la manière suivante :
|
||||
.B --dhcp-option=tag:printers,3,192.168.4.4
|
||||
La chaîne de caractères de la classe de vendeur founie en argument est cherchée
|
||||
La chaîne de caractères de la classe de vendeur fournie en argument est cherchée
|
||||
en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie
|
||||
par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
|
||||
de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
|
||||
@@ -1218,7 +1226,7 @@ matérielle coïncide avec les critères définis.
|
||||
.TP
|
||||
.B --dhcp-circuitid=set:<label>,<identifiant de circuit>, --dhcp-remoteid=set:<label>,<identifiant distant>
|
||||
Associe des options de relais DHCP issus de la RFC3046 à des labels.
|
||||
Cette information peut-être fournie par des relais DHCP. L'identifiant
|
||||
Cette information peut être fournie par des relais DHCP. L'identifiant
|
||||
de circuit ou l'identifiant distant est normalement fourni sous la forme d'une
|
||||
chaîne de valeurs hexadécimales séparées par des ":", mais il est également
|
||||
possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
|
||||
@@ -1231,7 +1239,7 @@ est supporté en IPv6 (mais non dhcp-circuitid).
|
||||
(IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des
|
||||
labels.
|
||||
.TP
|
||||
.B --dhcp-proxy[=<adresse ip>]......
|
||||
.B --dhcp-proxy[=<adresse IP>]......
|
||||
(IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire
|
||||
suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois
|
||||
que le client est configuré, il communique directement avec le serveur. Cela
|
||||
@@ -1252,7 +1260,7 @@ interactions avec les relais dont l'adresse est dans la liste seront affectées.
|
||||
Si aucune valeur n'est spécifiée, associe le label si le client
|
||||
envoie une option DHCP avec le numéro ou le nom spécifié. Lorsqu'une valeur est
|
||||
fournie, positionne le label seulement dans le cas où l'option est fournie et
|
||||
correspond à la valeur. La valeur peut-être de la forme "01:ff:*:02", auquel
|
||||
correspond à la valeur. La valeur peut être de la forme "01:ff:*:02", auquel
|
||||
cas le début de l'option doit correspondre (en respectant les jokers). La
|
||||
valeur peut aussi être de la même forme que dans
|
||||
.B dhcp-option
|
||||
@@ -1262,14 +1270,14 @@ valeur peut aussi être de la même forme que dans
|
||||
--dhcp-match=set:efi-ia32,option:client-arch,6
|
||||
|
||||
spécifie le label "efi-ia32" si le numéro 6 apparaît dnas la liste
|
||||
d'architectures envoyé par le client au sein de l'option 93. (se réferer
|
||||
d'architectures envoyé par le client au sein de l'option 93. (se référer
|
||||
au RFC 4578 pour plus de détails). Si la valeur est un chaine de caractères,
|
||||
celle-ci est recherchée (correspondance en temps que sous-chaîne).
|
||||
|
||||
Pour la forme particulière vi-encap:<numéro d'entreprise>, la comparaison se
|
||||
fait avec les classes de vendeur "identifiant de vendeur" ("vendor-identifying
|
||||
vendor classes") pour l'entreprise dont le numéro est fourni en option.
|
||||
Veuillez vous réferer à la RFC 3925 pour plus de détail.
|
||||
Veuillez vous référer à la RFC 3925 pour plus de détails.
|
||||
.TP
|
||||
.B --tag-if=set:<label>[,set:<label>[,tag:<label>[,tag:<label>]]]
|
||||
Effectue une opération booléenne sur les labels. Si tous les labels
|
||||
@@ -1280,7 +1288,7 @@ Si aucun tag:<label> n'est spécifié, alors tous les labels fournis par
|
||||
set:<label> sont positionnés.
|
||||
N'importe quel nombre de set: ou tag: peuvent être fournis, et l'ordre est sans
|
||||
importance.
|
||||
Les lignes tag-if sont executées dans l'ordre, ce qui fait que si un label dans
|
||||
Les lignes tag-if sont exécutées dans l'ordre, ce qui fait que si un label dans
|
||||
tag:<label> est un label positionné par une rêgle
|
||||
.B tag-if,
|
||||
la ligne qui positionne le label doit précéder celle qui le teste.
|
||||
@@ -1320,17 +1328,17 @@ le cas de certains vieux clients BOOTP.
|
||||
(IPv4 seulement) Spécifie les options BOOTP devant être retournées par le
|
||||
serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils
|
||||
ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de
|
||||
la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
||||
la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq fournit un service TFTP (voir
|
||||
.B --enable-tftp
|
||||
), alors seul un nom de fichier est requis ici pour permettre un démarrage par
|
||||
le réseau.
|
||||
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
||||
ceux du client pour que cet élement de configuration lui soit envoyé.
|
||||
ceux du client pour que cet élément de configuration lui soit envoyé.
|
||||
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
|
||||
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
|
||||
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
|
||||
celles-ci seront utilisées tour à tour (algorithme round-robin).
|
||||
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
|
||||
Cela peut être utilisé pour équilibrer la charge tftp sur plusieurs serveurs.
|
||||
.TP
|
||||
.B --dhcp-sequential-ip
|
||||
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
|
||||
@@ -1357,7 +1365,7 @@ Ceci spécifie l'option de démarrage qui apparaitra dans un menu de démarrage
|
||||
PXE. <CSA> est le type du système client. Seuls des types de services valides
|
||||
apparaitront dans un menu. Les types connus sont x86PC, PC98, IA64_EFI, Alpha,
|
||||
Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI et X86-64_EFI;
|
||||
D'autres types peuvent-être spécifiés sous la forme d'une valeur entière. Le
|
||||
D'autres types peuvent être spécifiés sous la forme d'une valeur entière. Le
|
||||
paramètre après le texte correspondant à l'entrée dans le menu peut être un nom
|
||||
de fichier, auquel cas Dnsmasq agit comme un serveur de démarrage et indique au
|
||||
client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
|
||||
@@ -1376,7 +1384,7 @@ démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
|
||||
service), alors l'entrée de menu provoque l'interruption du démarrage par
|
||||
le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur
|
||||
peut être donnée sous la forme de nom de domaine qui est recherché dans
|
||||
/etc/hosts. Ce nom peut-être associé à plusieurs adresses IP, qui dans ce cas
|
||||
/etc/hosts. Ce nom peut être associé à plusieurs adresses IP, qui dans ce cas
|
||||
sont utilisées à tour de rôle (en "round-robin").
|
||||
.TP
|
||||
.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
|
||||
@@ -1435,7 +1443,7 @@ Utiliser cette option avec précaution, une adresse allouée à un client BOOTP
|
||||
étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si
|
||||
aucun argument n'est donné, alors cette option permet une allocation dynamique
|
||||
dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se
|
||||
fait que lorsque tous les identifiants coïncident. Il est possible de répeter
|
||||
fait que lorsque tous les identifiants coïncident. Il est possible de répéter
|
||||
cette option avec plusieurs jeux d'arguments.
|
||||
.TP
|
||||
.B \-5, --no-ping
|
||||
@@ -1560,7 +1568,7 @@ Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
|
||||
sont ouverts sur /dev/null (sauf en mode déverminage).
|
||||
|
||||
Le script n'est pas lancé de manière concurrente : au plus une instance du
|
||||
script est executée à la fois (dnsmasq attends qu'une instance de script se
|
||||
script est exécutée à la fois (dnsmasq attend qu'une instance de script se
|
||||
termine avant de lancer la suivante). Les changements dans la base des baux
|
||||
nécessitant le lancement du script sont placé en attente dans une queue jusqu'à
|
||||
terminaison d'une instance du script en cours. Si cette mise en queue fait que
|
||||
@@ -1575,7 +1583,7 @@ le script sera invoqué avec une action "old" pour tous les baux existants.
|
||||
|
||||
Il existe deux autres actions pouvant apparaître comme argument au script :
|
||||
"init" et "tftp". D'autres sont susceptibles d'être rajoutées dans le futur,
|
||||
aussi les scripts devraient-être écrits de sorte à ignorer les actions
|
||||
aussi les scripts devraient être écrits de sorte à ignorer les actions
|
||||
inconnues. "init" est décrite ci-dessous dans
|
||||
.B --leasefile-ro.
|
||||
L'action "tftp" est invoquée lorsqu'un transfert de fichier TFTP s'est
|
||||
@@ -1588,7 +1596,7 @@ Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
|
||||
créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être
|
||||
compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une
|
||||
seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales
|
||||
persistent entre les évênements liés aux baux. Le code Lua doit définir une
|
||||
persistent entre les événements liés aux baux. Le code Lua doit définir une
|
||||
fonction
|
||||
.B lease
|
||||
et peut fournir des fonctions
|
||||
@@ -1637,7 +1645,7 @@ et
|
||||
.B --dhcp-scriptuser
|
||||
Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
|
||||
doivent être exécutés. La valeur par défaut correspond à l'utilisateur root
|
||||
mais peut-être changée par le biais de cette option.
|
||||
mais peut être changée par le biais de cette option.
|
||||
.TP
|
||||
.B \-9, --leasefile-ro
|
||||
Supprimer complètement l'usage du fichier servant de base de donnée pour les
|
||||
@@ -1649,8 +1657,8 @@ biais de l'option
|
||||
être complètement gérée par le script sur un stockage externe. En addition aux
|
||||
actions décrites dans
|
||||
.B --dhcp-script,
|
||||
le script de changement d'état de bail est appellé une fois, au lancement de
|
||||
Dnsmasq, avec pour seul argument "init". Lorsqu'appellé de la sorte, le script
|
||||
le script de changement d'état de bail est appelé une fois, au lancement de
|
||||
Dnsmasq, avec pour seul argument "init". Lorsqu'appelé de la sorte, le script
|
||||
doit fournir l'état de la base de baux, dans le format de fichier de baux de
|
||||
Dnsmasq, sur sa sortie standard (stdout) et retourner un code de retour de 0.
|
||||
Positionner cette option provoque également une invocation du script de
|
||||
@@ -1692,20 +1700,20 @@ positionné à la première valeur de la directive "search" du fichier
|
||||
/etc/resolv.conf (ou équivalent).
|
||||
|
||||
La gamme d'adresses peut être de la forme
|
||||
<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple
|
||||
<adresse ip>. Voir
|
||||
<adresse IP>,<adresse IP> ou <adresse IP>/<masque de réseau> voire une simple
|
||||
<adresse IP>. Voir
|
||||
.B --dhcp-fqdn
|
||||
qui peut changer le comportement de dnsmasq relatif aux domaines.
|
||||
|
||||
Si la gamme d'adresse est fournie sous la forme
|
||||
<adresse ip>/<taille de réseau>, alors le drapeau "local" peut-être rajouté
|
||||
qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et
|
||||
<adresse IP>/<taille de réseau>, alors le drapeau "local" peut être rajouté
|
||||
qui a pour effet d'ajouter --local-declarations aux requêtes DNS directes et
|
||||
inverses. C-à-d
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
est identique à
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
La taille de réseau doit-être de 8, 16 ou 24 pour être valide.
|
||||
La taille de réseau doit être de 8, 16 ou 24 pour être valide.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
|
||||
@@ -1717,8 +1725,8 @@ ce nom est transféré au nouveau client. Si
|
||||
est spécifié, ce comportement change : les noms non qualifiés ne sont plus
|
||||
rajoutés dans le DNS, seuls les noms qualifiés le sont. Deux clients DHCP
|
||||
avec le même nom peuvent tous les deux garder le nom, pour peu que la partie
|
||||
relative au domaine soit différente (c-à-d que les noms pleinements qualifiés
|
||||
diffèrent). Pour d'assurer que tous les noms ont une partie domaine, il doit-y
|
||||
relative au domaine soit différente (c-à-d que les noms pleinement qualifiés
|
||||
diffèrent). Pour s'assurer que tous les noms ont une partie domaine, il doit y
|
||||
avoir au moins un
|
||||
.B --domain
|
||||
sans gamme d'adresses de spécifié lorsque l'option
|
||||
@@ -1735,7 +1743,7 @@ Windows de la mise à jour de serveurs Active Directory. Voir la RFC 4702 pour
|
||||
plus de détails.
|
||||
.TP
|
||||
.B --enable-ra
|
||||
Active la fonctionalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
|
||||
Active la fonctionnalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
|
||||
DHCPv6 ne gère pas la configuration complète du réseau de la même façon que
|
||||
DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour
|
||||
la création autonome d'adresse sont gérées par un protocole différent.
|
||||
@@ -1747,7 +1755,7 @@ dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
|
||||
la valeur d'adresse link-local appropriée parmi celles de la machine sur
|
||||
laquelle tourne dnsmasq.
|
||||
Par défaut, les bits "managed address" sont positionnés, et le bit "use SLAAC"
|
||||
("utiliser SLAAC") est réinitialisé. Cela peut-être changé pour des
|
||||
("utiliser SLAAC") est réinitialisé. Cela peut être changé pour des
|
||||
sous-réseaux donnés par le biais du mot clef de mode décris dans
|
||||
.B --dhcp-range.
|
||||
Les paramètres DNS du RFC6106 sont inclus dans les annonces. Par défaut,
|
||||
@@ -1759,16 +1767,16 @@ DNSSL.
|
||||
.B --ra-param=<interface>,[mtu:<valeur>|<interface>|off,][high,|low,]<intervalle d'annonce routeur>[,<durée de vie route>]
|
||||
Configure pour une interface donnée des valeurs pour les annonces routeurs
|
||||
différentes des valeurs par défaut. La valeur par défaut du champ priorité
|
||||
pour le routeur peut-être changée de "medium" (moyen) à "high" (haute) ou
|
||||
pour le routeur peut être changée de "medium" (moyen) à "high" (haute) ou
|
||||
"low" (basse). Par exemple :
|
||||
.B --ra-param=eth0,high,0.
|
||||
Un intervalle (en secondes) entre les annonces routeur peut-être fourni par :
|
||||
Un intervalle (en secondes) entre les annonces routeur peut être fourni par :
|
||||
.B --ra-param=eth0,60.
|
||||
La durée de vie de la route peut-être changée ou mise à zéro, auquel cas
|
||||
La durée de vie de la route peut être changée ou mise à zéro, auquel cas
|
||||
le routeur peut annoncer les préfixes mais pas de route :
|
||||
.B --ra-parm=eth0,0,0
|
||||
(une valeur de zéro pour l'intervalle signifie qu'il garde la valeur par défaut).
|
||||
Ces quatre paramètres peuvent-être configurés en une fois :
|
||||
Ces quatre paramètres peuvent être configurés en une fois :
|
||||
.B --ra-param=eth0,mtu:1280,low,60,1200
|
||||
La valeur pour l'interface peut inclure un caractère joker.
|
||||
.TP
|
||||
@@ -1776,7 +1784,7 @@ La valeur pour l'interface peut inclure un caractère joker.
|
||||
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
|
||||
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
|
||||
un accès en lecture est possible; les extensions tsize et blksize sont supportées
|
||||
(tsize est seulement supporté en mode octet). Sans argument optionel, le service
|
||||
(tsize est seulement supportée en mode octet). Sans argument optionnel, le service
|
||||
TFTP est fourni sur les mêmes interfaces que le service DHCP. Si une liste
|
||||
d'interfaces est fournie, cela définit les interfaces sur lesquelles le
|
||||
service TFTP sera activé.
|
||||
@@ -1847,9 +1855,9 @@ Un serveur TFTP écoute sur le port prédéfini 69 ("well-known port") pour
|
||||
l'initiation de la connexion, mais utilise également un port dynamiquement
|
||||
alloué pour chaque connexion. Normalement, ces ports sont alloués par
|
||||
le système d'exploitation, mais cette option permet de spécifier une gamme
|
||||
de ports à utiliser pour les transferts TFTP. Cela peut-être utile si
|
||||
de ports à utiliser pour les transferts TFTP. Cela peut être utile si
|
||||
TFTP doit traverser un dispositif garde-barrière ("firewall"). La valeur
|
||||
de début pour la plage de port ne peut-être inférieure à 1025 sauf si
|
||||
de début pour la plage de port ne peut être inférieure à 1025 sauf si
|
||||
dnsmasq tourne en temps que super-utilisateur ("root"). Le nombre de
|
||||
connexions TFTP concurrentes est limitée par la taille de la gamme de
|
||||
ports ainsi spécifiée.
|
||||
@@ -1859,8 +1867,8 @@ Un serveur TFTP écoute sur un numéro de port bien connu (69) pour l'initiation
|
||||
de la connexion, et alloue dynamiquement un port pour chaque connexion. Ces
|
||||
numéros de ports sont en principe alloués par le système d'exploitation, mais
|
||||
cette option permet de spécifier une gamme de ports à utiliser pour les
|
||||
transferts TFTP. Cela peut-être utile lorsque ceux-ci doivent traverser un
|
||||
dispositif garde-barrière ("firewall"). Le début de la plage ne peut-être
|
||||
transferts TFTP. Cela peut être utile lorsque ceux-ci doivent traverser un
|
||||
dispositif garde-barrière ("firewall"). Le début de la plage ne peut être
|
||||
inférieur à 1024 à moins que Dnsmasq ne fonctionne en temps que
|
||||
super-utilisateur ("root"). Le nombre maximal de connexions TFTP concurrentes
|
||||
est limitée par la taille de la plage de ports ainsi définie.
|
||||
@@ -1895,7 +1903,7 @@ par "--". Les lignes commençant par # sont des commentaires et sont ignorées.
|
||||
Pour les options qui ne peuvent-être spécifiées qu'une seule fois, celle du
|
||||
fichier de configuration prends le pas sur celle fournie en ligne de commande.
|
||||
Il est possible d'utiliser des guillemets afin d'éviter que les ",",":","." et
|
||||
"#" ne soit interprêtés, et il est possible d'utiliser les séquences
|
||||
"#" ne soient interprétés, et il est possible d'utiliser les séquences
|
||||
d'échappement suivantes : \\\\ \\" \\t \\e \\b \\r et \\n. Elles correspondent
|
||||
respectivement à la barre oblique descendante ("anti-slash"), guillemets doubles,
|
||||
tabulation, caractère d'échappement ("escape"), suppression ("backspace"), retour ("return") et
|
||||
@@ -1940,8 +1948,8 @@ traces dans un fichier (voir
|
||||
.B --log-facility
|
||||
), alors
|
||||
.B Dnsmasq
|
||||
ferme et re-rouvre le fichier de traces. Il faut noter que pendant cette
|
||||
opération Dnsmasq ne s'exécute pas en temps que "root". Lorsqu'il créé un
|
||||
ferme et rouvre le fichier de traces. Il faut noter que pendant cette
|
||||
opération Dnsmasq ne s'exécute pas en tant que "root". Lorsqu'il créé un
|
||||
fichier de traces pour la première fois, Dnsmasq change le propriétaire du
|
||||
fichier afin de le faire appartenir à l'utilisateur non "root" sous lequel
|
||||
Dnsmasq s'exécute. Le logiciel de rotation de fichiers de trace logrotate doit
|
||||
@@ -1983,7 +1991,7 @@ qu'une connexion PPP ne soit établie. Dans ce cas, Dnsmasq vérifie régulière
|
||||
pour voir si un fichier
|
||||
.I /etc/resolv.conf
|
||||
est créé. Dnsmasq peut être configuré pour lire plus d'un fichier resolv.conf.
|
||||
Cela est utile sur un ordinateur portable où PPP et DHCP peuvent-être utilisés :
|
||||
Cela est utile sur un ordinateur portable où PPP et DHCP peuvent être utilisés :
|
||||
Dnsmasq peut alors être configuré pour lire à la fois
|
||||
.I /etc/ppp/resolv.conf
|
||||
et
|
||||
@@ -2007,7 +2015,7 @@ ou alors en mettant leurs adresses dans un autre fichier, par exemple
|
||||
.I /etc/resolv.dnsmasq
|
||||
et en lançant Dnsmasq avec l'option
|
||||
.B \-r /etc/resolv.dnsmasq.
|
||||
Cette deuxième technique permet la mise-à-jour dynamique des addresses de
|
||||
Cette deuxième technique permet la mise-à-jour dynamique des adresses de
|
||||
serveurs DNS amont par le biais de PPP ou DHCP.
|
||||
.PP
|
||||
Les adresses dans /etc/hosts prennent le dessus sur celles fournies par le
|
||||
@@ -2067,10 +2075,10 @@ et pour affecter l'option envoyée, sur la base de la plage sélectionnée.
|
||||
|
||||
Ce système a évolué d'un système plus ancien et aux possibilités plus limitées,
|
||||
et pour des raisons de compatibilité "net:" peut être utilisé à la place de
|
||||
"tag:" et "set:" peut-être omis (à l'exception de
|
||||
"tag:" et "set:" peut être omis (à l'exception de
|
||||
.B dhcp-host,
|
||||
où "net:" peut-être utilisé à la place de "set:"). Pour les mêmes raisons, '#'
|
||||
peut-être utilisé à la place de '!' pour indiquer la négation.
|
||||
où "net:" peut être utilisé à la place de "set:"). Pour les mêmes raisons, '#'
|
||||
peut être utilisé à la place de '!' pour indiquer la négation.
|
||||
.PP
|
||||
Le serveur DHCP intégré dans Dnsmasq fonctionne également en temps que serveur
|
||||
BOOTP, pour peu que l'adresse MAC et l'adresse IP des clients soient fournies,
|
||||
@@ -2097,7 +2105,7 @@ scénarios de complexité croissante. Le pré-requis pour chacun de ces scénari
|
||||
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
|
||||
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
|
||||
capable d'effectuer la délégation de la zone en question. Pour la première
|
||||
partie de ces explications, nous allons appeller serveur.exemple.com
|
||||
partie de ces explications, nous allons appeler serveur.exemple.com
|
||||
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
|
||||
notre.zone.com la zone pour laquelle dnsmasq fait autorité.
|
||||
|
||||
@@ -2138,11 +2146,11 @@ notre.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
|
||||
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
|
||||
qui résout le problème de poule et d'oeuf consistant à trouver l'adresse IP
|
||||
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
|
||||
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
|
||||
fait désormais autorité pour notre.zone.com, il doit également fournir cet
|
||||
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
|
||||
enregistrement. Si l'adresse externe est statique, cela peut être réalisé par
|
||||
le biais d'une entrée dans
|
||||
.B /etc/hosts
|
||||
ou via un
|
||||
@@ -2194,7 +2202,7 @@ spécifiques, vous pouvez le faire via :
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
le nom) peuvent simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
1.2.3.0/24 :
|
||||
.nf
|
||||
@@ -2243,7 +2251,7 @@ celui fourni par
|
||||
.B --domain.
|
||||
Si l'option
|
||||
.B --dhcp-fqdn
|
||||
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
|
||||
est fournie, alors les noms pleinement qualifiés associés aux baux DHCP
|
||||
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
|
||||
à la zone.
|
||||
|
||||
@@ -2282,7 +2290,7 @@ Dnsmasq est capable de gérer le DNS et DHCP pour au moins un millier de clients
|
||||
Pour cela, la durée des bail ne doit pas être très courte (moins d'une heure).
|
||||
La valeur de
|
||||
.B --dns-forward-max
|
||||
peut-être augmentée : commencer par la rendre égale au nombre de clients et
|
||||
peut être augmentée : commencer par la rendre égale au nombre de clients et
|
||||
l'augmenter si le DNS semble lent. Noter que la performance du DNS dépends
|
||||
également de la performance des serveurs amonts. La taille du cache DNS peut-
|
||||
être augmentée : la limite en dur est de 10000 entrées et la valeur par défaut
|
||||
@@ -2306,7 +2314,7 @@ Il est possible d'utiliser Dnsmasq pour bloquer la publicité sur la toile
|
||||
en associant des serveurs de publicité bien connus à l'adresse 127.0.0.1 ou
|
||||
0.0.0.0 par le biais du fichier
|
||||
.B /etc/hosts
|
||||
ou d'un fichier d'hôte additionnel. Cette liste peut-être très longue, Dnsmasq
|
||||
ou d'un fichier d'hôte additionnel. Cette liste peut être très longue, Dnsmasq
|
||||
ayant été testé avec succès avec un million de noms. Cette taille de fichier
|
||||
nécessite un processeur à 1 Ghz et environ 60 Mo de RAM.
|
||||
|
||||
|
||||
1050
po/pt_BR.po
1050
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -125,7 +125,7 @@ address of its ethernet card. For the former to work, a machine needs to know it
|
||||
requests a DHCP lease. For dhcpcd, the -h option specifies this. The
|
||||
names may be anything as far as DHCP is concerned, but dnsmasq adds
|
||||
some limitations. By default the names must no have a domain part, ie
|
||||
they must just be a alphanumeric name, without any dots. This is a
|
||||
they must just be alphanumeric names, without any dots. This is a
|
||||
security feature to stop a machine on your network telling DHCP that
|
||||
its name is "www.microsoft.com" and thereby grabbing traffic which
|
||||
shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
48
src/auth.c
48
src/auth.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -103,7 +103,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp;
|
||||
int qtype, qclass;
|
||||
int qtype, qclass, rc;
|
||||
int nameoffset, axfroffset = 0;
|
||||
int q, anscount = 0, authcount = 0;
|
||||
struct crec *crecp;
|
||||
@@ -119,11 +119,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
struct cname *a, *candidate;
|
||||
unsigned int wclen;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(((char *)header) + qlen, 0,
|
||||
(limit - ((char *)header)) - qlen);
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
@@ -288,11 +283,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (!rec->issrv && hostname_isequal(name, rec->name))
|
||||
if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_MX)
|
||||
if (rc == 2 && qtype == T_MX)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
@@ -303,11 +298,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
|
||||
if (qtype == T_SRV)
|
||||
if (rc == 2 && qtype == T_SRV)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
@@ -338,13 +333,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (txt = daemon->rr; txt; txt = txt->next)
|
||||
if (hostname_isequal(name, txt->name))
|
||||
if ((rc = hostname_issubdomain(name, txt->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (txt->class == qtype)
|
||||
if (rc == 2 && txt->class == qtype)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, txt->class));
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
|
||||
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
|
||||
anscount++;
|
||||
@@ -352,10 +347,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (txt->class == C_IN && hostname_isequal(name, txt->name))
|
||||
if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_TXT)
|
||||
if (rc == 2 && qtype == T_TXT)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
@@ -366,10 +361,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (na = daemon->naptr; na; na = na->next)
|
||||
if (hostname_isequal(name, na->name))
|
||||
if ((rc = hostname_issubdomain(name, na->name)))
|
||||
{
|
||||
nxdomain = 0;
|
||||
if (qtype == T_NAPTR)
|
||||
if (rc == 2 && qtype == T_NAPTR)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
@@ -389,13 +384,13 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
#endif
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
if ((rc = hostname_issubdomain(name, intr->name)))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
nxdomain = 0;
|
||||
|
||||
if (flag)
|
||||
if (rc == 2 && flag)
|
||||
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
|
||||
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
|
||||
(local_query || filter_zone(zone, flag, &addrlist->addr)))
|
||||
@@ -441,8 +436,9 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
if (sockaddr_isequal(peer_addr, &peers->addr))
|
||||
break;
|
||||
|
||||
/* Refuse all AXFR unless --auth-sec-servers is set */
|
||||
if ((!peers && daemon->auth_peers) || !daemon->secondary_forward_server)
|
||||
/* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
|
||||
if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
|
||||
(daemon->auth_peers && !peers))
|
||||
{
|
||||
if (peer_addr->sa.sa_family == AF_INET)
|
||||
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
@@ -571,6 +567,8 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
goto cname_restart;
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -597,12 +595,12 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen >= 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
p += sprintf(p, "%u.in-addr.arpa", a & 0xff);
|
||||
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -25,7 +25,7 @@ static void blockdata_expand(int n)
|
||||
{
|
||||
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
|
||||
|
||||
if (n > 0 && new)
|
||||
if (new)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -49,7 +49,7 @@ void blockdata_init(void)
|
||||
|
||||
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
blockdata_expand((daemon->cachesize * 100) / sizeof(struct blockdata));
|
||||
blockdata_expand(daemon->cachesize);
|
||||
}
|
||||
|
||||
void blockdata_report(void)
|
||||
@@ -100,6 +100,7 @@ struct blockdata *blockdata_alloc(char *data, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void blockdata_free(struct blockdata *blocks)
|
||||
{
|
||||
struct blockdata *tmp;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -169,7 +169,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct in6_ifreq ifr6;
|
||||
|
||||
memset(&ifr6, 0, sizeof(ifr6));
|
||||
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
|
||||
|
||||
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
|
||||
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
|
||||
|
||||
446
src/cache.c
446
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -21,10 +21,12 @@ static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
|
||||
static struct crec *dhcp_spare = NULL;
|
||||
#endif
|
||||
static struct crec *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static int insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
|
||||
static void make_non_terminals(struct crec *source);
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
unsigned int type;
|
||||
@@ -45,6 +47,7 @@ static const struct {
|
||||
{ 24, "SIG" },
|
||||
{ 25, "KEY" },
|
||||
{ 28, "AAAA" },
|
||||
{ 29, "LOC" },
|
||||
{ 33, "SRV" },
|
||||
{ 35, "NAPTR" },
|
||||
{ 36, "KX" },
|
||||
@@ -57,13 +60,18 @@ static const struct {
|
||||
{ 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" }
|
||||
{ 255, "ANY" },
|
||||
{ 257, "CAA" }
|
||||
};
|
||||
|
||||
static void cache_free(struct crec *crecp);
|
||||
@@ -72,17 +80,20 @@ static void cache_link(struct crec *crecp);
|
||||
static void rehash(int size);
|
||||
static void cache_hash(struct crec *crecp);
|
||||
|
||||
static unsigned int next_uid(void)
|
||||
void next_uid(struct crec *crecp)
|
||||
{
|
||||
static unsigned int uid = 0;
|
||||
|
||||
uid++;
|
||||
if (crecp->uid == UID_NONE)
|
||||
{
|
||||
uid++;
|
||||
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == SRC_INTERFACE)
|
||||
uid++;
|
||||
|
||||
return uid;
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == UID_NONE)
|
||||
uid++;
|
||||
|
||||
crecp->uid = uid;
|
||||
}
|
||||
}
|
||||
|
||||
void cache_init(void)
|
||||
@@ -100,7 +111,7 @@ void cache_init(void)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = next_uid();
|
||||
crecp->uid = UID_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +210,7 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
|
||||
crecp->uid = UID_NONE; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
@@ -317,7 +328,8 @@ static int is_expired(time_t now, struct crec *crecp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags,
|
||||
struct crec **target_crec, unsigned int *target_uid)
|
||||
{
|
||||
/* Scan and remove old entries.
|
||||
If (flags & F_FORWARD) then remove any forward entries for name and any expired
|
||||
@@ -330,7 +342,10 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
|
||||
to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
|
||||
|
||||
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
|
||||
so that when we hit an entry which isn't reverse and is immortal, we're done. */
|
||||
so that when we hit an entry which isn't reverse and is immortal, we're done.
|
||||
|
||||
If we free a crec which is a CNAME target, return the entry and uid in target_crec and target_uid.
|
||||
This entry will get re-used with the same name, to preserve CNAMEs. */
|
||||
|
||||
struct crec *crecp, **up;
|
||||
|
||||
@@ -338,17 +353,6 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
|
||||
{
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||
{
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
|
||||
{
|
||||
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
|
||||
@@ -358,6 +362,16 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
|
||||
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
|
||||
return crecp;
|
||||
*up = crecp->hash_next;
|
||||
/* If this record is for the name we're inserting and is the target
|
||||
of a CNAME record. Make the new record for the same name, in the same
|
||||
crec, with the same uid to avoid breaking the existing CNAME. */
|
||||
if (crecp->uid != UID_NONE)
|
||||
{
|
||||
if (target_crec)
|
||||
*target_crec = crecp;
|
||||
if (target_uid)
|
||||
*target_uid = crecp->uid;
|
||||
}
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
continue;
|
||||
@@ -376,6 +390,18 @@ static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t no
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (is_expired(now, crecp) || is_outdated_cname_pointer(crecp))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
if (!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
{
|
||||
cache_unlink(crecp);
|
||||
cache_free(crecp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
}
|
||||
@@ -442,11 +468,12 @@ void cache_start_insert(void)
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags)
|
||||
{
|
||||
struct crec *new;
|
||||
struct crec *new, *target_crec = NULL;
|
||||
union bigname *big_name = NULL;
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int free_avail = 0;
|
||||
|
||||
unsigned int target_uid;
|
||||
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
{
|
||||
@@ -464,7 +491,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. */
|
||||
if ((new = cache_scan_free(name, addr, now, flags)))
|
||||
if ((new = cache_scan_free(name, addr, now, flags, &target_crec, &target_uid)))
|
||||
{
|
||||
/* We're trying to insert a record over one from
|
||||
/etc/hosts or DHCP, or other config. If the
|
||||
@@ -488,81 +515,89 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
}
|
||||
|
||||
/* Now get a cache entry from the end of the LRU list */
|
||||
while (1) {
|
||||
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* End of LRU list is still in use: if we didn't scan all the hash
|
||||
chains for expired entries do that now. If we already tried that
|
||||
then it's time to start spilling things. */
|
||||
|
||||
if (new->flags & (F_FORWARD | F_REVERSE))
|
||||
{
|
||||
/* If free_avail set, we believe that an entry has been freed.
|
||||
Bugs have been known to make this not true, resulting in
|
||||
a tight loop here. If that happens, abandon the
|
||||
insert. Once in this state, all inserts will probably fail. */
|
||||
if (free_avail)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Internal error in cache."));
|
||||
warned = 1;
|
||||
}
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (freed_all)
|
||||
{
|
||||
struct all_addr free_addr = new->addr.addr;;
|
||||
if (!target_crec)
|
||||
while (1) {
|
||||
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free entry at end of LRU list, use it. */
|
||||
if (!(new->flags & (F_FORWARD | F_REVERSE)))
|
||||
break;
|
||||
|
||||
/* End of LRU list is still in use: if we didn't scan all the hash
|
||||
chains for expired entries do that now. If we already tried that
|
||||
then it's time to start spilling things. */
|
||||
|
||||
/* If free_avail set, we believe that an entry has been freed.
|
||||
Bugs have been known to make this not true, resulting in
|
||||
a tight loop here. If that happens, abandon the
|
||||
insert. Once in this state, all inserts will probably fail. */
|
||||
if (free_avail)
|
||||
{
|
||||
static int warned = 0;
|
||||
if (!warned)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("Internal error in cache."));
|
||||
warned = 1;
|
||||
}
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (freed_all)
|
||||
{
|
||||
struct all_addr free_addr = new->addr.addr;;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* For DNSSEC records, addr holds class. */
|
||||
if (new->flags & (F_DS | F_DNSKEY))
|
||||
free_addr.addr.dnssec.class = new->uid;
|
||||
/* For DNSSEC records, addr holds class. */
|
||||
if (new->flags & (F_DS | F_DNSKEY))
|
||||
free_addr.addr.dnssec.class = new->uid;
|
||||
#endif
|
||||
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
cache_scan_free(cache_get_name(new), &free_addr, now, new->flags);
|
||||
cache_live_freed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_scan_free(NULL, NULL, now, 0);
|
||||
freed_all = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check if we need to and can allocate extra memory for a long name.
|
||||
If that fails, give up now, always succeed for DNSSEC records. */
|
||||
if (name && (strlen(name) > SMALLDNAME-1))
|
||||
{
|
||||
if (big_free)
|
||||
{
|
||||
big_name = big_free;
|
||||
big_free = big_free->next;
|
||||
}
|
||||
else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
|
||||
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
else if (bignames_left != 0)
|
||||
bignames_left--;
|
||||
|
||||
}
|
||||
|
||||
free_avail = 1; /* Must be free space now. */
|
||||
cache_scan_free(cache_get_name(new), &free_addr, now, new->flags, NULL, NULL);
|
||||
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_scan_free(NULL, NULL, now, 0, NULL, NULL);
|
||||
freed_all = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we need to and can allocate extra memory for a long name.
|
||||
If that fails, give up now, always succeed for DNSSEC records. */
|
||||
if (name && (strlen(name) > SMALLDNAME-1))
|
||||
{
|
||||
if (big_free)
|
||||
{
|
||||
big_name = big_free;
|
||||
big_free = big_free->next;
|
||||
}
|
||||
else if ((bignames_left == 0 && !(flags & (F_DS | F_DNSKEY))) ||
|
||||
!(big_name = (union bigname *)whine_malloc(sizeof(union bigname))))
|
||||
{
|
||||
insert_error = 1;
|
||||
return NULL;
|
||||
}
|
||||
else if (bignames_left != 0)
|
||||
bignames_left--;
|
||||
|
||||
}
|
||||
|
||||
/* Got the rest: finally grab entry. */
|
||||
cache_unlink(new);
|
||||
break;
|
||||
}
|
||||
/* If we freed a cache entry for our name which was a CNAME target, use that.
|
||||
and preserve the uid, so that existing CNAMES are not broken. */
|
||||
if (target_crec)
|
||||
{
|
||||
new = target_crec;
|
||||
new->uid = target_uid;
|
||||
}
|
||||
|
||||
/* Got the rest: finally grab entry. */
|
||||
cache_unlink(new);
|
||||
|
||||
new->flags = flags;
|
||||
if (big_name)
|
||||
@@ -609,13 +644,27 @@ void cache_end_insert(void)
|
||||
{
|
||||
cache_hash(new_chain);
|
||||
cache_link(new_chain);
|
||||
cache_inserted++;
|
||||
daemon->metrics[METRIC_DNS_CACHE_INSERTED]++;
|
||||
}
|
||||
new_chain = tmp;
|
||||
}
|
||||
new_chain = NULL;
|
||||
}
|
||||
|
||||
int cache_find_non_terminal(char *name, time_t now)
|
||||
{
|
||||
struct crec *crecp;
|
||||
|
||||
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
|
||||
if (!is_outdated_cname_pointer(crecp) &&
|
||||
!is_expired(now, crecp) &&
|
||||
(crecp->flags & F_FORWARD) &&
|
||||
hostname_isequal(name, cache_get_name(crecp)))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
@@ -776,15 +825,18 @@ static void add_hosts_cname(struct crec *target)
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (a->alias[1] != '*' &&
|
||||
hostname_isequal(cache_get_name(target), a->target) &&
|
||||
(crec = whine_malloc(sizeof(struct crec))))
|
||||
(crec = whine_malloc(SIZEOF_POINTER_CREC)))
|
||||
{
|
||||
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
|
||||
crec->ttd = a->ttl;
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
next_uid(target);
|
||||
crec->addr.cname.uid = target->uid;
|
||||
crec->uid = next_uid();
|
||||
crec->uid = UID_NONE;
|
||||
cache_hash(crec);
|
||||
make_non_terminals(crec);
|
||||
|
||||
add_hosts_cname(crec); /* handle chains */
|
||||
}
|
||||
}
|
||||
@@ -856,6 +908,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
cache->uid = index;
|
||||
memcpy(&cache->addr.addr, addr, addrlen);
|
||||
cache_hash(cache);
|
||||
make_non_terminals(cache);
|
||||
|
||||
/* don't need to do alias stuff for second and subsequent addresses. */
|
||||
if (!nameexists)
|
||||
@@ -976,8 +1029,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(sizeof(struct crec) +
|
||||
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
(cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
strcat(cache->name.sname, ".");
|
||||
@@ -987,7 +1039,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
|
||||
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
|
||||
name_count++;
|
||||
}
|
||||
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
|
||||
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
|
||||
{
|
||||
strcpy(cache->name.sname, canon);
|
||||
cache->flags = flags;
|
||||
@@ -1026,7 +1078,8 @@ void cache_reload(void)
|
||||
struct ds_config *ds;
|
||||
#endif
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
daemon->metrics[METRIC_DNS_CACHE_INSERTED] = 0;
|
||||
daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED] = 0;
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i], up = &hash_table[i]; cache; cache = tmp)
|
||||
@@ -1059,21 +1112,22 @@ void cache_reload(void)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (a->alias[1] != '*' &&
|
||||
hostname_isequal(a->target, intr->name) &&
|
||||
((cache = whine_malloc(sizeof(struct crec)))))
|
||||
((cache = whine_malloc(SIZEOF_POINTER_CREC))))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->ttd = a->ttl;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
cache->uid = next_uid();
|
||||
cache->uid = UID_NONE;
|
||||
cache_hash(cache);
|
||||
make_non_terminals(cache);
|
||||
add_hosts_cname(cache); /* handle chains */
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if ((cache = whine_malloc(sizeof(struct crec))) &&
|
||||
if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
@@ -1085,6 +1139,7 @@ void cache_reload(void)
|
||||
cache->addr.ds.digest = ds->digest_type;
|
||||
cache->uid = ds->class;
|
||||
cache_hash(cache);
|
||||
make_non_terminals(cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1099,7 +1154,7 @@ void cache_reload(void)
|
||||
for (nl = hr->names; nl; nl = nl->next)
|
||||
{
|
||||
if (hr->addr.s_addr != 0 &&
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
@@ -1108,7 +1163,7 @@ void cache_reload(void)
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||
(cache = whine_malloc(sizeof(struct crec))))
|
||||
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->ttd = hr->ttl;
|
||||
@@ -1185,7 +1240,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
if ((aliasc = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
aliasc = whine_malloc(sizeof(struct crec));
|
||||
aliasc = whine_malloc(SIZEOF_POINTER_CREC);
|
||||
|
||||
if (aliasc)
|
||||
{
|
||||
@@ -1196,9 +1251,11 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
aliasc->ttd = ttd;
|
||||
aliasc->name.namep = a->alias;
|
||||
aliasc->addr.cname.target.cache = target;
|
||||
next_uid(target);
|
||||
aliasc->addr.cname.uid = target->uid;
|
||||
aliasc->uid = next_uid();
|
||||
aliasc->uid = UID_NONE;
|
||||
cache_hash(aliasc);
|
||||
make_non_terminals(aliasc);
|
||||
add_dhcp_cname(aliasc, ttd);
|
||||
}
|
||||
}
|
||||
@@ -1238,7 +1295,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
else if (!(crec->flags & F_DHCP))
|
||||
{
|
||||
cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
|
||||
cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD), NULL, NULL);
|
||||
/* scan_free deletes all addresses associated with name */
|
||||
break;
|
||||
}
|
||||
@@ -1265,7 +1322,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
if (crec->flags & F_NEG)
|
||||
{
|
||||
flags |= F_REVERSE;
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
|
||||
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags, NULL, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1274,7 +1331,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
if ((crec = dhcp_spare))
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
else /* need new one */
|
||||
crec = whine_malloc(sizeof(struct crec));
|
||||
crec = whine_malloc(SIZEOF_POINTER_CREC);
|
||||
|
||||
if (crec) /* malloc may fail */
|
||||
{
|
||||
@@ -1285,14 +1342,108 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
crec->ttd = ttd;
|
||||
crec->addr.addr = *host_address;
|
||||
crec->name.namep = host_name;
|
||||
crec->uid = next_uid();
|
||||
crec->uid = UID_NONE;
|
||||
cache_hash(crec);
|
||||
make_non_terminals(crec);
|
||||
|
||||
add_dhcp_cname(crec, ttd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Called when we put a local or DHCP name into the cache.
|
||||
Creates empty cache entries for subnames (ie,
|
||||
for three.two.one, for two.one and one), without
|
||||
F_IPV4 or F_IPV6 or F_CNAME set. These convert
|
||||
NXDOMAIN answers to NoData ones. */
|
||||
static void make_non_terminals(struct crec *source)
|
||||
{
|
||||
char *name = cache_get_name(source);
|
||||
struct crec *crecp, *tmp, **up;
|
||||
int type = F_HOSTS | F_CONFIG;
|
||||
#ifdef HAVE_DHCP
|
||||
if (source->flags & F_DHCP)
|
||||
type = F_DHCP;
|
||||
#endif
|
||||
|
||||
/* First delete any empty entries for our new real name. Note that
|
||||
we only delete empty entries deriving from DHCP for a new DHCP-derived
|
||||
entry and vice-versa for HOSTS and CONFIG. This ensures that
|
||||
non-terminals from DHCP go when we reload DHCP and
|
||||
for HOSTS/CONFIG when we re-read. */
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = tmp)
|
||||
{
|
||||
tmp = crecp->hash_next;
|
||||
|
||||
if (!is_outdated_cname_pointer(crecp) &&
|
||||
(crecp->flags & F_FORWARD) &&
|
||||
(crecp->flags & type) &&
|
||||
!(crecp->flags & (F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS)) &&
|
||||
hostname_isequal(name, cache_get_name(crecp)))
|
||||
{
|
||||
*up = crecp->hash_next;
|
||||
#ifdef HAVE_DHCP
|
||||
if (type & F_DHCP)
|
||||
{
|
||||
crecp->next = dhcp_spare;
|
||||
dhcp_spare = crecp;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
free(crecp);
|
||||
break;
|
||||
}
|
||||
else
|
||||
up = &crecp->hash_next;
|
||||
}
|
||||
|
||||
while ((name = strchr(name, '.')))
|
||||
{
|
||||
name++;
|
||||
|
||||
/* Look for one existing, don't need another */
|
||||
for (crecp = *hash_bucket(name); crecp; crecp = crecp->hash_next)
|
||||
if (!is_outdated_cname_pointer(crecp) &&
|
||||
(crecp->flags & F_FORWARD) &&
|
||||
(crecp->flags & type) &&
|
||||
hostname_isequal(name, cache_get_name(crecp)))
|
||||
break;
|
||||
|
||||
if (crecp)
|
||||
{
|
||||
/* If the new name expires later, transfer that time to
|
||||
empty non-terminal entry. */
|
||||
if (!(crecp->flags & F_IMMORTAL))
|
||||
{
|
||||
if (source->flags & F_IMMORTAL)
|
||||
crecp->flags |= F_IMMORTAL;
|
||||
else if (difftime(crecp->ttd, source->ttd) < 0)
|
||||
crecp->ttd = source->ttd;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if ((source->flags & F_DHCP) && dhcp_spare)
|
||||
{
|
||||
crecp = dhcp_spare;
|
||||
dhcp_spare = dhcp_spare->next;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
crecp = whine_malloc(SIZEOF_POINTER_CREC);
|
||||
|
||||
if (crecp)
|
||||
{
|
||||
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
|
||||
crecp->ttd = source->ttd;
|
||||
crecp->name.namep = name;
|
||||
|
||||
cache_hash(crecp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_ID
|
||||
int cache_make_stat(struct txt_record *t)
|
||||
{
|
||||
@@ -1314,24 +1465,24 @@ int cache_make_stat(struct txt_record *t)
|
||||
break;
|
||||
|
||||
case TXT_STAT_INSERTS:
|
||||
sprintf(buff+1, "%d", cache_inserted);
|
||||
sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
|
||||
break;
|
||||
|
||||
case TXT_STAT_EVICTIONS:
|
||||
sprintf(buff+1, "%d", cache_live_freed);
|
||||
sprintf(buff+1, "%d", daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED]);
|
||||
break;
|
||||
|
||||
case TXT_STAT_MISSES:
|
||||
sprintf(buff+1, "%u", daemon->queries_forwarded);
|
||||
sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]);
|
||||
break;
|
||||
|
||||
case TXT_STAT_HITS:
|
||||
sprintf(buff+1, "%u", daemon->local_answer);
|
||||
sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
case TXT_STAT_AUTH:
|
||||
sprintf(buff+1, "%u", daemon->auth_answer);
|
||||
sprintf(buff+1, "%u", daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -1408,15 +1559,14 @@ static char *sanitise(char *name)
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
struct server *serv, *serv1;
|
||||
char *t = "";
|
||||
|
||||
my_syslog(LOG_INFO, _("time %lu"), (unsigned long)now);
|
||||
my_syslog(LOG_INFO, _("cache size %d, %d/%d cache insertions re-used unexpired cache entries."),
|
||||
daemon->cachesize, cache_live_freed, cache_inserted);
|
||||
daemon->cachesize, daemon->metrics[METRIC_DNS_CACHE_LIVE_FREED], daemon->metrics[METRIC_DNS_CACHE_INSERTED]);
|
||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||
daemon->queries_forwarded, daemon->local_answer);
|
||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED], daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]);
|
||||
#ifdef HAVE_AUTH
|
||||
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->auth_answer);
|
||||
my_syslog(LOG_INFO, _("queries for authoritative zones %u"), daemon->metrics[METRIC_DNS_AUTH_ANSWERED]);
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
blockdata_report();
|
||||
@@ -1454,6 +1604,7 @@ void dump_cache(time_t now)
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
{
|
||||
char *t = " ";
|
||||
char *a = daemon->addrbuff, *p = daemon->namebuff, *n = cache_get_name(cache);
|
||||
*a = 0;
|
||||
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
|
||||
@@ -1511,7 +1662,7 @@ void dump_cache(time_t now)
|
||||
/* ctime includes trailing \n - eat it */
|
||||
*(p-1) = 0;
|
||||
#endif
|
||||
my_syslog(LOG_INFO, daemon->namebuff);
|
||||
my_syslog(LOG_INFO, "%s", daemon->namebuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1554,9 +1705,13 @@ char *querystr(char *desc, unsigned short type)
|
||||
break;
|
||||
}
|
||||
|
||||
len += 3; /* braces, terminator */
|
||||
len += strlen(desc);
|
||||
|
||||
if (desc)
|
||||
{
|
||||
len += 2; /* braces */
|
||||
len += strlen(desc);
|
||||
}
|
||||
len++; /* terminator */
|
||||
|
||||
if (!buff || bufflen < len)
|
||||
{
|
||||
if (buff)
|
||||
@@ -1570,12 +1725,22 @@ char *querystr(char *desc, unsigned short type)
|
||||
|
||||
if (buff)
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "%s[%s]", desc, types);
|
||||
if (desc)
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "%s[%s]", desc, types);
|
||||
else
|
||||
sprintf(buff, "%s[type=%d]", desc, type);
|
||||
}
|
||||
else
|
||||
sprintf(buff, "%s[type=%d]", desc, type);
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "<%s>", types);
|
||||
else
|
||||
sprintf(buff, "type=%d", type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return buff ? buff : "";
|
||||
}
|
||||
|
||||
@@ -1593,6 +1758,19 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
{
|
||||
if (flags & F_KEYTAG)
|
||||
sprintf(daemon->addrbuff, arg, addr->addr.log.keytag, addr->addr.log.algo, addr->addr.log.digest);
|
||||
else if (flags & F_RCODE)
|
||||
{
|
||||
unsigned int rcode = addr->addr.rcode.rcode;
|
||||
|
||||
if (rcode == SERVFAIL)
|
||||
dest = "SERVFAIL";
|
||||
else if (rcode == REFUSED)
|
||||
dest = "REFUSED";
|
||||
else if (rcode == NOTIMP)
|
||||
dest = "not implemented";
|
||||
else
|
||||
sprintf(daemon->addrbuff, "%u", rcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
25
src/config.h
25
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -26,6 +26,7 @@
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
|
||||
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
|
||||
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
@@ -93,6 +94,9 @@ HAVE_DBUS
|
||||
support some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_UBUS
|
||||
define this if you want to link against libubus
|
||||
|
||||
HAVE_IDN
|
||||
define this if you want international domain name 2003 support.
|
||||
|
||||
@@ -116,6 +120,9 @@ HAVE_AUTH
|
||||
HAVE_DNSSEC
|
||||
include DNSSEC validator.
|
||||
|
||||
HAVE_DUMPFILE
|
||||
include code to dump packets to a libpcap-format file for debugging.
|
||||
|
||||
HAVE_LOOP
|
||||
include functionality to probe for and remove DNS forwarding loops.
|
||||
|
||||
@@ -131,14 +138,12 @@ NO_DHCP6
|
||||
NO_SCRIPT
|
||||
NO_LARGEFILE
|
||||
NO_AUTH
|
||||
NO_DUMPFILE
|
||||
NO_INOTIFY
|
||||
these are available to explicitly disable compile time options which would
|
||||
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
|
||||
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||
|
||||
NO_NETTLE_ECC
|
||||
Don't include the ECDSA cypher in DNSSEC validation. Needed for older Nettle versions.
|
||||
NO_GMP
|
||||
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
|
||||
|
||||
@@ -166,6 +171,7 @@ RESOLVFILE
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
#define HAVE_LOOP
|
||||
#define HAVE_DUMPFILE
|
||||
|
||||
/* Build options which require external libraries.
|
||||
|
||||
@@ -365,6 +371,10 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_LOOP
|
||||
#endif
|
||||
|
||||
#ifdef NO_DUMPFILE
|
||||
#undef HAVE_DUMPFILE
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
|
||||
#define HAVE_INOTIFY
|
||||
#endif
|
||||
@@ -453,8 +463,11 @@ static char *compile_opts =
|
||||
#ifndef HAVE_INOTIFY
|
||||
"no-"
|
||||
#endif
|
||||
"inotify";
|
||||
|
||||
"inotify "
|
||||
#ifndef HAVE_DUMPFILE
|
||||
"no-"
|
||||
#endif
|
||||
"dumpfile";
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
460
src/crypto.c
Normal file
460
src/crypto.c
Normal file
@@ -0,0 +1,460 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#include <nettle/ecdsa.h>
|
||||
#include <nettle/ecc-curve.h>
|
||||
#include <nettle/eddsa.h>
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Implement a "hash-function" to the nettle API, which simply returns
|
||||
the input data, concatenated into a single, statically maintained, buffer.
|
||||
|
||||
Used for the EdDSA sigs, which operate on the whole message, rather
|
||||
than a digest. */
|
||||
|
||||
struct null_hash_digest
|
||||
{
|
||||
uint8_t *buff;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
struct null_hash_ctx
|
||||
{
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static size_t null_hash_buff_sz = 0;
|
||||
static uint8_t *null_hash_buff = NULL;
|
||||
#define BUFF_INCR 128
|
||||
|
||||
static void null_hash_init(void *ctx)
|
||||
{
|
||||
((struct null_hash_ctx *)ctx)->len = 0;
|
||||
}
|
||||
|
||||
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
|
||||
{
|
||||
struct null_hash_ctx *ctx = ctxv;
|
||||
size_t new_len = ctx->len + length;
|
||||
|
||||
if (new_len > null_hash_buff_sz)
|
||||
{
|
||||
uint8_t *new;
|
||||
|
||||
if (!(new = whine_malloc(new_len + BUFF_INCR)))
|
||||
return;
|
||||
|
||||
if (null_hash_buff)
|
||||
{
|
||||
if (ctx->len != 0)
|
||||
memcpy(new, null_hash_buff, ctx->len);
|
||||
free(null_hash_buff);
|
||||
}
|
||||
|
||||
null_hash_buff_sz = new_len + BUFF_INCR;
|
||||
null_hash_buff = new;
|
||||
}
|
||||
|
||||
memcpy(null_hash_buff + ctx->len, src, length);
|
||||
ctx->len += length;
|
||||
}
|
||||
|
||||
|
||||
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
|
||||
{
|
||||
(void)length;
|
||||
|
||||
((struct null_hash_digest *)dst)->buff = null_hash_buff;
|
||||
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
|
||||
}
|
||||
|
||||
static struct nettle_hash null_hash = {
|
||||
"null_hash",
|
||||
sizeof(struct null_hash_ctx),
|
||||
sizeof(struct null_hash_digest),
|
||||
0,
|
||||
(nettle_hash_init_func *) null_hash_init,
|
||||
(nettle_hash_update_func *) null_hash_update,
|
||||
(nettle_hash_digest_func *) null_hash_digest
|
||||
};
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* We provide a "null" hash which returns the input data as digest. */
|
||||
if (strcmp(null_hash.name, name) == 0)
|
||||
return &null_hash;
|
||||
|
||||
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
|
||||
incompatibilities if sizeof(nettle_hashes) changes between library
|
||||
versions. It also #defines nettle_hashes, so use that to tell
|
||||
if we have the new facilities. */
|
||||
|
||||
#ifdef nettle_hashes
|
||||
return nettle_lookup_hash(name);
|
||||
#else
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static mpz_t y;
|
||||
static struct dsa_params *params = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (params == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(params = whine_malloc(sizeof(struct dsa_params))))
|
||||
return 0;
|
||||
|
||||
mpz_init(y);
|
||||
nettle_dsa_params_init(params);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(params->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(params->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(params->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_verify(params, y, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
|
||||
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (key_len != ED25519_KEY_SIZE ||
|
||||
sig_len != ED25519_SIGNATURE_SIZE ||
|
||||
digest_len != sizeof(struct null_hash_digest) ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
|
||||
which has a pointer to the actual data and a length, because the buffer
|
||||
may need to be extended during "hashing". */
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 15:
|
||||
return ed25519_sha512_verify(p,
|
||||
((struct null_hash_digest *)digest)->len,
|
||||
((struct null_hash_digest *)digest)->buff,
|
||||
sig);
|
||||
case 16:
|
||||
/* Ed448 when available */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
|
||||
case 15: case 16:
|
||||
return dnsmasq_eddsa_verify;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
|
||||
define which algo numbers we support. If algo_digest_name() returns
|
||||
non-NULL for an algorithm number, we assume that algorithm is
|
||||
supported by verify(). */
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
|
||||
case 2: return NULL; /* Diffie-Hellman */
|
||||
case 3: return "sha1"; /* DSA/SHA1 */
|
||||
case 5: return "sha1"; /* RSA/SHA1 */
|
||||
case 6: return "sha1"; /* DSA-NSEC3-SHA1 */
|
||||
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
|
||||
case 8: return "sha256"; /* RSA/SHA-256 */
|
||||
case 10: return "sha512"; /* RSA/SHA-512 */
|
||||
case 12: return NULL; /* ECC-GOST */
|
||||
case 13: return "sha256"; /* ECDSAP256SHA256 */
|
||||
case 14: return "sha384"; /* ECDSAP384SHA384 */
|
||||
case 15: return "null_hash"; /* ED25519 */
|
||||
case 16: return NULL; /* ED448 */
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
33
src/dbus.c
33
src/dbus.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -85,6 +85,9 @@ const char* introspection_xml_template =
|
||||
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
|
||||
" </method>\n"
|
||||
#endif
|
||||
" <method name=\"GetMetrics\">\n"
|
||||
" <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
|
||||
" </method>\n"
|
||||
" </interface>\n"
|
||||
"</node>\n";
|
||||
|
||||
@@ -613,6 +616,30 @@ static DBusMessage *dbus_del_lease(DBusMessage* message)
|
||||
}
|
||||
#endif
|
||||
|
||||
static DBusMessage *dbus_get_metrics(DBusMessage* message)
|
||||
{
|
||||
DBusMessage *reply = dbus_message_new_method_return(message);
|
||||
DBusMessageIter array, dict, iter;
|
||||
int i;
|
||||
|
||||
dbus_message_iter_init_append(reply, &iter);
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
|
||||
|
||||
for (i = 0; i < __METRIC_MAX; i++) {
|
||||
const char *key = get_metric_name(i);
|
||||
dbus_uint32_t value = daemon->metrics[i];
|
||||
|
||||
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
|
||||
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
|
||||
dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
|
||||
dbus_message_iter_close_container(&array, &dict);
|
||||
}
|
||||
|
||||
dbus_message_iter_close_container(&iter, &array);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
@@ -680,6 +707,10 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
reply = dbus_del_lease(message);
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(method, "GetMetrics") == 0)
|
||||
{
|
||||
reply = dbus_get_metrics(message);
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache = 1;
|
||||
else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -485,11 +485,11 @@ char *whichdevice(void)
|
||||
|
||||
void bindtodevice(char *device, int fd)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
strcpy(ifr.ifr_name, device);
|
||||
size_t len = strlen(device)+1;
|
||||
if (len > IFNAMSIZ)
|
||||
len = IFNAMSIZ;
|
||||
/* only allowed by root. */
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
|
||||
errno != EPERM)
|
||||
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -559,6 +559,7 @@ static const struct opttab_t {
|
||||
{ "nntp-server", 71, OT_ADDR_LIST },
|
||||
{ "irc-server", 74, OT_ADDR_LIST },
|
||||
{ "user-class", 77, 0 },
|
||||
{ "rapid-commit", 80, 0 },
|
||||
{ "FQDN", 81, OT_INTERNAL },
|
||||
{ "agent-id", 82, OT_INTERNAL },
|
||||
{ "client-arch", 93, 2 | OT_DEC },
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -54,6 +54,7 @@
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_RAPID_COMMIT 80
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
|
||||
13
src/dhcp.c
13
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -232,7 +232,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* ARP fiddling uses original interface even if we pretend to use a different one. */
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
|
||||
#endif
|
||||
|
||||
/* If the interface on which the DHCP request was received is an
|
||||
@@ -255,7 +255,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
|
||||
safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -279,7 +279,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
is_relay_reply = 1;
|
||||
iov.iov_len = sz;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||
safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -678,7 +678,7 @@ struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int h
|
||||
if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
|
||||
{
|
||||
/* overloaded, or configured not to check, loopback interface, return "not in use" */
|
||||
dummy.hash = 0;
|
||||
dummy.hash = hash;
|
||||
return &dummy;
|
||||
}
|
||||
else if (icmp_ping(addr))
|
||||
@@ -988,8 +988,7 @@ char *host_from_dns(struct in_addr addr)
|
||||
if (!legal_hostname(hostname))
|
||||
return NULL;
|
||||
|
||||
strncpy(daemon->dhcp_buff, hostname, 256);
|
||||
daemon->dhcp_buff[255] = 0;
|
||||
safe_strncpy(daemon->dhcp_buff, hostname, 256);
|
||||
strip_hostname(daemon->dhcp_buff);
|
||||
|
||||
return daemon->dhcp_buff;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
46
src/dhcp6.c
46
src/dhcp6.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -640,13 +640,20 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
return 0;
|
||||
|
||||
for (template = daemon->dhcp6; template; template = template->next)
|
||||
if (!(template->flags & CONTEXT_TEMPLATE))
|
||||
if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED)))
|
||||
{
|
||||
/* non-template entries, just fill in interface and local addresses */
|
||||
if (prefix <= template->prefix &&
|
||||
is_same_net6(local, &template->start6, template->prefix) &&
|
||||
is_same_net6(local, &template->end6, template->prefix))
|
||||
{
|
||||
/* First time found, do fast RA. */
|
||||
if (template->if_index != if_index || !IN6_ARE_ADDR_EQUAL(&template->local6, local))
|
||||
{
|
||||
ra_start_unsolicited(param->now, template);
|
||||
param->newone = 1;
|
||||
}
|
||||
|
||||
template->if_index = if_index;
|
||||
template->local6 = *local;
|
||||
}
|
||||
@@ -661,24 +668,33 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
setaddr6part(&end6, addr6part(&template->end6));
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
int flags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (flags & CONTEXT_OLD)
|
||||
/* If there's an absolute address context covering this address
|
||||
then don't construct one as well. */
|
||||
if (!(context->flags & CONTEXT_CONSTRUCTED))
|
||||
break;
|
||||
|
||||
if (context->if_index == if_index)
|
||||
{
|
||||
/* address went, now it's back */
|
||||
log_context(AF_INET6, context);
|
||||
/* fast RAs for a while */
|
||||
ra_start_unsolicited(param->now, context);
|
||||
param->newone = 1;
|
||||
/* Add address to name again */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
int cflags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (cflags & CONTEXT_OLD)
|
||||
{
|
||||
/* address went, now it's back, and on the same interface */
|
||||
log_context(AF_INET6, context);
|
||||
/* fast RAs for a while */
|
||||
ra_start_unsolicited(param->now, context);
|
||||
param->newone = 1;
|
||||
/* Add address to name again */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param->newname = 1;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#define NAMESERVER_PORT 53
|
||||
#define TFTP_PORT 69
|
||||
#define MIN_PORT 1024 /* first non-reserved port */
|
||||
#define MAX_PORT 65535u
|
||||
|
||||
#define IN6ADDRSZ 16
|
||||
@@ -75,6 +76,7 @@
|
||||
#define T_AXFR 252
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
#define T_CAA 257
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
|
||||
164
src/dnsmasq.c
164
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -48,6 +48,7 @@ int main (int argc, char **argv)
|
||||
long i, max_fd = sysconf(_SC_OPEN_MAX);
|
||||
char *baduser = NULL;
|
||||
int log_err;
|
||||
int chown_warn = 0;
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
cap_user_header_t hdr = NULL;
|
||||
cap_user_data_t data = NULL;
|
||||
@@ -77,7 +78,8 @@ int main (int argc, char **argv)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
sigaction(SIGCHLD, &sigact, NULL);
|
||||
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
|
||||
/* ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigaction(SIGPIPE, &sigact, NULL);
|
||||
@@ -118,6 +120,9 @@ int main (int argc, char **argv)
|
||||
daemon->namebuff = safe_malloc(MAXDNAME * 2);
|
||||
daemon->keyname = safe_malloc(MAXDNAME * 2);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME * 2);
|
||||
/* one char flag per possible RR in answer section (may get extended). */
|
||||
daemon->rr_status_sz = 64;
|
||||
daemon->rr_status = safe_malloc(daemon->rr_status_sz);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -211,7 +216,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_AUTH
|
||||
if (daemon->authserver)
|
||||
if (daemon->auth_zones)
|
||||
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
@@ -220,21 +225,30 @@ int main (int argc, char **argv)
|
||||
die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (daemon->max_port != MAX_PORT && daemon->min_port == 0)
|
||||
daemon->min_port = 1024u;
|
||||
|
||||
#ifndef HAVE_UBUS
|
||||
if (option_bool(OPT_UBUS))
|
||||
die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (daemon->max_port < daemon->min_port)
|
||||
die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF);
|
||||
|
||||
now = dnsmasq_time();
|
||||
|
||||
/* Create a serial at startup if not configured. */
|
||||
if (daemon->authinterface && daemon->soa_sn == 0)
|
||||
if (daemon->auth_zones)
|
||||
{
|
||||
if (!daemon->authserver)
|
||||
die(_("--auth-server required when an auth zone is defined."), NULL, EC_BADCONF);
|
||||
|
||||
/* Create a serial at startup if not configured. */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
|
||||
if (daemon_>soa_sn == 0)
|
||||
die(_("zone serial must be configured in --auth-soa"), NULL, EC_BADCONF);
|
||||
#else
|
||||
daemon->soa_sn = now;
|
||||
if (daemon->soa_sn == 0)
|
||||
daemon->soa_sn = now;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (daemon->dhcp6)
|
||||
@@ -358,12 +372,22 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY
|
||||
if (daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
||||
if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
||||
&& (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
|
||||
inotify_dnsmasq_init();
|
||||
else
|
||||
daemon->inotifyfd = -1;
|
||||
#endif
|
||||
|
||||
|
||||
if (daemon->dump_file)
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_init();
|
||||
else
|
||||
daemon->dumpfd = -1;
|
||||
#else
|
||||
die(_("Packet dumps not available: set HAVE_DUMP in src/config.h"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
@@ -386,10 +410,12 @@ int main (int argc, char **argv)
|
||||
daemon->scriptuser &&
|
||||
(daemon->lease_change_command || daemon->luascript))
|
||||
{
|
||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||
struct passwd *scr_pw;
|
||||
|
||||
if ((scr_pw = getpwnam(daemon->scriptuser)))
|
||||
{
|
||||
script_uid = ent_pw->pw_uid;
|
||||
script_gid = ent_pw->pw_gid;
|
||||
script_uid = scr_pw->pw_uid;
|
||||
script_gid = scr_pw->pw_gid;
|
||||
}
|
||||
else
|
||||
baduser = daemon->scriptuser;
|
||||
@@ -537,9 +563,18 @@ int main (int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're still running as root here. Change the ownership of the PID file
|
||||
to the user we will be running as. Note that this is not to allow
|
||||
us to delete the file, since that depends on the permissions
|
||||
of the directory containing the file. That directory will
|
||||
need to by owned by the dnsmasq user, and the ownership of the
|
||||
file has to match, to keep systemd >273 happy. */
|
||||
if (getuid() == 0 && ent_pw && ent_pw->pw_uid != 0 && fchown(fd, ent_pw->pw_uid, ent_pw->pw_gid) == -1)
|
||||
chown_warn = errno;
|
||||
|
||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, strlen(daemon->namebuff), 0))
|
||||
err = 1;
|
||||
else
|
||||
else
|
||||
{
|
||||
while (retry_send(close(fd)));
|
||||
if (errno != 0)
|
||||
@@ -717,7 +752,11 @@ int main (int argc, char **argv)
|
||||
else
|
||||
{
|
||||
if (daemon->cachesize != 0)
|
||||
my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
|
||||
{
|
||||
my_syslog(LOG_INFO, _("started, version %s cachesize %d"), VERSION, daemon->cachesize);
|
||||
if (daemon->cachesize > 10000)
|
||||
my_syslog(LOG_WARNING, _("cache size greater than 10000 may cause performance issues, and is unlikely to be useful."));
|
||||
}
|
||||
else
|
||||
my_syslog(LOG_INFO, _("started, version %s cache disabled"), VERSION);
|
||||
|
||||
@@ -726,6 +765,9 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||
|
||||
if (chown_warn != 0)
|
||||
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (option_bool(OPT_DBUS))
|
||||
@@ -741,7 +783,8 @@ int main (int argc, char **argv)
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
int rc;
|
||||
|
||||
struct ds_config *ds;
|
||||
|
||||
/* Delay creating the timestamp file until here, after we've changed user, so that
|
||||
it has the correct owner to allow updating the mtime later.
|
||||
This means we have to report fatal errors via the pipe. */
|
||||
@@ -751,14 +794,21 @@ int main (int argc, char **argv)
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
if (option_bool(OPT_DNSSEC_IGN_NS))
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled but all unsigned answers are trusted"));
|
||||
else
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
|
||||
daemon->dnssec_no_time_check = option_bool(OPT_DNSSEC_TIME);
|
||||
if (option_bool(OPT_DNSSEC_TIME) && !daemon->back_to_the_future)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until receipt of SIGINT"));
|
||||
|
||||
if (rc == 1)
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
|
||||
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
my_syslog(LOG_INFO, _("configured with trust anchor for %s keytag %u"),
|
||||
ds->name[0] == 0 ? "<root>" : ds->name, ds->keytag);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -909,8 +959,13 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
set_dbus_listeners();
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (option_bool(OPT_UBUS))
|
||||
set_ubus_listeners();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->relay4)
|
||||
{
|
||||
@@ -1040,7 +1095,12 @@ int main (int argc, char **argv)
|
||||
}
|
||||
check_dbus_listeners();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
if (option_bool(OPT_UBUS))
|
||||
check_ubus_listeners();
|
||||
#endif
|
||||
|
||||
check_dns_listeners(now);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
@@ -1079,7 +1139,7 @@ static void sig_handler(int sig)
|
||||
{
|
||||
/* ignore anything other than TERM during startup
|
||||
and in helper proc. (helper ignore TERM too) */
|
||||
if (sig == SIGTERM)
|
||||
if (sig == SIGTERM || sig == SIGINT)
|
||||
exit(EC_MISC);
|
||||
}
|
||||
else if (pid != getpid())
|
||||
@@ -1105,6 +1165,15 @@ static void sig_handler(int sig)
|
||||
event = EVENT_DUMP;
|
||||
else if (sig == SIGUSR2)
|
||||
event = EVENT_REOPEN;
|
||||
else if (sig == SIGINT)
|
||||
{
|
||||
/* Handle SIGINT normally in debug mode, so
|
||||
ctrl-c continues to operate. */
|
||||
if (option_bool(OPT_DEBUG))
|
||||
exit(EC_MISC);
|
||||
else
|
||||
event = EVENT_TIME;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
@@ -1187,31 +1256,40 @@ static void fatal_event(struct event_desc *ev, char *msg)
|
||||
|
||||
case EVENT_FORK_ERR:
|
||||
die(_("cannot fork into background: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_PIPE_ERR:
|
||||
die(_("failed to create helper: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_CAP_ERR:
|
||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_USER_ERR:
|
||||
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_GROUP_ERR:
|
||||
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_PIDFILE:
|
||||
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_LOG_ERR:
|
||||
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_LUA_ERR:
|
||||
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||
|
||||
/* fall through */
|
||||
case EVENT_TFTP_ERR:
|
||||
die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
|
||||
|
||||
|
||||
/* fall through */
|
||||
case EVENT_TIME_ERR:
|
||||
die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
|
||||
}
|
||||
@@ -1232,14 +1310,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
daemon->soa_sn++; /* Bump zone serial, as it may have changed. */
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
daemon->dnssec_no_time_check = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fall through */
|
||||
|
||||
case EVENT_INIT:
|
||||
@@ -1348,6 +1419,17 @@ static void async_event(int pipe, time_t now)
|
||||
poll_resolv(0, 1, now);
|
||||
break;
|
||||
|
||||
case EVENT_TIME:
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (daemon->dnssec_no_time_check && option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
daemon->dnssec_no_time_check = 0;
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case EVENT_TERM:
|
||||
/* Knock all our children on the head. */
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
@@ -1382,6 +1464,11 @@ static void async_event(int pipe, time_t now)
|
||||
|
||||
if (daemon->runfile)
|
||||
unlink(daemon->runfile);
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
if (daemon->dumpfd != -1)
|
||||
close(daemon->dumpfd);
|
||||
#endif
|
||||
|
||||
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
|
||||
flush_log();
|
||||
@@ -1472,9 +1559,6 @@ void clear_cache_and_reload(time_t now)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
#ifdef HAVE_INOTIFY
|
||||
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
|
||||
#endif
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
lease_update_from_configs();
|
||||
lease_update_file(now);
|
||||
|
||||
159
src/dnsmasq.h
159
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,13 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2017 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2018 Simon Kelley"
|
||||
|
||||
/* We do defines that influence behavior of stdio.h, so complain
|
||||
if included too early. */
|
||||
#ifdef _STDIO_H
|
||||
# error "Header file stdio.h included too early!"
|
||||
#endif
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -36,6 +42,12 @@
|
||||
# define __EXTENSIONS__
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__clang__)
|
||||
#define ATTRIBUTE_NORETURN __attribute__ ((noreturn))
|
||||
#else
|
||||
#define ATTRIBUTE_NORETURN
|
||||
#endif
|
||||
|
||||
/* get these before config.h for IPv6 stuff... */
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -51,6 +63,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "ip6addr.h"
|
||||
#include "metrics.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
@@ -113,6 +126,9 @@ typedef unsigned long long u64;
|
||||
#include <net/if_arp.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#ifdef HAVE_IPV6
|
||||
#include <netinet/ip6.h>
|
||||
#endif
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <sys/uio.h>
|
||||
#include <syslog.h>
|
||||
@@ -136,6 +152,10 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
||||
#include <priv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
# include <nettle/nettle-meta.h>
|
||||
#endif
|
||||
|
||||
/* daemon is function in the C library.... */
|
||||
#define daemon dnsmasq_daemon
|
||||
|
||||
@@ -169,6 +189,7 @@ struct event_desc {
|
||||
#define EVENT_NEWROUTE 23
|
||||
#define EVENT_TIME_ERR 24
|
||||
#define EVENT_SCRIPT_LOG 25
|
||||
#define EVENT_TIME 26
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -230,7 +251,7 @@ struct event_desc {
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_DNSSEC_TIME 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_DNSSEC_IGN_NS 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LOOP_DETECT 50
|
||||
#define OPT_EXTRALOG 51
|
||||
@@ -239,7 +260,9 @@ struct event_desc {
|
||||
#define OPT_MAC_B64 54
|
||||
#define OPT_MAC_HEX 55
|
||||
#define OPT_TFTP_APREF_MAC 56
|
||||
#define OPT_LAST 57
|
||||
#define OPT_RAPID_COMMIT 57
|
||||
#define OPT_UBUS 58
|
||||
#define OPT_LAST 59
|
||||
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||
@@ -256,7 +279,11 @@ struct all_addr {
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest;
|
||||
} log;
|
||||
} log;
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned int rcode;
|
||||
} rcode;
|
||||
/* for cache_insert of DNSKEY, DS */
|
||||
struct {
|
||||
unsigned short class, type;
|
||||
@@ -415,6 +442,9 @@ struct crec {
|
||||
} name;
|
||||
};
|
||||
|
||||
#define SIZEOF_BARE_CREC (sizeof(struct crec) - SMALLDNAME)
|
||||
#define SIZEOF_POINTER_CREC (sizeof(struct crec) + sizeof(char *) - SMALLDNAME)
|
||||
|
||||
#define F_IMMORTAL (1u<<0)
|
||||
#define F_NAMEP (1u<<1)
|
||||
#define F_REVERSE (1u<<2)
|
||||
@@ -446,9 +476,15 @@ struct crec {
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
#define F_NOEXTRA (1u<<27)
|
||||
#define F_SERVFAIL (1u<<28)
|
||||
#define F_RCODE (1u<<29)
|
||||
|
||||
#define UID_NONE 0
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
/* cname to uid SRC_INTERFACE are to interface names,
|
||||
so use UID_NONE for that to eliminate clashes with
|
||||
any other uid */
|
||||
#define SRC_INTERFACE UID_NONE
|
||||
#define SRC_CONFIG 1
|
||||
#define SRC_HOSTS 2
|
||||
#define SRC_AH 3
|
||||
@@ -493,7 +529,7 @@ struct serverfd {
|
||||
int fd;
|
||||
union mysockaddr source_addr;
|
||||
char interface[IF_NAMESIZE+1];
|
||||
unsigned int ifindex, used;
|
||||
unsigned int ifindex, used, preallocated;
|
||||
struct serverfd *next;
|
||||
};
|
||||
|
||||
@@ -508,6 +544,7 @@ struct server {
|
||||
struct serverfd *sfd;
|
||||
char *domain; /* set if this server only handles a domain. */
|
||||
int flags, tcpfd, edns_pktsz;
|
||||
time_t pktsz_reduced;
|
||||
unsigned int queries, failed_queries;
|
||||
#ifdef HAVE_LOOP
|
||||
u32 uid;
|
||||
@@ -579,6 +616,16 @@ struct hostsfile {
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
/* packet-dump flags */
|
||||
#define DUMP_QUERY 0x0001
|
||||
#define DUMP_REPLY 0x0002
|
||||
#define DUMP_UP_QUERY 0x0004
|
||||
#define DUMP_UP_REPLY 0x0008
|
||||
#define DUMP_SEC_QUERY 0x0010
|
||||
#define DUMP_SEC_REPLY 0x0020
|
||||
#define DUMP_BOGUS 0x0040
|
||||
#define DUMP_SEC_BOGUS 0x0080
|
||||
|
||||
|
||||
/* DNSSEC status values. */
|
||||
#define STAT_SECURE 1
|
||||
@@ -784,6 +831,13 @@ struct dhcp_boot {
|
||||
struct dhcp_boot *next;
|
||||
};
|
||||
|
||||
struct dhcp_match_name {
|
||||
char *name;
|
||||
int wildcard;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_match_name *next;
|
||||
};
|
||||
|
||||
struct pxe_service {
|
||||
unsigned short CSA, type;
|
||||
char *menu, *basename, *sname;
|
||||
@@ -826,7 +880,7 @@ struct cond_domain {
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr start6, end6;
|
||||
#endif
|
||||
int is6;
|
||||
int is6, indexed;
|
||||
struct cond_domain *next;
|
||||
};
|
||||
|
||||
@@ -976,6 +1030,7 @@ extern struct daemon {
|
||||
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_vendor *dhcp_vendors;
|
||||
struct dhcp_mac *dhcp_macs;
|
||||
struct dhcp_boot *boot_config;
|
||||
@@ -1001,14 +1056,15 @@ extern struct daemon {
|
||||
unsigned int duid_enterprise, duid_config_len;
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
char *dump_file;
|
||||
int dump_mask;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
u32 metrics[__METRIC_MAX];
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *prefix_classes;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct ds_config *ds;
|
||||
int dnssec_no_time_check;
|
||||
int back_to_the_future;
|
||||
char *timestamp_file;
|
||||
#endif
|
||||
|
||||
@@ -1019,8 +1075,11 @@ extern struct daemon {
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
char *rr_status; /* flags for individual RRs */
|
||||
int rr_status_sz;
|
||||
int dnssec_no_time_check;
|
||||
int back_to_the_future;
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
struct serverfd *sfds;
|
||||
struct irec *interfaces;
|
||||
@@ -1073,13 +1132,19 @@ extern struct daemon {
|
||||
char *addrbuff;
|
||||
char *addrbuff2; /* only allocated when OPT_EXTRALOG */
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
/* file for packet dumps. */
|
||||
int dumpfd;
|
||||
#endif
|
||||
} *daemon;
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void next_uid(struct crec *crecp);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
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,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned int prot);
|
||||
@@ -1130,18 +1195,18 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
time_t now, char **ipsets, int is_sign, int checkrebind,
|
||||
int no_cache, int secure, int *doctored);
|
||||
unsigned long ttl);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
struct bogus_addr *baddr, time_t now);
|
||||
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
@@ -1162,30 +1227,41 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||
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);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
|
||||
int check_unsigned, int *neganswer, int *nons);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
int setup_timestamp(void);
|
||||
|
||||
/* crypto.c */
|
||||
const struct nettle_hash *hash_find(char *name);
|
||||
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp);
|
||||
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
char *ds_digest_name(int digest);
|
||||
char *algo_digest_name(int algo);
|
||||
char *nsec3_digest_name(int digest);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
unsigned short rand16(void);
|
||||
u32 rand32(void);
|
||||
u64 rand64(void);
|
||||
int legal_hostname(char *c);
|
||||
char *canonicalise(char *s, int *nomem);
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
|
||||
int legal_hostname(char *name);
|
||||
char *canonicalise(char *in, int *nomem);
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
|
||||
void *safe_malloc(size_t size);
|
||||
void safe_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 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);
|
||||
@@ -1209,10 +1285,12 @@ int wildcard_match(const char* wildcard, const char* match);
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN;
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
int log_reopen(char *log_file);
|
||||
|
||||
void my_syslog(int priority, const char *format, ...);
|
||||
|
||||
void set_log_writer(void);
|
||||
void check_log_writer(int force);
|
||||
void flush_log(void);
|
||||
@@ -1240,13 +1318,13 @@ struct frec *get_new_frec(time_t now, int *wait, int force);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
void resend_query();
|
||||
void resend_query(void);
|
||||
struct randfd *allocate_rfd(int family);
|
||||
void free_rfd(struct randfd *rfd);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
@@ -1260,12 +1338,12 @@ void add_update_server(int flags,
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
void create_bound_listeners(int dienow);
|
||||
void warn_bound_listeners(void);
|
||||
void warn_wild_labels(void);
|
||||
void warn_int_names(void);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth);
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||
int label_exception(int index, int family, struct all_addr *addr);
|
||||
int fix_fd(int fd);
|
||||
@@ -1286,7 +1364,7 @@ void newaddress(time_t now);
|
||||
void dhcp_init(void);
|
||||
void dhcp_packet(time_t now, int pxe_fd);
|
||||
struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
struct in_addr addr,
|
||||
struct in_addr taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
struct in_addr taddr,
|
||||
@@ -1345,7 +1423,7 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
|
||||
#ifdef HAVE_DHCP
|
||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
size_t sz, time_t now, int unicast_dest, int loopback,
|
||||
int *is_inform, int pxe_fd, struct in_addr fallback, time_t recvtime);
|
||||
int *is_inform, int pxe, struct in_addr fallback, time_t recvtime);
|
||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||
int clid_len, unsigned char *clid, int *len_out);
|
||||
#endif
|
||||
@@ -1389,6 +1467,13 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ubus.c */
|
||||
#ifdef HAVE_UBUS
|
||||
void set_ubus_listeners(void);
|
||||
void check_ubus_listeners(void);
|
||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface);
|
||||
#endif
|
||||
|
||||
/* ipset.c */
|
||||
#ifdef HAVE_IPSET
|
||||
void ipset_init(void);
|
||||
@@ -1460,10 +1545,10 @@ unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arriva
|
||||
#ifdef HAVE_DHCP
|
||||
void dhcp_common_init(void);
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags);
|
||||
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
|
||||
struct dhcp_opt *opts);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
|
||||
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded);
|
||||
char *strip_hostname(char *hostname);
|
||||
void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
@@ -1521,13 +1606,13 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
|
||||
|
||||
/* loop.c */
|
||||
#ifdef HAVE_LOOP
|
||||
void loop_send_probes();
|
||||
void loop_send_probes(void);
|
||||
int detect_loop(char *query, int type);
|
||||
#endif
|
||||
|
||||
/* inotify.c */
|
||||
#ifdef HAVE_INOTIFY
|
||||
void inotify_dnsmasq_init();
|
||||
void inotify_dnsmasq_init(void);
|
||||
int inotify_check(time_t now);
|
||||
void set_dynamic_inotify(int flag, int total_size, struct crec **rhash, int revhashsz);
|
||||
#endif
|
||||
@@ -1556,3 +1641,9 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
|
||||
/* arp.c */
|
||||
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now);
|
||||
int do_arp_script_run(void);
|
||||
|
||||
/* dump.c */
|
||||
#ifdef HAVE_DUMPFILE
|
||||
void dump_init(void);
|
||||
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
|
||||
#endif
|
||||
|
||||
746
src/dnssec.c
746
src/dnssec.c
@@ -1,5 +1,5 @@
|
||||
/* dnssec.c is Copyright (c) 2012 Giovanni Bajo <rasky@develer.com>
|
||||
and Copyright (c) 2012-2017 Simon Kelley
|
||||
and Copyright (c) 2012-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -19,332 +19,11 @@
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
|
||||
#include <nettle/rsa.h>
|
||||
#include <nettle/dsa.h>
|
||||
#ifndef NO_NETTLE_ECC
|
||||
# include <nettle/ecdsa.h>
|
||||
# include <nettle/ecc-curve.h>
|
||||
#endif
|
||||
#include <nettle/nettle-meta.h>
|
||||
#include <nettle/bignum.h>
|
||||
|
||||
/* Nettle-3.0 moved to a new API for DSA. We use a name that's defined in the new API
|
||||
to detect Nettle-3, and invoke the backwards compatibility mode. */
|
||||
#ifdef dsa_params_init
|
||||
#include <nettle/dsa-compat.h>
|
||||
#endif
|
||||
|
||||
#define SERIAL_UNDEF -100
|
||||
#define SERIAL_EQ 0
|
||||
#define SERIAL_LT -1
|
||||
#define SERIAL_GT 1
|
||||
|
||||
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
|
||||
static char *ds_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
case 2: return "sha256";
|
||||
case 3: return "gosthash94";
|
||||
case 4: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
|
||||
static char *algo_digest_name(int algo)
|
||||
{
|
||||
switch (algo)
|
||||
{
|
||||
case 1: return "md5";
|
||||
case 3: return "sha1";
|
||||
case 5: return "sha1";
|
||||
case 6: return "sha1";
|
||||
case 7: return "sha1";
|
||||
case 8: return "sha256";
|
||||
case 10: return "sha512";
|
||||
case 12: return "gosthash94";
|
||||
case 13: return "sha256";
|
||||
case 14: return "sha384";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
|
||||
static char *nsec3_digest_name(int digest)
|
||||
{
|
||||
switch (digest)
|
||||
{
|
||||
case 1: return "sha1";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find pointer to correct hash function in nettle library */
|
||||
static const struct nettle_hash *hash_find(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; nettle_hashes[i]; i++)
|
||||
{
|
||||
if (strcmp(nettle_hashes[i]->name, name) == 0)
|
||||
return nettle_hashes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* expand ctx and digest memory allocations if necessary and init hash function */
|
||||
static int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
|
||||
{
|
||||
static void *ctx = NULL;
|
||||
static unsigned char *digest = NULL;
|
||||
static unsigned int ctx_sz = 0;
|
||||
static unsigned int digest_sz = 0;
|
||||
|
||||
void *new;
|
||||
|
||||
if (ctx_sz < hash->context_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->context_size)))
|
||||
return 0;
|
||||
if (ctx)
|
||||
free(ctx);
|
||||
ctx = new;
|
||||
ctx_sz = hash->context_size;
|
||||
}
|
||||
|
||||
if (digest_sz < hash->digest_size)
|
||||
{
|
||||
if (!(new = whine_malloc(hash->digest_size)))
|
||||
return 0;
|
||||
if (digest)
|
||||
free(digest);
|
||||
digest = new;
|
||||
digest_sz = hash->digest_size;
|
||||
}
|
||||
|
||||
*ctxp = ctx;
|
||||
*digestp = digest;
|
||||
|
||||
hash->init(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t exp_len;
|
||||
|
||||
static struct rsa_public_key *key = NULL;
|
||||
static mpz_t sig_mpz;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_rsa_public_key_init(key);
|
||||
mpz_init(sig_mpz);
|
||||
}
|
||||
|
||||
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
key_len--;
|
||||
if ((exp_len = *p++) == 0)
|
||||
{
|
||||
GETSHORT(exp_len, p);
|
||||
key_len -= 2;
|
||||
}
|
||||
|
||||
if (exp_len >= key_len)
|
||||
return 0;
|
||||
|
||||
key->size = key_len - exp_len;
|
||||
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
|
||||
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
|
||||
|
||||
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 1:
|
||||
return nettle_rsa_md5_verify_digest(key, digest, sig_mpz);
|
||||
case 5: case 7:
|
||||
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
|
||||
case 8:
|
||||
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
|
||||
case 10:
|
||||
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dnsmasq_dsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
|
||||
static struct dsa_public_key *key = NULL;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
(void)digest_len;
|
||||
|
||||
if (key == NULL)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
|
||||
!(key = whine_malloc(sizeof(struct dsa_public_key))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_public_key_init(key);
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
}
|
||||
|
||||
if ((sig_len < 41) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
t = *p++;
|
||||
|
||||
if (key_len < (213 + (t * 24)))
|
||||
return 0;
|
||||
|
||||
mpz_import(key->q, 20, 1, 1, 0, 0, p); p += 20;
|
||||
mpz_import(key->p, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->g, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
mpz_import(key->y, 64 + (t*8), 1, 1, 0, 0, p); p += 64 + (t*8);
|
||||
|
||||
mpz_import(sig_struct->r, 20, 1, 1, 0, 0, sig+1);
|
||||
mpz_import(sig_struct->s, 20, 1, 1, 0, 0, sig+21);
|
||||
|
||||
(void)algo;
|
||||
|
||||
return nettle_dsa_sha1_verify_digest(key, digest, sig_struct);
|
||||
}
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
|
||||
unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
unsigned char *p;
|
||||
unsigned int t;
|
||||
struct ecc_point *key;
|
||||
|
||||
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
|
||||
static mpz_t x, y;
|
||||
static struct dsa_signature *sig_struct;
|
||||
|
||||
if (!sig_struct)
|
||||
{
|
||||
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
|
||||
return 0;
|
||||
|
||||
nettle_dsa_signature_init(sig_struct);
|
||||
mpz_init(x);
|
||||
mpz_init(y);
|
||||
}
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case 13:
|
||||
if (!key_256)
|
||||
{
|
||||
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_256, &nettle_secp_256r1);
|
||||
}
|
||||
|
||||
key = key_256;
|
||||
t = 32;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (!key_384)
|
||||
{
|
||||
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
|
||||
return 0;
|
||||
|
||||
nettle_ecc_point_init(key_384, &nettle_secp_384r1);
|
||||
}
|
||||
|
||||
key = key_384;
|
||||
t = 48;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sig_len != 2*t || key_len != 2*t ||
|
||||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
|
||||
return 0;
|
||||
|
||||
mpz_import(x, t , 1, 1, 0, 0, p);
|
||||
mpz_import(y, t , 1, 1, 0, 0, p + t);
|
||||
|
||||
if (!ecc_point_set(key, x, y))
|
||||
return 0;
|
||||
|
||||
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
|
||||
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
|
||||
|
||||
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
/* Enure at runtime that we have support for this digest */
|
||||
if (!hash_find(algo_digest_name(algo)))
|
||||
return NULL;
|
||||
|
||||
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
|
||||
switch (algo)
|
||||
{
|
||||
case 1: case 5: case 7: case 8: case 10:
|
||||
return dnsmasq_rsa_verify;
|
||||
|
||||
case 3: case 6:
|
||||
return dnsmasq_dsa_verify;
|
||||
|
||||
#ifndef NO_NETTLE_ECC
|
||||
case 13: case 14:
|
||||
return dnsmasq_ecdsa_verify;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo)
|
||||
{
|
||||
|
||||
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
|
||||
unsigned char *digest, size_t digest_len, int algo);
|
||||
|
||||
func = verify_func(algo);
|
||||
|
||||
if (!func)
|
||||
return 0;
|
||||
|
||||
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
|
||||
}
|
||||
|
||||
/* Convert from presentation format to wire format, in place.
|
||||
Also map UC -> LC.
|
||||
Note that using extract_name to get presentation format
|
||||
@@ -424,15 +103,17 @@ static void from_wire(char *name)
|
||||
static int count_labels(char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
char *p;
|
||||
|
||||
if (*name == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; *name; name++)
|
||||
if (*name == '.')
|
||||
for (p = name, i = 0; *p; p++)
|
||||
if (*p == '.')
|
||||
i++;
|
||||
|
||||
return i+1;
|
||||
/* Don't count empty first label. */
|
||||
return *name == '.' ? i : i+1;
|
||||
}
|
||||
|
||||
/* Implement RFC1982 wrapped compare for 32-bit numbers */
|
||||
@@ -598,10 +279,10 @@ static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end,
|
||||
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
*/
|
||||
|
||||
static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
int swap, quit, i;
|
||||
int swap, quit, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -663,11 +344,21 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
||||
rrset[i] = tmp;
|
||||
swap = quit = 1;
|
||||
}
|
||||
else if (rc == 0 && quit && len1 == len2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
}
|
||||
else if (rc < 0)
|
||||
quit = 1;
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
|
||||
return rrsetidx;
|
||||
}
|
||||
|
||||
static unsigned char **rrset = NULL, **sigs = NULL;
|
||||
@@ -812,7 +503,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* Sort RRset records into canonical order.
|
||||
Note that at this point keyname and daemon->workspacename buffs are
|
||||
unused, and used as workspace by the sort. */
|
||||
sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
|
||||
rrsetidx = sort_rrset(header, plen, rr_desc, rrsetidx, rrset, daemon->workspacename, keyname);
|
||||
|
||||
/* Now try all the sigs to try and find one which validates */
|
||||
for (j = 0; j <sigidx; j++)
|
||||
@@ -866,6 +557,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
u16 len, *dp;
|
||||
|
||||
p = rrset[i];
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -1120,7 +812,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
a.addr.log.keytag = keytag;
|
||||
a.addr.log.algo = algo;
|
||||
if (verify_func(algo))
|
||||
if (algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %hu, algo %hu (not supported)");
|
||||
@@ -1181,11 +873,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
rc = STAT_BOGUS;
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons);
|
||||
/* Note dnssec_validate_reply() will have cached positive answers */
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
rc = STAT_BOGUS;
|
||||
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received, do upstream DNS servers support DNSSEC?"));
|
||||
rc = STAT_BOGUS;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
extract_name(header, plen, &p, name, 1, 4);
|
||||
p += 4; /* qtype, qclass */
|
||||
@@ -1248,7 +942,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
a.addr.log.keytag = keytag;
|
||||
a.addr.log.algo = algo;
|
||||
a.addr.log.digest = digest;
|
||||
if (hash_find(ds_digest_name(digest)) && verify_func(algo))
|
||||
if (ds_digest_name(digest) && algo_digest_name(algo))
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu");
|
||||
else
|
||||
log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %hu, algo %hu, digest %hu (not supported)");
|
||||
@@ -1405,8 +1099,8 @@ static int hostname_cmp(const char *a, const char *b)
|
||||
}
|
||||
}
|
||||
|
||||
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
|
||||
char *workspace1, char *workspace2, char *name, int type, int *nons)
|
||||
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, unsigned char **labels, int nsec_count,
|
||||
char *workspace1_in, char *workspace2, char *name, int type, int *nons)
|
||||
{
|
||||
int i, rc, rdlen;
|
||||
unsigned char *p, *psave;
|
||||
@@ -1419,6 +1113,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
/* Find NSEC record that proves name doesn't exist */
|
||||
for (i = 0; i < nsec_count; i++)
|
||||
{
|
||||
char *workspace1 = workspace1_in;
|
||||
int sig_labels, name_labels;
|
||||
|
||||
p = nsecs[i];
|
||||
if (!extract_name(header, plen, &p, workspace1, 1, 10))
|
||||
return 0;
|
||||
@@ -1427,7 +1124,27 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
psave = p;
|
||||
if (!extract_name(header, plen, &p, workspace2, 1, 10))
|
||||
return 0;
|
||||
|
||||
|
||||
/* If NSEC comes from wildcard expansion, use original wildcard
|
||||
as name for computation. */
|
||||
sig_labels = *labels[i];
|
||||
name_labels = count_labels(workspace1);
|
||||
|
||||
if (sig_labels < name_labels)
|
||||
{
|
||||
int k;
|
||||
for (k = name_labels - sig_labels; k != 0; k--)
|
||||
{
|
||||
while (*workspace1 != '.' && *workspace1 != 0)
|
||||
workspace1++;
|
||||
if (k != 1 && *workspace1 == '.')
|
||||
workspace1++;
|
||||
}
|
||||
|
||||
workspace1--;
|
||||
*workspace1 = '*';
|
||||
}
|
||||
|
||||
rc = hostname_cmp(workspace1, name);
|
||||
|
||||
if (rc == 0)
|
||||
@@ -1453,8 +1170,9 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
|
||||
return 0;
|
||||
|
||||
/* If the SOA bit is set for a DS record, then we have the
|
||||
DS from the wrong side of the delegation. */
|
||||
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
DS from the wrong side of the delegation. For the root DS,
|
||||
this is expected. */
|
||||
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1559,7 +1277,7 @@ static int base32_decode(char *in, unsigned char *out)
|
||||
}
|
||||
|
||||
static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
|
||||
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
|
||||
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons, int name_labels)
|
||||
{
|
||||
int i, hash_len, salt_len, base32_len, rdlen, flags;
|
||||
unsigned char *p, *psave;
|
||||
@@ -1614,8 +1332,9 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
|
||||
return 0;
|
||||
|
||||
/* If the SOA bit is set for a DS record, then we have the
|
||||
DS from the wrong side of the delegation. */
|
||||
if (type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
DS from the wrong side of the delegation. For the root DS,
|
||||
this is expected. */
|
||||
if (name_labels != 0 && type == T_DS && (p[2] & (0x80 >> T_SOA)) != 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1756,7 +1475,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
|
||||
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons, count_labels(name)))
|
||||
return 1;
|
||||
|
||||
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
|
||||
@@ -1801,7 +1520,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
|
||||
return 0;
|
||||
|
||||
/* Finally, check that there's no seat of wildcard synthesis */
|
||||
@@ -1816,7 +1535,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
|
||||
return 0;
|
||||
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
|
||||
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL, 1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1825,24 +1544,26 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass, char *wildname, int *nons)
|
||||
{
|
||||
static unsigned char **nsecset = NULL;
|
||||
static int nsecset_sz = 0;
|
||||
static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
|
||||
static int nsecset_sz = 0, rrsig_labels_sz = 0;
|
||||
|
||||
int type_found = 0;
|
||||
unsigned char *p = skip_questions(header, plen);
|
||||
unsigned char *auth_start, *p = skip_questions(header, plen);
|
||||
int type, class, rdlen, i, nsecs_found;
|
||||
|
||||
/* Move to NS section */
|
||||
if (!p || !(p = skip_section(p, ntohs(header->ancount), header, plen)))
|
||||
return 0;
|
||||
|
||||
auth_start = p;
|
||||
|
||||
for (nsecs_found = 0, i = ntohs(header->nscount); i != 0; i--)
|
||||
{
|
||||
unsigned char *pstart = p;
|
||||
|
||||
if (!(p = skip_name(p, header, plen, 10)))
|
||||
if (!extract_name(header, plen, &p, daemon->workspacename, 1, 10))
|
||||
return 0;
|
||||
|
||||
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
p += 4; /* TTL */
|
||||
@@ -1859,7 +1580,69 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
if (!expand_workspace(&nsecset, &nsecset_sz, nsecs_found))
|
||||
return 0;
|
||||
|
||||
nsecset[nsecs_found++] = pstart;
|
||||
if (type == T_NSEC)
|
||||
{
|
||||
/* If we're looking for NSECs, find the corresponding SIGs, to
|
||||
extract the labels value, which we need in case the NSECs
|
||||
are the result of wildcard expansion.
|
||||
Note that the NSEC may not have been validated yet
|
||||
so if there are multiple SIGs, make sure the label value
|
||||
is the same in all, to avoid be duped by a rogue one.
|
||||
If there are no SIGs, that's an error */
|
||||
unsigned char *p1 = auth_start;
|
||||
int res, j, rdlen1, type1, class1;
|
||||
|
||||
if (!expand_workspace(&rrsig_labels, &rrsig_labels_sz, nsecs_found))
|
||||
return 0;
|
||||
|
||||
rrsig_labels[nsecs_found] = NULL;
|
||||
|
||||
for (j = ntohs(header->nscount); j != 0; j--)
|
||||
{
|
||||
if (!(res = extract_name(header, plen, &p1, daemon->workspacename, 0, 10)))
|
||||
return 0;
|
||||
|
||||
GETSHORT(type1, p1);
|
||||
GETSHORT(class1, p1);
|
||||
p1 += 4; /* TTL */
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
if (!CHECK_LEN(header, p1, plen, rdlen1))
|
||||
return 0;
|
||||
|
||||
if (res == 1 && class1 == qclass && type1 == T_RRSIG)
|
||||
{
|
||||
int type_covered;
|
||||
unsigned char *psav = p1;
|
||||
|
||||
if (rdlen1 < 18)
|
||||
return 0; /* bad packet */
|
||||
|
||||
GETSHORT(type_covered, p1);
|
||||
|
||||
if (type_covered == T_NSEC)
|
||||
{
|
||||
p1++; /* algo */
|
||||
|
||||
/* labels field must be the same in every SIG we find. */
|
||||
if (!rrsig_labels[nsecs_found])
|
||||
rrsig_labels[nsecs_found] = p1;
|
||||
else if (*rrsig_labels[nsecs_found] != *p1) /* algo */
|
||||
return 0;
|
||||
}
|
||||
p1 = psav;
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must have found at least one sig. */
|
||||
if (!rrsig_labels[nsecs_found])
|
||||
return 0;
|
||||
}
|
||||
|
||||
nsecset[nsecs_found++] = pstart;
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p, plen, rdlen))
|
||||
@@ -1867,7 +1650,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
}
|
||||
|
||||
if (type_found == T_NSEC)
|
||||
return prove_non_existence_nsec(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
else if (type_found == T_NSEC3)
|
||||
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons);
|
||||
else
|
||||
@@ -1935,8 +1718,8 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
do
|
||||
{
|
||||
if (crecp->uid == (unsigned int)class &&
|
||||
hash_find(ds_digest_name(crecp->addr.ds.digest)) &&
|
||||
verify_func(crecp->addr.ds.algo))
|
||||
ds_digest_name(crecp->addr.ds.digest) &&
|
||||
algo_digest_name(crecp->addr.ds.algo))
|
||||
break;
|
||||
}
|
||||
while ((crecp = cache_find_by_name(crecp, keyname, now, F_DS)));
|
||||
@@ -1965,7 +1748,10 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
STAT_INSECURE at least one RRset not validated, because in unsigned zone.
|
||||
STAT_BOGUS signature is wrong, bad packet, no validation where there should be.
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname, class in *class)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
STAT_NEED_DS need DS to complete validation (name is returned in keyname)
|
||||
|
||||
daemon->rr_status points to a char array which corressponds to the RRs in the
|
||||
answer section (only). This is set to 1 for each RR which is validated, and 0 for any which aren't.
|
||||
*/
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
||||
int *class, int check_unsigned, int *neganswer, int *nons)
|
||||
@@ -1974,9 +1760,25 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
static int target_sz = 0;
|
||||
|
||||
unsigned char *ans_start, *p1, *p2;
|
||||
int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
|
||||
int i, j, rc;
|
||||
int secure = STAT_SECURE;
|
||||
|
||||
/* extend rr_status if necessary */
|
||||
if (daemon->rr_status_sz < ntohs(header->ancount))
|
||||
{
|
||||
char *new = whine_malloc(ntohs(header->ancount) + 64);
|
||||
|
||||
if (!new)
|
||||
return STAT_BOGUS;
|
||||
|
||||
free(daemon->rr_status);
|
||||
daemon->rr_status = new;
|
||||
daemon->rr_status_sz = ntohs(header->ancount) + 64;
|
||||
}
|
||||
|
||||
memset(daemon->rr_status, 0, ntohs(header->ancount));
|
||||
|
||||
if (neganswer)
|
||||
*neganswer = 0;
|
||||
|
||||
@@ -2033,7 +1835,10 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
for (p1 = ans_start, i = 0; i < ntohs(header->ancount) + ntohs(header->nscount); i++)
|
||||
{
|
||||
if (!extract_name(header, plen, &p1, name, 1, 10))
|
||||
if (i != 0 && !ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (!extract_name(header, plen, &p1, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type1, p1);
|
||||
@@ -2042,140 +1847,159 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
GETSHORT(rdlen1, p1);
|
||||
|
||||
/* Don't try and validate RRSIGs! */
|
||||
if (type1 != T_RRSIG)
|
||||
if (type1 == T_RRSIG)
|
||||
continue;
|
||||
|
||||
/* Check if we've done this RRset already */
|
||||
for (p2 = ans_start, j = 0; j < i; j++)
|
||||
{
|
||||
/* Check if we've done this RRset already */
|
||||
for (p2 = ans_start, j = 0; j < i; j++)
|
||||
{
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p2);
|
||||
GETSHORT(class2, p2);
|
||||
p2 += 4; /* TTL */
|
||||
GETSHORT(rdlen2, p2);
|
||||
|
||||
if (type2 == type1 && class2 == class1 && rc == 1)
|
||||
break; /* Done it before: name, type, class all match. */
|
||||
|
||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
GETSHORT(type2, p2);
|
||||
GETSHORT(class2, p2);
|
||||
p2 += 4; /* TTL */
|
||||
GETSHORT(rdlen2, p2);
|
||||
|
||||
if (type2 == type1 && class2 == class1 && rc == 1)
|
||||
break; /* Done it before: name, type, class all match. */
|
||||
|
||||
if (!ADD_RDLEN(header, p2, plen, rdlen2))
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (j != i)
|
||||
{
|
||||
/* Done already: copy the validation status */
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = daemon->rr_status[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not done, validate now */
|
||||
if (j == i)
|
||||
int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* No signatures for RRset. We can be configured to assume this is OK and return an INSECURE result. */
|
||||
if (sigcnt == 0)
|
||||
{
|
||||
int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* No signatures for RRset. We can be configured to assume this is OK and return a INSECURE result. */
|
||||
if (sigcnt == 0)
|
||||
if (check_unsigned)
|
||||
{
|
||||
if (check_unsigned)
|
||||
{
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
return rc;
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (rc != STAT_INSECURE)
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* explore_rrset() gives us key name from sigs in keyname.
|
||||
Can't overwrite name here. */
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (rc != STAT_SECURE)
|
||||
{
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt, rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (rc == STAT_SECURE)
|
||||
{
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
|
||||
|
||||
|
||||
/* Note that RR is validated */
|
||||
if (i < ntohs(header->ancount))
|
||||
daemon->rr_status[i] = 1;
|
||||
|
||||
/* Note if we've validated either the answer to the question
|
||||
or the target of a CNAME. Any not noted will need NSEC or
|
||||
to be in unsigned space. */
|
||||
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (!(rc = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
int rc1;
|
||||
if (!(rc1 = extract_name(header, plen, &p2, name, 0, 10)))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
if (class1 == qclass && rc == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
|
||||
if (class1 == qclass && rc1 == 1 && (type1 == T_CNAME || type1 == qtype || qtype == T_ANY ))
|
||||
targets[j] = NULL;
|
||||
}
|
||||
|
||||
/* An attacker replay a wildcard answer with a different
|
||||
answer and overlay a genuine RR. To prove this
|
||||
hasn't happened, the answer must prove that
|
||||
the genuine record doesn't exist. Check that here.
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD && !prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
|
||||
|
||||
/* An attacker replay a wildcard answer with a different
|
||||
answer and overlay a genuine RR. To prove this
|
||||
hasn't happened, the answer must prove that
|
||||
the genuine record doesn't exist. Check that here.
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD &&
|
||||
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL))
|
||||
return STAT_BOGUS;
|
||||
|
||||
rc = STAT_SECURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ADD_RDLEN(header, p1, plen, rdlen1))
|
||||
return STAT_BOGUS;
|
||||
if (rc == STAT_INSECURE)
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (neganswer)
|
||||
*neganswer = 1;
|
||||
|
||||
if (!extract_name(header, plen, &p2, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((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 */
|
||||
}
|
||||
}
|
||||
if (secure == STAT_SECURE)
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
if (neganswer)
|
||||
*neganswer = 1;
|
||||
|
||||
if (!extract_name(header, plen, &p2, name, 1, 10))
|
||||
return STAT_BOGUS; /* bad packet */
|
||||
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
|
||||
|
||||
/* For anything other than a DS record, this situation is OK if either
|
||||
the answer is in an unsigned zone, or there's a NSEC records. */
|
||||
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons))
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((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_SECURE;
|
||||
return secure;
|
||||
}
|
||||
|
||||
|
||||
@@ -2202,19 +2026,11 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
|
||||
}
|
||||
|
||||
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class,
|
||||
int type, union mysockaddr *addr, int edns_pktsz)
|
||||
int type, int edns_pktsz)
|
||||
{
|
||||
unsigned char *p;
|
||||
char *types = querystr("dnssec-query", type);
|
||||
size_t ret;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
|
||||
#endif
|
||||
|
||||
header->qdcount = htons(1);
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
@@ -2230,7 +2046,7 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
|
||||
p = do_rfc1035_name(p, name);
|
||||
p = do_rfc1035_name(p, name, NULL);
|
||||
*p++ = 0;
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(class, p);
|
||||
|
||||
227
src/domain.c
227
src/domain.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -55,83 +55,133 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
|
||||
|
||||
if (pref && *pref != 0)
|
||||
continue; /* prefix match fail */
|
||||
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
|
||||
if (c->indexed)
|
||||
{
|
||||
char c = *p;
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if (c < '0' || c > '9')
|
||||
break;
|
||||
}
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
*p = 0;
|
||||
|
||||
if (hostname_isequal(c->domain, p+1))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
unsigned int index = atoi(tail);
|
||||
|
||||
if (!c->is6 &&
|
||||
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
|
||||
{
|
||||
addr->addr.addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 index = atoll(tail);
|
||||
|
||||
if (c->is6 &&
|
||||
index <= addr6part(&c->end6) - addr6part(&c->start6))
|
||||
{
|
||||
u64 start = addr6part(&c->start6);
|
||||
addr->addr.addr6 = c->start6;
|
||||
setaddr6part(&addr->addr.addr6, start + index);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
|
||||
{
|
||||
/* special hack for v4-mapped. */
|
||||
memcpy(tail, "::ffff:", 7);
|
||||
for (p = tail + 7; *p; p++)
|
||||
if (*p == '-')
|
||||
*p = '.';
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* swap . or : for - */
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
|
||||
{
|
||||
/* special hack for v4-mapped. */
|
||||
memcpy(tail, "::ffff:", 7);
|
||||
for (p = tail + 7; *p; p++)
|
||||
if (*p == '-')
|
||||
*p = '.';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
|
||||
|
||||
if (found)
|
||||
return 1;
|
||||
}
|
||||
@@ -149,14 +199,22 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
if (c->indexed)
|
||||
{
|
||||
unsigned int index = ntohl(addr->addr.addr4.s_addr) - ntohl(c->start.s_addr);
|
||||
snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
}
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
@@ -169,23 +227,32 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
if (c->indexed)
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
u64 index = addr6part(&addr->addr.addr6) - addr6part(&c->start6);
|
||||
snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* V4-mapped have periods.... */
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':' || *p == '.')
|
||||
*p = '-';
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
}
|
||||
|
||||
/* V4-mapped have periods.... */
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':' || *p == '.')
|
||||
*p = '-';
|
||||
|
||||
}
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
211
src/dump.c
Normal file
211
src/dump.c
Normal file
@@ -0,0 +1,211 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
|
||||
static u32 packet_count;
|
||||
|
||||
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
|
||||
struct pcap_hdr_s {
|
||||
u32 magic_number; /* magic number */
|
||||
u16 version_major; /* major version number */
|
||||
u16 version_minor; /* minor version number */
|
||||
u32 thiszone; /* GMT to local correction */
|
||||
u32 sigfigs; /* accuracy of timestamps */
|
||||
u32 snaplen; /* max length of captured packets, in octets */
|
||||
u32 network; /* data link type */
|
||||
};
|
||||
|
||||
struct pcaprec_hdr_s {
|
||||
u32 ts_sec; /* timestamp seconds */
|
||||
u32 ts_usec; /* timestamp microseconds */
|
||||
u32 incl_len; /* number of octets of packet saved in file */
|
||||
u32 orig_len; /* actual length of packet */
|
||||
};
|
||||
|
||||
|
||||
void dump_init(void)
|
||||
{
|
||||
struct stat buf;
|
||||
struct pcap_hdr_s header;
|
||||
struct pcaprec_hdr_s pcap_header;
|
||||
|
||||
packet_count = 0;
|
||||
|
||||
if (stat(daemon->dump_file, &buf) == -1)
|
||||
{
|
||||
/* doesn't exist, create and add header */
|
||||
header.magic_number = 0xa1b2c3d4;
|
||||
header.version_major = 2;
|
||||
header.version_minor = 4;
|
||||
header.thiszone = 0;
|
||||
header.sigfigs = 0;
|
||||
header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
|
||||
header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
|
||||
|
||||
if (errno != ENOENT ||
|
||||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
|
||||
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
|
||||
}
|
||||
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
|
||||
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
|
||||
else if (header.magic_number != 0xa1b2c3d4)
|
||||
die(_("bad header in %s"), daemon->dump_file, EC_FILE);
|
||||
else
|
||||
{
|
||||
/* count existing records */
|
||||
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
|
||||
{
|
||||
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
|
||||
packet_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
|
||||
{
|
||||
struct ip ip;
|
||||
#ifdef HAVE_IPV6
|
||||
struct ip6_hdr ip6;
|
||||
int family;
|
||||
#endif
|
||||
struct udphdr {
|
||||
u16 uh_sport; /* source port */
|
||||
u16 uh_dport; /* destination port */
|
||||
u16 uh_ulen; /* udp length */
|
||||
u16 uh_sum; /* udp checksum */
|
||||
} udp;
|
||||
struct pcaprec_hdr_s pcap_header;
|
||||
struct timeval time;
|
||||
u32 i, sum;
|
||||
void *iphdr;
|
||||
size_t ipsz;
|
||||
int rc;
|
||||
|
||||
if (daemon->dumpfd == -1 || !(mask & daemon->dump_mask))
|
||||
return;
|
||||
|
||||
/* So wireshark can Id the packet. */
|
||||
udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (src)
|
||||
family = src->sa.sa_family;
|
||||
else
|
||||
family = dst->sa.sa_family;
|
||||
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
iphdr = &ip6;
|
||||
ipsz = sizeof(ip6);
|
||||
memset(&ip6, 0, sizeof(ip6));
|
||||
|
||||
ip6.ip6_vfc = 6 << 4;
|
||||
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
|
||||
ip6.ip6_nxt = IPPROTO_UDP;
|
||||
ip6.ip6_hops = 64;
|
||||
|
||||
if (src)
|
||||
{
|
||||
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
|
||||
udp.uh_sport = src->in6.sin6_port;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
{
|
||||
memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
|
||||
udp.uh_dport = dst->in6.sin6_port;
|
||||
}
|
||||
|
||||
/* start UDP checksum */
|
||||
for (sum = 0, i = 0; i < IN6ADDRSZ; i++)
|
||||
sum += ((u16 *)&ip6.ip6_src)[i];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
iphdr = &ip;
|
||||
ipsz = sizeof(ip);
|
||||
memset(&ip, 0, sizeof(ip));
|
||||
|
||||
ip.ip_v = IPVERSION;
|
||||
ip.ip_hl = sizeof(struct ip) / 4;
|
||||
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
|
||||
ip.ip_ttl = IPDEFTTL;
|
||||
ip.ip_p = IPPROTO_UDP;
|
||||
|
||||
if (src)
|
||||
{
|
||||
ip.ip_src = src->in.sin_addr;
|
||||
udp.uh_sport = src->in.sin_port;
|
||||
}
|
||||
|
||||
if (dst)
|
||||
{
|
||||
ip.ip_dst = dst->in.sin_addr;
|
||||
udp.uh_dport = dst->in.sin_port;
|
||||
}
|
||||
|
||||
ip.ip_sum = 0;
|
||||
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
|
||||
sum += ((u16 *)&ip)[i];
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
/* start UDP checksum */
|
||||
sum = ip.ip_src.s_addr & 0xffff;
|
||||
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
|
||||
sum += ip.ip_dst.s_addr & 0xffff;
|
||||
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
if (len & 1)
|
||||
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
|
||||
|
||||
udp.uh_sum = 0;
|
||||
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
|
||||
sum += htons(IPPROTO_UDP);
|
||||
sum += htons(sizeof(struct udphdr) + len);
|
||||
for (i = 0; i < sizeof(struct udphdr)/2; i++)
|
||||
sum += ((u16 *)&udp)[i];
|
||||
for (i = 0; i < (len + 1) / 2; i++)
|
||||
sum += ((u16 *)packet)[i];
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
|
||||
|
||||
rc = gettimeofday(&time, NULL);
|
||||
pcap_header.ts_sec = time.tv_sec;
|
||||
pcap_header.ts_usec = time.tv_usec;
|
||||
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
|
||||
|
||||
if (rc == -1 ||
|
||||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
|
||||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
|
||||
!read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
|
||||
!read_write(daemon->dumpfd, (void *)packet, len, 0))
|
||||
my_syslog(LOG_ERR, _("failed to write packet dump"));
|
||||
else
|
||||
my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
28
src/edns0.c
28
src/edns0.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -144,7 +144,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
GETSHORT(len, p);
|
||||
|
||||
/* malformed option, delete the whole OPT RR and start again. */
|
||||
if (i + len > rdlen)
|
||||
if (i + 4 + len > rdlen)
|
||||
{
|
||||
rdlen = 0;
|
||||
is_last = 0;
|
||||
@@ -159,7 +159,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
/* delete option if we're to replace it. */
|
||||
p -= 4;
|
||||
rdlen -= len + 4;
|
||||
memcpy(p, p+len+4, rdlen - i);
|
||||
memmove(p, p+len+4, rdlen - i);
|
||||
PUTSHORT(rdlen, lenp);
|
||||
lenp -= 2;
|
||||
}
|
||||
@@ -192,7 +192,15 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
|
||||
header, plen)))
|
||||
{
|
||||
free(buff);
|
||||
return plen;
|
||||
}
|
||||
if (p + 11 > limit)
|
||||
{
|
||||
free(buff);
|
||||
return plen; /* Too big */
|
||||
}
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
|
||||
@@ -204,11 +212,19 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
/* Copy back any options */
|
||||
if (buff)
|
||||
{
|
||||
if (p + rdlen > limit)
|
||||
{
|
||||
free(buff);
|
||||
return plen; /* Too big */
|
||||
}
|
||||
memcpy(p, buff, rdlen);
|
||||
free(buff);
|
||||
p += rdlen;
|
||||
}
|
||||
header->arcount = htons(ntohs(header->arcount) + 1);
|
||||
|
||||
/* Only bump arcount if RR is going to fit */
|
||||
if (((ssize_t)optlen) <= (limit - (p + 4)))
|
||||
header->arcount = htons(ntohs(header->arcount) + 1);
|
||||
}
|
||||
|
||||
if (((ssize_t)optlen) > (limit - (p + 4)))
|
||||
@@ -217,8 +233,12 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
/* Add new option */
|
||||
if (optno != 0 && replace != 2)
|
||||
{
|
||||
if (p + 4 > limit)
|
||||
return plen; /* Too big */
|
||||
PUTSHORT(optno, p);
|
||||
PUTSHORT(optlen, p);
|
||||
if (p + optlen > limit)
|
||||
return plen; /* Too big */
|
||||
memcpy(p, opt, optlen);
|
||||
p += optlen;
|
||||
PUTSHORT(p - datap, lenp);
|
||||
|
||||
430
src/forward.c
430
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -118,6 +118,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
|
||||
unsigned int matchlen = 0;
|
||||
struct server *serv;
|
||||
unsigned int flags = 0;
|
||||
static struct all_addr zero;
|
||||
|
||||
for (serv = daemon->servers; serv; serv=serv->next)
|
||||
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
|
||||
@@ -129,9 +130,16 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
|
||||
*type = SERV_FOR_NODOTS;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
/* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
|
||||
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
|
||||
{
|
||||
memset(&zero, 0, sizeof(zero));
|
||||
flags = qtype;
|
||||
*addrpp = &zero;
|
||||
}
|
||||
else if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
@@ -184,7 +192,14 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
/* literal address = '#' -> return all-zero address for IPv4 and IPv6 */
|
||||
if ((serv->flags & SERV_USE_RESOLV) && (qtype & (F_IPV6 | F_IPV4)))
|
||||
{
|
||||
memset(&zero, 0, sizeof(zero));
|
||||
flags = qtype;
|
||||
*addrpp = &zero;
|
||||
}
|
||||
else if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
@@ -214,12 +229,18 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
|
||||
|
||||
if (flags)
|
||||
{
|
||||
int logflags = 0;
|
||||
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
logflags = F_NEG | qtype;
|
||||
|
||||
log_query(logflags | flags | F_CONFIG | F_FORWARD, qdomain, *addrpp, NULL);
|
||||
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||
log_query(flags | qtype | F_NEG | F_CONFIG | F_FORWARD, qdomain, NULL, NULL);
|
||||
else
|
||||
{
|
||||
/* handle F_IPV4 and F_IPV6 set on ANY query to 0.0.0.0/:: domain. */
|
||||
if (flags & F_IPV4)
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, qdomain, *addrpp, NULL);
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, qdomain, *addrpp, NULL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if ((*type) & SERV_USE_RESOLV)
|
||||
{
|
||||
@@ -246,9 +267,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
void *hash = &crc;
|
||||
#endif
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
|
||||
(void)do_bit;
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
|
||||
(void)do_bit;
|
||||
|
||||
/* may be no servers available. */
|
||||
if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
|
||||
@@ -272,14 +293,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
while (forward->blocking_query)
|
||||
forward = forward->blocking_query;
|
||||
|
||||
forward->flags |= FREC_TEST_PKTSZ;
|
||||
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
forward->flags |= FREC_TEST_PKTSZ;
|
||||
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
|
||||
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||
|
||||
|
||||
if (forward->sentto->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -299,9 +319,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
fd = forward->rfd4->fd;
|
||||
}
|
||||
|
||||
while (retry_send( sendto(fd, (char *)header, plen, 0,
|
||||
&forward->sentto->addr.sa,
|
||||
sa_len(&forward->sentto->addr))));
|
||||
while (retry_send(sendto(fd, (char *)header, plen, 0,
|
||||
&forward->sentto->addr.sa,
|
||||
sa_len(&forward->sentto->addr))));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -400,31 +420,21 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct server *firstsentto = start;
|
||||
int subnet, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
|
||||
unsigned char *pheader;
|
||||
|
||||
/* If a query is retried, use the log_id for the retry when logging the answer. */
|
||||
forward->log_id = daemon->log_id;
|
||||
|
||||
edns0_len = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->source, now, &subnet);
|
||||
|
||||
if (edns0_len != plen)
|
||||
{
|
||||
plen = edns0_len;
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
}
|
||||
if (subnet)
|
||||
forward->flags |= FREC_HAS_SUBNET;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
|
||||
{
|
||||
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
||||
|
||||
if (new != plen)
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
plen = new;
|
||||
|
||||
plen = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
@@ -433,9 +443,20 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
|
||||
if (find_pseudoheader(header, plen, &edns0_len, NULL, NULL, NULL) && edns0_len > 11)
|
||||
forward->flags |= FREC_HAS_EXTRADATA;
|
||||
if (find_pseudoheader(header, plen, &edns0_len, &pheader, NULL, NULL))
|
||||
{
|
||||
/* If there wasn't a PH before, and there is now, we added it. */
|
||||
if (!oph)
|
||||
forward->flags |= FREC_ADDED_PHEADER;
|
||||
|
||||
/* If we're sending an EDNS0 with any options, we can't recreate the query from a reply. */
|
||||
if (edns0_len > 11)
|
||||
forward->flags |= FREC_HAS_EXTRADATA;
|
||||
|
||||
/* Reduce udp size on retransmits. */
|
||||
if (forward->flags & FREC_TEST_PKTSZ)
|
||||
PUTSHORT(SAFE_PKTSZ, pheader);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -507,6 +528,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (errno == 0)
|
||||
{
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &start->addr);
|
||||
#endif
|
||||
|
||||
/* Keep info in case we want to re-send this packet */
|
||||
daemon->srv_save = start;
|
||||
daemon->packet_len = plen;
|
||||
@@ -549,6 +574,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
if (oph)
|
||||
plen = add_pseudoheader(header, plen, ((unsigned char *) header) + PACKETSZ, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
@@ -562,8 +589,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
int munged = 0, is_sign;
|
||||
unsigned int rcode = RCODE(header);
|
||||
size_t plen;
|
||||
|
||||
|
||||
(void)ad_reqd;
|
||||
(void)do_bit;
|
||||
(void)bogusanswer;
|
||||
@@ -592,6 +620,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
|
||||
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
|
||||
{
|
||||
/* Get extended RCODE. */
|
||||
rcode |= sizep[2] << 4;
|
||||
|
||||
if (check_subnet && !check_source(header, plen, pheader, query_source))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
|
||||
@@ -640,11 +671,20 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||
if (OPCODE(header) != QUERY)
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
|
||||
if (rcode != NOERROR && rcode != NXDOMAIN)
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.rcode.rcode = rcode;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
}
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR &&
|
||||
if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
@@ -653,7 +693,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||
if (daemon->bogus_addr && rcode != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||
{
|
||||
munged = 1;
|
||||
@@ -665,7 +705,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
{
|
||||
int doctored = 0;
|
||||
|
||||
if (RCODE(header) == NXDOMAIN &&
|
||||
if (rcode == NXDOMAIN &&
|
||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now))
|
||||
{
|
||||
@@ -755,7 +795,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
#endif
|
||||
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
|
||||
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
|
||||
return;
|
||||
|
||||
@@ -767,7 +807,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
|
||||
/* If sufficient time has elapsed, try and expand UDP buffer size again. */
|
||||
if (difftime(now, server->pktsz_reduced) > UDP_TEST_TIME)
|
||||
server->edns_pktsz = daemon->edns_pktsz;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
hash = hash_questions(header, n, daemon->namebuff);
|
||||
#else
|
||||
@@ -778,6 +822,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (!(forward = lookup_frec(ntohs(header->id), hash)))
|
||||
return;
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
|
||||
(void *)header, n, &serveraddr, NULL);
|
||||
#endif
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
pass these in global variables - sorry. */
|
||||
daemon->log_display_id = forward->log_id;
|
||||
@@ -789,8 +838,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
/* Note: if we send extra options in the EDNS0 header, we can't recreate
|
||||
the query from the reply. */
|
||||
if (RCODE(header) == REFUSED &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) &&
|
||||
forward->forwardall == 0 &&
|
||||
!(forward->flags & FREC_HAS_EXTRADATA))
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
@@ -798,10 +846,84 @@ void reply_query(int fd, int family, time_t now)
|
||||
unsigned char *pheader;
|
||||
size_t plen;
|
||||
int is_sign;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* For DNSSEC originated queries, just retry the query to the same server. */
|
||||
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
|
||||
{
|
||||
struct server *start;
|
||||
|
||||
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
|
||||
plen = forward->stash_len;
|
||||
|
||||
forward->forwardall = 2; /* only retry once */
|
||||
start = forward->sentto;
|
||||
|
||||
/* for non-domain specific servers, see if we can find another to try. */
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
while (1)
|
||||
{
|
||||
if (!(start = start->next))
|
||||
start = daemon->servers;
|
||||
if (start == forward->sentto)
|
||||
break;
|
||||
|
||||
if ((start->flags & SERV_TYPE) == 0 &&
|
||||
(start->flags & SERV_DO_DNSSEC))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (start->sfd)
|
||||
fd = start->sfd->fd;
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (start->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
/* may have changed family */
|
||||
if (!forward->rfd6)
|
||||
forward->rfd6 = allocate_rfd(AF_INET6);
|
||||
fd = forward->rfd6->fd;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* may have changed family */
|
||||
if (!forward->rfd4)
|
||||
forward->rfd4 = allocate_rfd(AF_INET);
|
||||
fd = forward->rfd4->fd;
|
||||
}
|
||||
}
|
||||
|
||||
while (retry_send(sendto(fd, (char *)header, plen, 0,
|
||||
&start->addr.sa,
|
||||
sa_len(&start->addr))));
|
||||
|
||||
if (start->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&start->addr.in.sin_addr, "dnssec");
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&start->addr.in6.sin6_addr, "dnssec");
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* In strict order mode, there must be a server later in the chain
|
||||
left to send to, otherwise without the forwardall mechanism,
|
||||
code further on will cycle around the list forwever if they
|
||||
all return REFUSED. Note that server is always non-NULL before
|
||||
this executes. */
|
||||
if (option_bool(OPT_ORDER))
|
||||
for (server = forward->sentto->next; server; server = server->next)
|
||||
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_NO_ADDR | SERV_LOOP)))
|
||||
break;
|
||||
|
||||
/* recreate query from reply */
|
||||
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
|
||||
if (!is_sign)
|
||||
if (!is_sign && server)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
header->nscount = htons(0);
|
||||
@@ -845,12 +967,18 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
|
||||
/* We tried resending to this server with a smaller maximum size and got an answer.
|
||||
Make that permanent. To avoid reduxing the packet size for an single dropped packet,
|
||||
Make that permanent. To avoid reduxing the packet size for a single dropped packet,
|
||||
only do this when we get a truncated answer, or one larger than the safe size. */
|
||||
if (server && (forward->flags & FREC_TEST_PKTSZ) &&
|
||||
if (server && server->edns_pktsz > SAFE_PKTSZ && (forward->flags & FREC_TEST_PKTSZ) &&
|
||||
((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
|
||||
server->edns_pktsz = SAFE_PKTSZ;
|
||||
|
||||
{
|
||||
server->edns_pktsz = SAFE_PKTSZ;
|
||||
server->pktsz_reduced = now;
|
||||
prettyprint_addr(&server->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
|
||||
}
|
||||
|
||||
|
||||
/* If the answer is an error, keep the forward record in place in case
|
||||
we get a good reply from another server. Kill it when we've
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
@@ -859,7 +987,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
|
||||
|
||||
if (option_bool(OPT_NO_REBIND))
|
||||
check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
@@ -899,7 +1027,13 @@ void reply_query(int fd, int family, time_t now)
|
||||
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
if (status == STAT_BOGUS)
|
||||
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
|
||||
header, (size_t)n, &serveraddr, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
@@ -924,7 +1058,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
int fd, type = SERV_DO_DNSSEC;
|
||||
int querytype, fd, type = SERV_DO_DNSSEC;
|
||||
struct frec *next = new->next;
|
||||
char *domain;
|
||||
|
||||
@@ -942,7 +1076,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
while (1)
|
||||
{
|
||||
if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
|
||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||
((type & SERV_TYPE) != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
|
||||
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||
{
|
||||
new_server = start;
|
||||
@@ -968,7 +1102,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
#ifdef HAVE_IPV6
|
||||
new->rfd6 = NULL;
|
||||
#endif
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY);
|
||||
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
|
||||
new->forwardall = 0;
|
||||
|
||||
new->dependent = forward; /* to find query awaiting new one. */
|
||||
forward->blocking_query = new; /* for garbage cleaning */
|
||||
@@ -976,15 +1111,26 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (status == STAT_NEED_KEY)
|
||||
{
|
||||
new->flags |= FREC_DNSKEY_QUERY;
|
||||
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
|
||||
daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
|
||||
querytype = T_DNSKEY;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->flags |= FREC_DS_QUERY;
|
||||
nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
|
||||
daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
|
||||
querytype = T_DS;
|
||||
}
|
||||
|
||||
nn = dnssec_generate_query(header,((unsigned char *) header) + server->edns_pktsz,
|
||||
daemon->keyname, forward->class, querytype, server->edns_pktsz);
|
||||
|
||||
if (server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, daemon->keyname, (struct all_addr *)&(server->addr.in.sin_addr),
|
||||
querystr("dnssec-query", querytype));
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, daemon->keyname, (struct all_addr *)&(server->addr.in6.sin6_addr),
|
||||
querystr("dnssec-query", querytype));
|
||||
#endif
|
||||
|
||||
if ((hash = hash_questions(header, nn, daemon->namebuff)))
|
||||
memcpy(new->hash, hash, HASH_SIZE);
|
||||
new->new_id = get_id();
|
||||
@@ -1026,6 +1172,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr);
|
||||
#endif
|
||||
|
||||
while (retry_send(sendto(fd, (char *)header, nn, 0,
|
||||
&server->addr.sa,
|
||||
sa_len(&server->addr))));
|
||||
@@ -1069,7 +1220,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
|
||||
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
@@ -1080,8 +1231,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
bogusanswer = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* restore CD bit to the value in the query */
|
||||
if (forward->flags & FREC_CHECKING_DISABLED)
|
||||
header->hb4 |= HB4_CD;
|
||||
@@ -1096,7 +1247,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* We added an EDNSO header for the purpose of getting DNSSEC RRs, and set the value of the UDP payload size
|
||||
greater than the no-EDNS0-implied 512 to have if space for the RRSIGS. If, having stripped them and the EDNS0
|
||||
greater than the no-EDNS0-implied 512 to have space for the RRSIGS. If, having stripped them and the EDNS0
|
||||
header, the answer is still bigger than 512, truncate it and mark it so. The client then retries with TCP. */
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER) && (nn > PACKETSZ))
|
||||
{
|
||||
@@ -1107,6 +1258,11 @@ void reply_query(int fd, int family, time_t now)
|
||||
nn = resize_packet(header, nn, NULL, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &forward->source);
|
||||
#endif
|
||||
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD) || option_bool (OPT_CLEVERBIND), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
@@ -1189,6 +1345,10 @@ void receive_query(struct listener *listen, time_t now)
|
||||
(msg.msg_flags & MSG_TRUNC) ||
|
||||
(header->hb3 & HB3_QR))
|
||||
return;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
|
||||
@@ -1356,7 +1516,11 @@ void receive_query(struct listener *listen, time_t now)
|
||||
pass these in global variables - sorry. */
|
||||
daemon->log_display_id = ++daemon->log_id;
|
||||
daemon->log_source_addr = &source_addr;
|
||||
|
||||
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
|
||||
#endif
|
||||
|
||||
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
|
||||
{
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -1409,6 +1573,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
defaults to 512 */
|
||||
if (udp_size > daemon->edns_pktsz)
|
||||
udp_size = daemon->edns_pktsz;
|
||||
else if (udp_size < PACKETSZ)
|
||||
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
|
||||
}
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -1420,7 +1586,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->auth_answer++;
|
||||
daemon->metrics[METRIC_DNS_AUTH_ANSWERED]++;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1438,13 +1604,13 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
|
||||
(char *)header, m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
header, (size_t)n, now, NULL, ad_reqd, do_bit))
|
||||
daemon->queries_forwarded++;
|
||||
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
|
||||
else
|
||||
daemon->local_answer++;
|
||||
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1477,7 +1643,8 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
option_bool(OPT_DNSSEC_NO_SIGN) && (server->flags & SERV_DO_DNSSEC), NULL, NULL);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL);
|
||||
|
||||
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
|
||||
break;
|
||||
@@ -1497,9 +1664,9 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
new_status = STAT_ABANDONED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
|
||||
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
|
||||
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
|
||||
*length = htons(m);
|
||||
|
||||
@@ -1532,30 +1699,30 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
|
||||
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
|
||||
continue;
|
||||
|
||||
retry:
|
||||
/* may need to make new connection. */
|
||||
if (server->tcpfd == -1)
|
||||
{
|
||||
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
continue; /* No good, next server */
|
||||
|
||||
|
||||
retry:
|
||||
/* may need to make new connection. */
|
||||
if (server->tcpfd == -1)
|
||||
{
|
||||
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
continue; /* No good, next server */
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
/* Copy connection mark of incoming query to outgoing connection. */
|
||||
if (have_mark)
|
||||
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
/* Copy connection mark of incoming query to outgoing connection. */
|
||||
if (have_mark)
|
||||
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
#endif
|
||||
|
||||
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
|
||||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
|
||||
{
|
||||
close(server->tcpfd);
|
||||
server->tcpfd = -1;
|
||||
continue; /* No good, next server */
|
||||
}
|
||||
|
||||
server->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) ||
|
||||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
|
||||
{
|
||||
close(server->tcpfd);
|
||||
server->tcpfd = -1;
|
||||
continue; /* No good, next server */
|
||||
}
|
||||
|
||||
server->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
|
||||
!read_write(server->tcpfd, &c1, 1, 1) ||
|
||||
@@ -1572,6 +1739,16 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (server->addr.sa.sa_family == AF_INET)
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, keyname, (struct all_addr *)&(server->addr.in.sin_addr),
|
||||
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, keyname, (struct all_addr *)&(server->addr.in6.sin6_addr),
|
||||
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
#endif
|
||||
|
||||
server->flags |= SERV_GOT_TCP;
|
||||
|
||||
@@ -1689,6 +1866,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(payload + size, 0, 65536 - size);
|
||||
|
||||
query_count++;
|
||||
|
||||
@@ -1774,17 +1955,30 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = SERV_DO_DNSSEC;
|
||||
char *domain = NULL;
|
||||
size_t new_size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
unsigned char *oph = find_pseudoheader(header, size, NULL, NULL, NULL, NULL);
|
||||
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet);
|
||||
|
||||
if (size != new_size)
|
||||
{
|
||||
added_pheader = 1;
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (type & SERV_DO_DNSSEC))
|
||||
{
|
||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check if we added a pheader on forwarding - may need to
|
||||
strip it from the reply. */
|
||||
if (!oph && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
|
||||
added_pheader = 1;
|
||||
|
||||
type &= ~SERV_DO_DNSSEC;
|
||||
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
@@ -1838,7 +2032,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
#endif
|
||||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) ||
|
||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
@@ -1849,24 +2043,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
last_server->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
|
||||
{
|
||||
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
|
||||
if (size != new_size)
|
||||
{
|
||||
added_pheader = 1;
|
||||
size = new_size;
|
||||
}
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
if (option_bool(OPT_DNSSEC_DEBUG))
|
||||
header->hb4 |= HB4_CD;
|
||||
}
|
||||
#endif
|
||||
|
||||
*length = htons(size);
|
||||
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
@@ -1921,7 +2097,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
|
||||
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
|
||||
if (status == STAT_BOGUS)
|
||||
{
|
||||
@@ -1971,7 +2147,11 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
{
|
||||
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
|
||||
if (have_pseudoheader)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,6 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
@@ -98,13 +97,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
return pipefd[1];
|
||||
}
|
||||
|
||||
/* ignore SIGTERM, so that we can clean up when the main process gets hit
|
||||
/* ignore SIGTERM and SIGINT, so that we can clean up when the main process gets hit
|
||||
and SIGALRM so that we can use sleep() */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigact.sa_flags = 0;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
sigaction(SIGINT, &sigact, NULL);
|
||||
|
||||
if (!option_bool(OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/param.h> /* For MAXSYMLINKS */
|
||||
|
||||
/* the strategy is to set a inotify on the directories containing
|
||||
/* the strategy is to set an inotify on the directories containing
|
||||
resolv files, for any files in the directory which are close-write
|
||||
or moved into the directory.
|
||||
|
||||
@@ -227,19 +227,21 @@ int inotify_check(time_t now)
|
||||
|
||||
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
in = (struct inotify_event*)p;
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (in->len == 0 ||
|
||||
in->name[in->len - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
|
||||
if (in->len == 0 || (namelen = strlen(in->name)) == 0 ||
|
||||
in->name[namelen - 1] == '~' ||
|
||||
(in->name[0] == '#' && in->name[namelen - 1] == '#') ||
|
||||
in->name[0] == '.')
|
||||
continue;
|
||||
|
||||
|
||||
for (res = daemon->resolv_files; res; res = res->next)
|
||||
if (res->wd == in->wd && strcmp(res->file, in->name) == 0)
|
||||
hit = 1;
|
||||
|
||||
for (ah = daemon->dynamic_dirs; ah; ah = ah->next)
|
||||
if (ah->wd == in->wd)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
17
src/lease.c
17
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -87,7 +87,7 @@ static int read_leases(time_t now, FILE *leasestream)
|
||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||
{
|
||||
lease_set_iaid(lease, strtoul(s, NULL, 10));
|
||||
domain = get_domain6((struct in6_addr *)lease->hwaddr);
|
||||
domain = get_domain6(&lease->addr6);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -229,7 +229,7 @@ void lease_update_from_configs(void)
|
||||
else if ((name = host_from_dns(lease->addr)))
|
||||
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
|
||||
}
|
||||
|
||||
|
||||
static void ourprintf(int *errp, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -555,7 +555,9 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
||||
file_dirty = 1;
|
||||
if (lease->hostname)
|
||||
dns_dirty = 1;
|
||||
|
||||
|
||||
daemon->metrics[lease->addr.s_addr ? METRIC_LEASES_PRUNED_4 : METRIC_LEASES_PRUNED_6]++;
|
||||
|
||||
*up = lease->next; /* unlink */
|
||||
|
||||
/* Put on old_leases list 'till we
|
||||
@@ -773,7 +775,10 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
if (lease)
|
||||
lease->addr = addr;
|
||||
{
|
||||
lease->addr = addr;
|
||||
daemon->metrics[METRIC_LEASES_ALLOCATED_4]++;
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
@@ -788,6 +793,8 @@ struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
lease->addr6 = *addrp;
|
||||
lease->flags |= lease_type;
|
||||
lease->iaid = 0;
|
||||
|
||||
daemon->metrics[METRIC_LEASES_ALLOCATED_6]++;
|
||||
}
|
||||
|
||||
return lease;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -232,7 +232,7 @@ static void log_write(void)
|
||||
logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1;
|
||||
#endif
|
||||
logaddr.sun_family = AF_UNIX;
|
||||
strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
safe_strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
|
||||
|
||||
/* Got connection back? try again. */
|
||||
if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
44
src/metrics.c
Normal file
44
src/metrics.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
const char * metric_names[] = {
|
||||
"dns_cache_inserted",
|
||||
"dns_cache_live_freed",
|
||||
"dns_queries_forwarded",
|
||||
"dns_auth_answered",
|
||||
"dns_local_answered",
|
||||
"bootp",
|
||||
"pxe",
|
||||
"dhcp_ack",
|
||||
"dhcp_decline",
|
||||
"dhcp_discover",
|
||||
"dhcp_inform",
|
||||
"dhcp_nak",
|
||||
"dhcp_offer",
|
||||
"dhcp_release",
|
||||
"dhcp_request",
|
||||
"noanswer",
|
||||
"leases_allocated_4",
|
||||
"leases_pruned_4",
|
||||
"leases_allocated_6",
|
||||
"leases_pruned_6",
|
||||
};
|
||||
|
||||
const char* get_metric_name(int i) {
|
||||
return metric_names[i];
|
||||
}
|
||||
43
src/metrics.h
Normal file
43
src/metrics.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* If you modify this list, please keep the labels in metrics.c in sync. */
|
||||
enum {
|
||||
METRIC_DNS_CACHE_INSERTED,
|
||||
METRIC_DNS_CACHE_LIVE_FREED,
|
||||
METRIC_DNS_QUERIES_FORWARDED,
|
||||
METRIC_DNS_AUTH_ANSWERED,
|
||||
METRIC_DNS_LOCAL_ANSWERED,
|
||||
METRIC_BOOTP,
|
||||
METRIC_PXE,
|
||||
METRIC_DHCPACK,
|
||||
METRIC_DHCPDECLINE,
|
||||
METRIC_DHCPDISCOVER,
|
||||
METRIC_DHCPINFORM,
|
||||
METRIC_DHCPNAK,
|
||||
METRIC_DHCPOFFER,
|
||||
METRIC_DHCPRELEASE,
|
||||
METRIC_DHCPREQUEST,
|
||||
METRIC_NOANSWER,
|
||||
METRIC_LEASES_ALLOCATED_4,
|
||||
METRIC_LEASES_PRUNED_4,
|
||||
METRIC_LEASES_ALLOCATED_6,
|
||||
METRIC_LEASES_PRUNED_6,
|
||||
|
||||
__METRIC_MAX,
|
||||
};
|
||||
|
||||
const char* get_metric_name(int);
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -149,10 +149,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
struct rtgenmsg g;
|
||||
} req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pad = 0;
|
||||
addr.nl_groups = 0;
|
||||
addr.nl_pid = 0; /* address to kernel */
|
||||
|
||||
again:
|
||||
if (family == AF_UNSPEC)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -29,7 +29,7 @@ int indextoname(int fd, int index, char *name)
|
||||
if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
|
||||
return 0;
|
||||
|
||||
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
|
||||
safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -82,12 +82,12 @@ int indextoname(int fd, int index, char *name)
|
||||
for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
|
||||
{
|
||||
struct lifreq lifr;
|
||||
strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
|
||||
safe_strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
|
||||
return 0;
|
||||
|
||||
if (lifr.lifr_index == index) {
|
||||
strncpy(name, lifr.lifr_name, IF_NAMESIZE);
|
||||
safe_strncpy(name, lifr.lifr_name, IF_NAMESIZE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||
struct ifreq ifr;
|
||||
struct irec *iface;
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
|
||||
ifr.ifr_flags & IFF_LOOPBACK)
|
||||
{
|
||||
@@ -1149,10 +1149,7 @@ int random_sock(int family)
|
||||
if (fix_fd(fd))
|
||||
while(tries--)
|
||||
{
|
||||
unsigned short port = rand16();
|
||||
|
||||
if (daemon->min_port != 0 || daemon->max_port != MAX_PORT)
|
||||
port = htons(daemon->min_port + (port % ((unsigned short)ports_avail)));
|
||||
unsigned short port = htons(daemon->min_port + (rand16() % ((unsigned short)ports_avail)));
|
||||
|
||||
if (family == AF_INET)
|
||||
{
|
||||
@@ -1187,7 +1184,7 @@ int random_sock(int family)
|
||||
}
|
||||
|
||||
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
|
||||
int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp)
|
||||
{
|
||||
union mysockaddr addr_copy = *addr;
|
||||
|
||||
@@ -1204,7 +1201,25 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1)
|
||||
return 0;
|
||||
|
||||
|
||||
if (!is_tcp && ifindex > 0)
|
||||
{
|
||||
#if defined(IP_UNICAST_IF)
|
||||
if (addr_copy.sa.sa_family == AF_INET)
|
||||
{
|
||||
uint32_t ifindex_opt = htonl(ifindex);
|
||||
return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(HAVE_IPV6) && defined (IPV6_UNICAST_IF)
|
||||
if (addr_copy.sa.sa_family == AF_INET6)
|
||||
{
|
||||
uint32_t ifindex_opt = htonl(ifindex);
|
||||
return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
if (intname[0] != 0 &&
|
||||
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
|
||||
@@ -1219,7 +1234,8 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
struct serverfd *sfd;
|
||||
unsigned int ifindex = 0;
|
||||
int errsave;
|
||||
|
||||
int opt = 1;
|
||||
|
||||
/* when using random ports, servers which would otherwise use
|
||||
the INADDR_ANY/port0 socket have sfd set to NULL */
|
||||
if (!daemon->osport && intname[0] == 0)
|
||||
@@ -1259,20 +1275,22 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
free(sfd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd))
|
||||
|
||||
if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
|
||||
!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
|
||||
{
|
||||
errsave = errno; /* save error from bind. */
|
||||
errsave = errno; /* save error from bind/setsockopt. */
|
||||
close(sfd->fd);
|
||||
free(sfd);
|
||||
errno = errsave;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(sfd->interface, intname);
|
||||
safe_strncpy(sfd->interface, intname, sizeof(sfd->interface));
|
||||
sfd->source_addr = *addr;
|
||||
sfd->next = daemon->sfds;
|
||||
sfd->ifindex = ifindex;
|
||||
sfd->preallocated = 0;
|
||||
daemon->sfds = sfd;
|
||||
|
||||
return sfd;
|
||||
@@ -1283,6 +1301,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
|
||||
void pre_allocate_sfds(void)
|
||||
{
|
||||
struct server *srv;
|
||||
struct serverfd *sfd;
|
||||
|
||||
if (daemon->query_port != 0)
|
||||
{
|
||||
@@ -1294,7 +1313,8 @@ void pre_allocate_sfds(void)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
if ((sfd = allocate_sfd(&addr, "")))
|
||||
sfd->preallocated = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
@@ -1303,7 +1323,8 @@ void pre_allocate_sfds(void)
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||
#endif
|
||||
allocate_sfd(&addr, "");
|
||||
if ((sfd = allocate_sfd(&addr, "")))
|
||||
sfd->preallocated = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1437,7 +1458,7 @@ void add_update_server(int flags,
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
|
||||
if (interface)
|
||||
strcpy(serv->interface, interface);
|
||||
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
@@ -1456,16 +1477,10 @@ void check_servers(void)
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
|
||||
sfd->used = 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
#endif
|
||||
/* don't garbage collect pre-allocated sfds. */
|
||||
for (sfd = daemon->sfds; sfd; sfd = sfd->next)
|
||||
sfd->used = sfd->preallocated;
|
||||
|
||||
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
@@ -1478,6 +1493,11 @@ void check_servers(void)
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
if (!(serv->flags & SERV_FOR_NODOTS))
|
||||
serv->flags |= SERV_DO_DNSSEC;
|
||||
|
||||
/* Disable DNSSEC validation when using server=/domain/.... servers
|
||||
unless there's a configured trust anchor. */
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
{
|
||||
struct ds_config *ds;
|
||||
@@ -1494,8 +1514,6 @@ void check_servers(void)
|
||||
if (!ds)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
else if (serv->flags & SERV_FOR_NODOTS)
|
||||
serv->flags &= ~SERV_DO_DNSSEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
441
src/option.c
441
src/option.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -160,6 +160,12 @@ struct myoption {
|
||||
#define LOPT_DHCPTTL 348
|
||||
#define LOPT_TFTP_MTU 349
|
||||
#define LOPT_REPLY_DELAY 350
|
||||
#define LOPT_RAPID_COMMIT 351
|
||||
#define LOPT_DUMPFILE 352
|
||||
#define LOPT_DUMPMASK 353
|
||||
#define LOPT_UBUS 354
|
||||
#define LOPT_NAME_MATCH 355
|
||||
#define LOPT_CAA 356
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -228,8 +234,10 @@ static const struct myoption opts[] =
|
||||
{ "srv-host", 1, 0, 'W' },
|
||||
{ "localise-queries", 0, 0, 'y' },
|
||||
{ "txt-record", 1, 0, 'Y' },
|
||||
{ "caa-record", 1, 0 , LOPT_CAA },
|
||||
{ "dns-rr", 1, 0, LOPT_RR },
|
||||
{ "enable-dbus", 2, 0, '1' },
|
||||
{ "enable-ubus", 0, 0, LOPT_UBUS },
|
||||
{ "bootp-dynamic", 2, 0, '3' },
|
||||
{ "dhcp-mac", 1, 0, '4' },
|
||||
{ "no-ping", 0, 0, '5' },
|
||||
@@ -268,7 +276,8 @@ static const struct myoption opts[] =
|
||||
{ "stop-dns-rebind", 0, 0, LOPT_REBIND },
|
||||
{ "rebind-domain-ok", 1, 0, LOPT_NO_REBIND },
|
||||
{ "all-servers", 0, 0, LOPT_NOLAST },
|
||||
{ "dhcp-match", 1, 0, LOPT_MATCH },
|
||||
{ "dhcp-match", 1, 0, LOPT_MATCH },
|
||||
{ "dhcp-name-match", 1, 0, LOPT_NAME_MATCH },
|
||||
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
|
||||
{ "neg-ttl", 1, 0, LOPT_NEGTTL },
|
||||
{ "max-ttl", 1, 0, LOPT_MAXTTL },
|
||||
@@ -310,7 +319,7 @@ static const struct myoption opts[] =
|
||||
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
||||
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
|
||||
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
|
||||
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-check-unsigned", 2, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
{ "dnssec-timestamp", 1, 0, LOPT_DNSSEC_STAMP },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
@@ -325,6 +334,9 @@ static const struct myoption opts[] =
|
||||
{ "script-arp", 0, 0, LOPT_SCRIPT_ARP },
|
||||
{ "dhcp-ttl", 1, 0 , LOPT_DHCPTTL },
|
||||
{ "dhcp-reply-delay", 1, 0, LOPT_REPLY_DELAY },
|
||||
{ "dhcp-rapid-commit", 0, 0, LOPT_RAPID_COMMIT },
|
||||
{ "dumpfile", 1, 0, LOPT_DUMPFILE },
|
||||
{ "dumpmask", 1, 0, LOPT_DUMPMASK },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -414,6 +426,7 @@ static struct {
|
||||
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
|
||||
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
||||
{ '1', ARG_ONE, "[=<busname>]", gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||
{ LOPT_UBUS, OPT_UBUS, NULL, gettext_noop("Enable the UBus interface."), NULL },
|
||||
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
||||
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
||||
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
||||
@@ -447,6 +460,7 @@ static struct {
|
||||
{ LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
|
||||
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
|
||||
{ LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
|
||||
{ LOPT_NAME_MATCH, ARG_DUP, "set:<tag>,<string>[*]", gettext_noop("Set tag if client provides given name."), NULL },
|
||||
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
|
||||
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
|
||||
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
|
||||
@@ -469,6 +483,7 @@ static struct {
|
||||
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
|
||||
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
|
||||
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>[,<ttl>]", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
|
||||
{ LOPT_CAA, ARG_DUP, "<name>,<flags>,<tag>,<value>", gettext_noop("Specify certification authority authorization record"), NULL },
|
||||
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
|
||||
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
|
||||
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
|
||||
@@ -482,7 +497,7 @@ static struct {
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
|
||||
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_CHECK, ARG_DUP, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
|
||||
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
{ LOPT_DNSSEC_STAMP, ARG_ONE, "<path>", gettext_noop("Timestamp file to verify system clock for DNSSEC"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
@@ -497,6 +512,9 @@ static struct {
|
||||
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
|
||||
{ LOPT_DHCPTTL, ARG_ONE, "<ttl>", gettext_noop("Set TTL in DNS responses with DHCP-derived addresses."), NULL },
|
||||
{ LOPT_REPLY_DELAY, ARG_ONE, "<integer>", gettext_noop("Delay DHCP replies for at least number of seconds."), NULL },
|
||||
{ LOPT_RAPID_COMMIT, OPT_RAPID_COMMIT, NULL, gettext_noop("Enables DHCPv4 Rapid Commit option."), NULL },
|
||||
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
|
||||
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -792,7 +810,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
if (interface_opt)
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
strncpy(interface, interface_opt, IF_NAMESIZE - 1);
|
||||
safe_strncpy(interface, interface_opt, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
@@ -821,7 +839,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return _("interface can only be specified once");
|
||||
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
strncpy(interface, source, IF_NAMESIZE - 1);
|
||||
safe_strncpy(interface, source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
@@ -856,7 +874,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return _("interface can only be specified once");
|
||||
|
||||
source_addr->in6.sin6_addr = in6addr_any;
|
||||
strncpy(interface, source, IF_NAMESIZE - 1);
|
||||
safe_strncpy(interface, source, IF_NAMESIZE);
|
||||
#else
|
||||
return _("interface binding not supported");
|
||||
#endif
|
||||
@@ -882,7 +900,7 @@ static struct server *add_rev4(struct in_addr addr, int msize)
|
||||
switch (msize)
|
||||
{
|
||||
case 32:
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
p += sprintf(p, "%u.", a & 0xff);
|
||||
/* fall through */
|
||||
case 24:
|
||||
p += sprintf(p, "%d.", (a >> 8) & 0xff);
|
||||
@@ -1163,7 +1181,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
/* fall though */
|
||||
/* fall through */
|
||||
case 'h':
|
||||
case 'H':
|
||||
fac *= 60;
|
||||
@@ -1415,7 +1433,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
|
||||
p = newp;
|
||||
end = do_rfc1035_name(p + len, dom);
|
||||
end = do_rfc1035_name(p + len, dom, NULL);
|
||||
*end++ = 0;
|
||||
len = end - p;
|
||||
free(dom);
|
||||
@@ -1737,7 +1755,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'x': /* --pid-file */
|
||||
daemon->runfile = opt_string_alloc(arg);
|
||||
break;
|
||||
@@ -1808,6 +1826,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(_("bad MX target"));
|
||||
break;
|
||||
|
||||
case LOPT_DUMPFILE: /* --dumpfile */
|
||||
daemon->dump_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_DUMPMASK: /* --dumpmask */
|
||||
daemon->dump_mask = strtol(arg, NULL, 0);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
case 'l': /* --dhcp-leasefile */
|
||||
daemon->lease_file = opt_string_alloc(arg);
|
||||
@@ -1875,47 +1901,43 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
case LOPT_AUTHSERV: /* --auth-server */
|
||||
if (!(comma = split(arg)))
|
||||
ret_err(gen_err);
|
||||
comma = split(arg);
|
||||
|
||||
daemon->authserver = opt_string_alloc(arg);
|
||||
arg = comma;
|
||||
do {
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
new->name = NULL;
|
||||
unhide_metas(arg);
|
||||
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
|
||||
while ((arg = comma))
|
||||
{
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
new->name = NULL;
|
||||
unhide_metas(arg);
|
||||
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
char *fam = split_chr(arg, '/');
|
||||
new->name = opt_string_alloc(arg);
|
||||
new->addr.sa.sa_family = 0;
|
||||
if (fam)
|
||||
{
|
||||
if (strcmp(fam, "4") == 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
else
|
||||
{
|
||||
char *fam = split_chr(arg, '/');
|
||||
new->name = opt_string_alloc(arg);
|
||||
new->addr.sa.sa_family = 0;
|
||||
if (fam)
|
||||
{
|
||||
if (strcmp(fam, "4") == 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (strcmp(fam, "6") == 0)
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
else if (strcmp(fam, "6") == 0)
|
||||
new->addr.sa.sa_family = AF_INET6;
|
||||
#endif
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
new->next = daemon->authinterface;
|
||||
daemon->authinterface = new;
|
||||
|
||||
arg = comma;
|
||||
} while (arg);
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
new->next = daemon->authinterface;
|
||||
daemon->authinterface = new;
|
||||
};
|
||||
|
||||
break;
|
||||
|
||||
@@ -2051,7 +2073,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 's': /* --domain */
|
||||
case LOPT_SYNTH: /* --synth-domain */
|
||||
@@ -2071,7 +2092,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
char *netpart;
|
||||
|
||||
new->prefix = NULL;
|
||||
|
||||
new->indexed = 0;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
{
|
||||
@@ -2208,8 +2230,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else
|
||||
{
|
||||
char *star;
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
if (new->prefix &&
|
||||
(star = strrchr(new->prefix, '*'))
|
||||
&& *(star+1) == 0)
|
||||
{
|
||||
*star = 0;
|
||||
new->indexed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (option == 's')
|
||||
@@ -2393,7 +2423,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (strcmp(arg, "#") == 0)
|
||||
domain = "";
|
||||
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
|
||||
option = '?';
|
||||
ret_err(gen_err);
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->next = newlist;
|
||||
@@ -2435,11 +2465,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
else if (strcmp(arg, "#") == 0)
|
||||
{
|
||||
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
|
||||
if (newlist->flags & SERV_LITERAL_ADDRESS)
|
||||
ret_err(gen_err);
|
||||
}
|
||||
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
|
||||
else
|
||||
{
|
||||
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
|
||||
@@ -2525,7 +2551,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (strcmp(arg, "#") == 0 || !*arg)
|
||||
domain = "";
|
||||
else if (strlen(arg) != 0 && !(domain = canonicalise_opt(arg)))
|
||||
option = '?';
|
||||
ret_err(gen_err);
|
||||
ipsets->next = opt_malloc(sizeof(struct ipsets));
|
||||
ipsets = ipsets->next;
|
||||
memset(ipsets, 0, sizeof(struct ipsets));
|
||||
@@ -2540,13 +2566,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
memset(ipsets, 0, sizeof(struct ipsets));
|
||||
ipsets->domain = "";
|
||||
}
|
||||
|
||||
if (!arg || !*arg)
|
||||
{
|
||||
option = '?';
|
||||
break;
|
||||
}
|
||||
size = 2;
|
||||
for (end = arg; *end; ++end)
|
||||
ret_err(gen_err);
|
||||
|
||||
for (size = 2, end = arg; *end; ++end)
|
||||
if (*end == ',')
|
||||
++size;
|
||||
|
||||
@@ -2579,8 +2603,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (size < 0)
|
||||
size = 0;
|
||||
else if (size > 10000)
|
||||
size = 10000;
|
||||
|
||||
daemon->cachesize = size;
|
||||
}
|
||||
@@ -2733,15 +2755,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
case LOPT_BRIDGE: /* --bridge-interface */
|
||||
{
|
||||
struct dhcp_bridge *new = opt_malloc(sizeof(struct dhcp_bridge));
|
||||
struct dhcp_bridge *new;
|
||||
|
||||
if (!(comma = split(arg)) || strlen(arg) > IF_NAMESIZE - 1 )
|
||||
ret_err(_("bad bridge-interface"));
|
||||
|
||||
strcpy(new->iface, arg);
|
||||
new->alias = NULL;
|
||||
new->next = daemon->bridges;
|
||||
daemon->bridges = new;
|
||||
|
||||
for (new = daemon->bridges; new; new = new->next)
|
||||
if (strcmp(new->iface, arg) == 0)
|
||||
break;
|
||||
|
||||
if (!new)
|
||||
{
|
||||
new = opt_malloc(sizeof(struct dhcp_bridge));
|
||||
strcpy(new->iface, arg);
|
||||
new->alias = NULL;
|
||||
new->next = daemon->bridges;
|
||||
daemon->bridges = new;
|
||||
}
|
||||
|
||||
do {
|
||||
arg = comma;
|
||||
comma = split(arg);
|
||||
@@ -2767,12 +2798,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
memset (new, 0, sizeof(*new));
|
||||
new->lease_time = DEFLEASE;
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
option = '?';
|
||||
break;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
for (cp = arg; *cp; cp++)
|
||||
@@ -2961,7 +2986,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'd':
|
||||
case 'D':
|
||||
fac *= 24;
|
||||
/* fall though */
|
||||
/* fall through */
|
||||
case 'h':
|
||||
case 'H':
|
||||
fac *= 60;
|
||||
@@ -3261,7 +3286,33 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
option == LOPT_FORCE ? DHOPT_FORCE :
|
||||
(option == LOPT_MATCH ? DHOPT_MATCH :
|
||||
(option == LOPT_OPTS ? DHOPT_BANK : 0)));
|
||||
|
||||
|
||||
case LOPT_NAME_MATCH: /* --dhcp-name-match */
|
||||
{
|
||||
struct dhcp_match_name *new = opt_malloc(sizeof(struct dhcp_match_name));
|
||||
struct dhcp_netid *id = opt_malloc(sizeof(struct dhcp_netid));
|
||||
ssize_t len;
|
||||
|
||||
if (!(comma = split(arg)) || (len = strlen(comma)) == 0)
|
||||
ret_err(gen_err);
|
||||
|
||||
new->wildcard = 0;
|
||||
new->netid = id;
|
||||
id->net = opt_string_alloc(set_prefix(arg));
|
||||
|
||||
if (comma[len-1] == '*')
|
||||
{
|
||||
comma[len-1] = 0;
|
||||
new->wildcard = 1;
|
||||
}
|
||||
new->name = opt_string_alloc(comma);
|
||||
|
||||
new->next = daemon->dhcp_name_match;
|
||||
daemon->dhcp_name_match = new;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'M': /* --dhcp-boot */
|
||||
{
|
||||
struct dhcp_netid *id = NULL;
|
||||
@@ -3774,11 +3825,9 @@ err:
|
||||
|
||||
if ((k < 2) ||
|
||||
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
|
||||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
|
||||
option = '?';
|
||||
|
||||
if (k == 3 && !inet_pton(AF_INET, a[2], &new->mask))
|
||||
option = '?';
|
||||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)) ||
|
||||
(k == 3 && !inet_pton(AF_INET, a[2], &new->mask)))
|
||||
ret_err(_("missing address in alias"));
|
||||
|
||||
if (dash &&
|
||||
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
|
||||
@@ -3847,6 +3896,7 @@ err:
|
||||
|
||||
while (arg != last)
|
||||
{
|
||||
int arglen = strlen(arg);
|
||||
alias = canonicalise_opt(arg);
|
||||
|
||||
if (!alias || !target)
|
||||
@@ -3862,7 +3912,7 @@ err:
|
||||
new->target = target;
|
||||
new->ttl = ttl;
|
||||
|
||||
arg += strlen(arg)+1;
|
||||
for (arg += arglen+1; *arg && isspace(*arg); arg++);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -3949,7 +3999,7 @@ err:
|
||||
|
||||
if (data)
|
||||
{
|
||||
new->txt=opt_malloc(len);
|
||||
new->txt = opt_malloc(len);
|
||||
new->len = len;
|
||||
memcpy(new->txt, data, len);
|
||||
}
|
||||
@@ -3957,6 +4007,37 @@ err:
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_CAA: /* --caa-record */
|
||||
{
|
||||
struct txt_record *new;
|
||||
char *tag, *value;
|
||||
int flags;
|
||||
|
||||
comma = split(arg);
|
||||
tag = split(comma);
|
||||
value = split(tag);
|
||||
|
||||
new = opt_malloc(sizeof(struct txt_record));
|
||||
new->next = daemon->rr;
|
||||
daemon->rr = new;
|
||||
|
||||
if (!atoi_check(comma, &flags) || !tag || !value || !(new->name = canonicalise_opt(arg)))
|
||||
ret_err(_("bad CAA record"));
|
||||
|
||||
unhide_metas(tag);
|
||||
unhide_metas(value);
|
||||
|
||||
new->len = strlen(tag) + strlen(value) + 2;
|
||||
new->txt = opt_malloc(new->len);
|
||||
new->txt[0] = flags;
|
||||
new->txt[1] = strlen(tag);
|
||||
memcpy(&new->txt[2], tag, strlen(tag));
|
||||
memcpy(&new->txt[2 + strlen(tag)], value, strlen(value));
|
||||
new->class = T_CAA;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'Y': /* --txt-record */
|
||||
{
|
||||
struct txt_record *new;
|
||||
@@ -4115,11 +4196,21 @@ err:
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case LOPT_DNSSEC_STAMP:
|
||||
case LOPT_DNSSEC_STAMP: /* --dnssec-timestamp */
|
||||
daemon->timestamp_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case LOPT_TRUST_ANCHOR:
|
||||
case LOPT_DNSSEC_CHECK: /* --dnssec-check-unsigned */
|
||||
if (arg)
|
||||
{
|
||||
if (strcmp(arg, "no") == 0)
|
||||
set_option_bool(OPT_DNSSEC_IGN_NS);
|
||||
else
|
||||
ret_err(_("bad value for dnssec-check-unsigned"));
|
||||
}
|
||||
break;
|
||||
|
||||
case LOPT_TRUST_ANCHOR: /* --trust-anchor */
|
||||
{
|
||||
struct ds_config *new = opt_malloc(sizeof(struct ds_config));
|
||||
char *cp, *cp1, *keyhex, *digest, *algo = NULL;
|
||||
@@ -4304,7 +4395,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
if (errmess)
|
||||
strcpy(daemon->namebuff, errmess);
|
||||
|
||||
if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
|
||||
if (errmess || !one_opt(option, arg, daemon->namebuff, _("error"), 0, hard_opt == LOPT_REV_SERV))
|
||||
{
|
||||
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
|
||||
if (hard_opt != 0)
|
||||
@@ -4318,7 +4409,7 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
#if defined(HAVE_DHCP) && defined(HAVE_INOTIFY)
|
||||
int option_read_dynfile(char *file, int flags)
|
||||
{
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), file);
|
||||
@@ -4519,86 +4610,99 @@ void read_servers_file(void)
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
static void clear_dynamic_conf(void)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
struct hwaddr_config *mac, *tmp;
|
||||
struct dhcp_netid_list *list, *tmplist;
|
||||
|
||||
for (mac = configs->hwaddr; mac; mac = tmp)
|
||||
{
|
||||
tmp = mac->next;
|
||||
free(mac);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
|
||||
for (list = configs->netid; list; list = tmplist)
|
||||
{
|
||||
free(list->list);
|
||||
tmplist = list->next;
|
||||
free(list);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_dynamic_opt(void)
|
||||
{
|
||||
struct dhcp_opt *opts, *cp, **up;
|
||||
struct dhcp_netid *id, *next;
|
||||
|
||||
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
||||
{
|
||||
cp = opts->next;
|
||||
|
||||
if (opts->flags & DHOPT_BANK)
|
||||
{
|
||||
if ((opts->flags & DHOPT_VENDOR))
|
||||
free(opts->u.vendor_class);
|
||||
free(opts->val);
|
||||
for (id = opts->netid; id; id = next)
|
||||
{
|
||||
next = id->next;
|
||||
free(id->net);
|
||||
free(id);
|
||||
}
|
||||
*up = opts->next;
|
||||
free(opts);
|
||||
}
|
||||
else
|
||||
up = &opts->next;
|
||||
}
|
||||
}
|
||||
|
||||
void reread_dhcp(void)
|
||||
{
|
||||
struct hostsfile *hf;
|
||||
struct hostsfile *hf;
|
||||
|
||||
if (daemon->dhcp_hosts_file)
|
||||
/* Do these even if there is no daemon->dhcp_hosts_file or
|
||||
daemon->dhcp_opts_file since entries may have been created by the
|
||||
inotify dynamic file reading system. */
|
||||
|
||||
clear_dynamic_conf();
|
||||
clear_dynamic_opt();
|
||||
|
||||
if (daemon->dhcp_hosts_file)
|
||||
{
|
||||
struct dhcp_config *configs, *cp, **up;
|
||||
|
||||
/* remove existing... */
|
||||
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
|
||||
{
|
||||
cp = configs->next;
|
||||
|
||||
if (configs->flags & CONFIG_BANK)
|
||||
{
|
||||
struct hwaddr_config *mac, *tmp;
|
||||
struct dhcp_netid_list *list, *tmplist;
|
||||
|
||||
for (mac = configs->hwaddr; mac; mac = tmp)
|
||||
{
|
||||
tmp = mac->next;
|
||||
free(mac);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_CLID)
|
||||
free(configs->clid);
|
||||
|
||||
for (list = configs->netid; list; list = tmplist)
|
||||
{
|
||||
free(list->list);
|
||||
tmplist = list->next;
|
||||
free(list);
|
||||
}
|
||||
|
||||
if (configs->flags & CONFIG_NAME)
|
||||
free(configs->hostname);
|
||||
|
||||
*up = configs->next;
|
||||
free(configs);
|
||||
}
|
||||
else
|
||||
up = &configs->next;
|
||||
}
|
||||
|
||||
daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
|
||||
for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
{
|
||||
if (one_file(hf->fname, LOPT_BANK))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
{
|
||||
if (one_file(hf->fname, LOPT_BANK))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->dhcp_opts_file)
|
||||
{
|
||||
struct dhcp_opt *opts, *cp, **up;
|
||||
struct dhcp_netid *id, *next;
|
||||
|
||||
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
|
||||
{
|
||||
cp = opts->next;
|
||||
|
||||
if (opts->flags & DHOPT_BANK)
|
||||
{
|
||||
if ((opts->flags & DHOPT_VENDOR))
|
||||
free(opts->u.vendor_class);
|
||||
free(opts->val);
|
||||
for (id = opts->netid; id; id = next)
|
||||
{
|
||||
next = id->next;
|
||||
free(id->net);
|
||||
free(id);
|
||||
}
|
||||
*up = opts->next;
|
||||
free(opts);
|
||||
}
|
||||
else
|
||||
up = &opts->next;
|
||||
}
|
||||
|
||||
daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
|
||||
for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
|
||||
if (!(hf->flags & AH_INACTIVE))
|
||||
@@ -4607,11 +4711,18 @@ void reread_dhcp(void)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef HAVE_INOTIFY
|
||||
/* Setup notify and read pre-existing files. */
|
||||
set_dynamic_inotify(AH_DHCP_HST | AH_DHCP_OPT, 0, NULL, 0);
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void read_opts(int argc, char **argv, char *compile_opts)
|
||||
{
|
||||
size_t argbuf_size = MAXDNAME;
|
||||
char *argbuf = opt_malloc(argbuf_size);
|
||||
char *buff = opt_malloc(MAXDNAME);
|
||||
int option, conffile_opt = '7', testmode = 0;
|
||||
char *arg, *conffile = CONFFILE;
|
||||
@@ -4642,6 +4753,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
daemon->max_port = MAX_PORT;
|
||||
daemon->min_port = MIN_PORT;
|
||||
|
||||
#ifndef NO_ID
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
@@ -4681,9 +4793,14 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
/* Copy optarg so that argv doesn't get changed */
|
||||
if (optarg)
|
||||
{
|
||||
strncpy(buff, optarg, MAXDNAME);
|
||||
buff[MAXDNAME-1] = 0;
|
||||
arg = buff;
|
||||
if (strlen(optarg) >= argbuf_size)
|
||||
{
|
||||
free(argbuf);
|
||||
argbuf_size = strlen(optarg) + 1;
|
||||
argbuf = opt_malloc(argbuf_size);
|
||||
}
|
||||
safe_strncpy(argbuf, optarg, argbuf_size);
|
||||
arg = argbuf;
|
||||
}
|
||||
else
|
||||
arg = NULL;
|
||||
@@ -4731,6 +4848,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
}
|
||||
}
|
||||
|
||||
free(argbuf);
|
||||
|
||||
if (conffile)
|
||||
{
|
||||
one_file(conffile, conffile_opt);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -198,6 +198,9 @@ void icmp6_packet(time_t now)
|
||||
/* look for link-layer address option for logging */
|
||||
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
|
||||
{
|
||||
if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) {
|
||||
return;
|
||||
}
|
||||
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
|
||||
mac = daemon->namebuff;
|
||||
}
|
||||
@@ -404,7 +407,7 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
|
||||
if (ra_param)
|
||||
mtu = ra_param->mtu;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not neccessarily the same as the IPv4 MTU
|
||||
/* Note that IPv6 MTU is not necessarily the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
if (mtu == 0)
|
||||
{
|
||||
|
||||
264
src/rfc1035.c
264
src/rfc1035.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -36,8 +36,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
if ((l = *p++) == 0)
|
||||
/* end marker */
|
||||
{
|
||||
/* check that there are the correct no of bytes after the name */
|
||||
if (!CHECK_LEN(header, p, plen, extrabytes))
|
||||
/* check that there are the correct no. of bytes after the name */
|
||||
if (!CHECK_LEN(header, p1 ? p1 : p, plen, extrabytes))
|
||||
return 0;
|
||||
|
||||
if (isExtract)
|
||||
@@ -156,7 +156,7 @@ int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
memset(addrp, 0, sizeof(struct all_addr));
|
||||
|
||||
/* turn name into a series of asciiz strings */
|
||||
/* j counts no of labels */
|
||||
/* j counts no. of labels */
|
||||
for(j = 1,cp1 = name; *namein; cp1++, namein++)
|
||||
if (*namein == '.')
|
||||
{
|
||||
@@ -498,6 +498,8 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
|
||||
{
|
||||
unsigned int i, len = *p1;
|
||||
unsigned char *p2 = p1;
|
||||
if ((p1 + len - p) >= rdlen)
|
||||
return 0; /* bad packet */
|
||||
/* make counted string zero-term and sanitise */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
@@ -582,7 +584,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *doc
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec, int secure, int *doctored)
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec,
|
||||
int secure, int *doctored)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -593,6 +596,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
#else
|
||||
(void)ipsets; /* unused */
|
||||
#endif
|
||||
|
||||
|
||||
cache_start_insert();
|
||||
|
||||
@@ -601,10 +605,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name, doctored);
|
||||
|
||||
if (*doctored)
|
||||
{
|
||||
if (secure)
|
||||
return 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (*doctored && secure)
|
||||
return 0;
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
for (i = 0; i < ntohs(header->ancount); i++)
|
||||
if (daemon->rr_status[i])
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* go through the questions. */
|
||||
@@ -615,7 +627,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
int found = 0, cname_count = CNAME_CHAIN;
|
||||
struct crec *cpp = NULL;
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
int secflag = secure ? F_DNSSECOK : 0;
|
||||
#ifdef HAVE_DNSSEC
|
||||
int cname_short = 0;
|
||||
#endif
|
||||
unsigned long cttl = ULONG_MAX, attl;
|
||||
|
||||
namep = p;
|
||||
@@ -643,8 +657,9 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
for (j = 0; j < ntohs(header->ancount); j++)
|
||||
{
|
||||
int secflag = 0;
|
||||
unsigned char *tmp = namep;
|
||||
/* the loop body overwrites the original name, so get it back here. */
|
||||
if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
|
||||
@@ -670,11 +685,24 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
if (!extract_name(header, qlen, &p1, name, 1, 0))
|
||||
return 0;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
{
|
||||
/* validated RR anywhere in CNAME chain, don't cache. */
|
||||
if (cname_short || aqtype == T_CNAME)
|
||||
return 0;
|
||||
|
||||
secflag = F_DNSSECOK;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count-- || secure)
|
||||
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES, we can't cache. */
|
||||
#ifdef HAVE_DNSSEC
|
||||
cname_short = 1;
|
||||
#endif
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
@@ -696,7 +724,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
ttl = find_soa(header, qlen, NULL, doctored);
|
||||
}
|
||||
if (ttl)
|
||||
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | secflag);
|
||||
cache_insert(NULL, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -724,8 +752,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (!(p1 = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
|
||||
for (j = ntohs(header->ancount); j != 0; j--)
|
||||
for (j = 0; j < ntohs(header->ancount); j++)
|
||||
{
|
||||
int secflag = 0;
|
||||
|
||||
if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
@@ -742,6 +772,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j])
|
||||
secflag = F_DNSSECOK;
|
||||
#endif
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
@@ -754,6 +788,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
newc->addr.cname.uid = 1;
|
||||
if (cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
@@ -810,6 +845,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD | secflag);
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
@@ -833,9 +869,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
pointing at this, inherit its TTL */
|
||||
if (ttl || cpp)
|
||||
{
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | secflag);
|
||||
newc = cache_insert(name, NULL, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||
if (newc && cpp)
|
||||
{
|
||||
next_uid(newc);
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
cpp->addr.cname.uid = newc->uid;
|
||||
}
|
||||
@@ -892,12 +929,11 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
return F_QUERY;
|
||||
}
|
||||
|
||||
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
|
||||
if (!(p = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
|
||||
@@ -913,65 +949,76 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
SET_RCODE(header, NOERROR); /* empty domain */
|
||||
else if (flags == F_NXDOMAIN)
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else if (flags == F_IPV4)
|
||||
{ /* we know the address */
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (flags == F_IPV6)
|
||||
else if (flags == F_SERVFAIL)
|
||||
{
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
struct all_addr a;
|
||||
a.addr.rcode.rcode = SERVFAIL;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
SET_RCODE(header, SERVFAIL);
|
||||
}
|
||||
else if (flags & ( F_IPV4 | F_IPV6))
|
||||
{
|
||||
if (flags & F_IPV4)
|
||||
{ /* we know the address */
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
{
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(ntohs(header->ancount) + 1);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else /* nowhere to forward to */
|
||||
SET_RCODE(header, REFUSED);
|
||||
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.rcode.rcode = REFUSED;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
SET_RCODE(header, REFUSED);
|
||||
}
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
|
||||
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
||||
int check_for_local_domain(char *name, time_t now)
|
||||
{
|
||||
struct crec *crecp;
|
||||
struct mx_srv_record *mx;
|
||||
struct txt_record *txt;
|
||||
struct interface_name *intr;
|
||||
struct ptr_record *ptr;
|
||||
struct naptr *naptr;
|
||||
|
||||
/* Note: the call to cache_find_by_name is intended to find any record which matches
|
||||
ie A, AAAA, CNAME. */
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME |F_NO_RR)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
return 1;
|
||||
|
||||
for (naptr = daemon->naptr; naptr; naptr = naptr->next)
|
||||
if (hostname_isequal(name, naptr->name))
|
||||
if (hostname_issubdomain(name, naptr->name))
|
||||
return 1;
|
||||
|
||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||
if (hostname_isequal(name, mx->name))
|
||||
if (hostname_issubdomain(name, mx->name))
|
||||
return 1;
|
||||
|
||||
for (txt = daemon->txt; txt; txt = txt->next)
|
||||
if (hostname_isequal(name, txt->name))
|
||||
if (hostname_issubdomain(name, txt->name))
|
||||
return 1;
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
if (hostname_issubdomain(name, intr->name))
|
||||
return 1;
|
||||
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name))
|
||||
if (hostname_issubdomain(name, ptr->name))
|
||||
return 1;
|
||||
|
||||
|
||||
if (cache_find_non_terminal(name, now))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1062,6 +1109,7 @@ int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bog
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
@@ -1071,29 +1119,41 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
unsigned short usval;
|
||||
long lval;
|
||||
char *sval;
|
||||
|
||||
#define CHECK_LIMIT(size) \
|
||||
if (limit && p + (size) > (unsigned char*)limit) goto truncated;
|
||||
|
||||
if (truncp && *truncp)
|
||||
return 0;
|
||||
|
||||
va_start(ap, format); /* make ap point to 1st unamed argument */
|
||||
|
||||
if (truncp && *truncp)
|
||||
goto truncated;
|
||||
|
||||
if (nameoffset > 0)
|
||||
{
|
||||
CHECK_LIMIT(2);
|
||||
PUTSHORT(nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *name = va_arg(ap, char *);
|
||||
if (name)
|
||||
p = do_rfc1035_name(p, name);
|
||||
if (name && !(p = do_rfc1035_name(p, name, limit)))
|
||||
goto truncated;
|
||||
|
||||
if (nameoffset < 0)
|
||||
{
|
||||
CHECK_LIMIT(2);
|
||||
PUTSHORT(-nameoffset | 0xc000, p);
|
||||
}
|
||||
else
|
||||
*p++ = 0;
|
||||
{
|
||||
CHECK_LIMIT(1);
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* type (2) + class (2) + ttl (4) + rdlen (2) */
|
||||
CHECK_LIMIT(10);
|
||||
|
||||
PUTSHORT(type, p);
|
||||
PUTSHORT(class, p);
|
||||
PUTLONG(ttl, p); /* TTL */
|
||||
@@ -1106,6 +1166,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
case '6':
|
||||
CHECK_LIMIT(IN6ADDRSZ);
|
||||
sval = va_arg(ap, char *);
|
||||
memcpy(p, sval, IN6ADDRSZ);
|
||||
p += IN6ADDRSZ;
|
||||
@@ -1113,36 +1174,43 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
#endif
|
||||
|
||||
case '4':
|
||||
CHECK_LIMIT(INADDRSZ);
|
||||
sval = va_arg(ap, char *);
|
||||
memcpy(p, sval, INADDRSZ);
|
||||
p += INADDRSZ;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
CHECK_LIMIT(1);
|
||||
usval = va_arg(ap, int);
|
||||
*p++ = usval;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
CHECK_LIMIT(2);
|
||||
usval = va_arg(ap, int);
|
||||
PUTSHORT(usval, p);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
CHECK_LIMIT(4);
|
||||
lval = va_arg(ap, long);
|
||||
PUTLONG(lval, p);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
/* get domain-name answer arg and store it in RDATA field */
|
||||
if (offset)
|
||||
*offset = p - (unsigned char *)header;
|
||||
p = do_rfc1035_name(p, va_arg(ap, char *));
|
||||
*p++ = 0;
|
||||
/* get domain-name answer arg and store it in RDATA field */
|
||||
if (offset)
|
||||
*offset = p - (unsigned char *)header;
|
||||
if (!(p = do_rfc1035_name(p, va_arg(ap, char *), limit)))
|
||||
goto truncated;
|
||||
CHECK_LIMIT(1);
|
||||
*p++ = 0;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
usval = va_arg(ap, int);
|
||||
CHECK_LIMIT(usval);
|
||||
sval = va_arg(ap, char *);
|
||||
if (usval != 0)
|
||||
memcpy(p, sval, usval);
|
||||
@@ -1154,6 +1222,7 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
usval = sval ? strlen(sval) : 0;
|
||||
if (usval > 255)
|
||||
usval = 255;
|
||||
CHECK_LIMIT(usval + 1);
|
||||
*p++ = (unsigned char)usval;
|
||||
memcpy(p, sval, usval);
|
||||
p += usval;
|
||||
@@ -1162,19 +1231,20 @@ int add_resource_record(struct dns_header *header, char *limit, int *truncp, int
|
||||
|
||||
va_end(ap); /* clean up variable argument pointer */
|
||||
|
||||
/* Now, store real RDLength. sav already checked against limit. */
|
||||
j = p - sav - 2;
|
||||
PUTSHORT(j, sav); /* Now, store real RDLength */
|
||||
|
||||
/* check for overflow of buffer */
|
||||
if (limit && ((unsigned char *)limit - p) < 0)
|
||||
{
|
||||
if (truncp)
|
||||
*truncp = 1;
|
||||
return 0;
|
||||
}
|
||||
PUTSHORT(j, sav);
|
||||
|
||||
*pp = p;
|
||||
return 1;
|
||||
|
||||
truncated:
|
||||
va_end(ap);
|
||||
if (truncp)
|
||||
*truncp = 1;
|
||||
return 0;
|
||||
|
||||
#undef CHECK_LIMIT
|
||||
}
|
||||
|
||||
static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
@@ -1223,17 +1293,14 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct mx_srv_record *rec;
|
||||
size_t len;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(((char *)header) + qlen, 0,
|
||||
(limit - ((char *)header)) - qlen);
|
||||
|
||||
if (ntohs(header->ancount) != 0 ||
|
||||
/* never answer queries with RD unset, to avoid cache snooping. */
|
||||
if (!(header->hb3 & HB3_RD) ||
|
||||
ntohs(header->ancount) != 0 ||
|
||||
ntohs(header->nscount) != 0 ||
|
||||
ntohs(header->qdcount) == 0 ||
|
||||
OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
|
||||
/* Don't return AD set if checking disabled. */
|
||||
if (header->hb4 & HB4_CD)
|
||||
sec_data = 0;
|
||||
@@ -1312,11 +1379,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, querystr(NULL, t->class));
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
t->class, C_IN, "t", t->len, t->txt))
|
||||
anscount ++;
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1510,44 +1577,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (qtype != type && qtype != T_ANY)
|
||||
continue;
|
||||
|
||||
/* Check for "A for A" queries; be rather conservative
|
||||
about what looks like dotted-quad. */
|
||||
if (qtype == T_A)
|
||||
{
|
||||
char *cp;
|
||||
unsigned int i, a;
|
||||
int x;
|
||||
|
||||
for (cp = name, i = 0, a = 0; *cp; i++)
|
||||
{
|
||||
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
{
|
||||
i = 5;
|
||||
break;
|
||||
}
|
||||
|
||||
a = (a << 8) + x;
|
||||
|
||||
if (*cp == '.')
|
||||
cp++;
|
||||
}
|
||||
|
||||
if (i == 4)
|
||||
{
|
||||
ans = 1;
|
||||
sec_data = 0;
|
||||
if (!dryrun)
|
||||
{
|
||||
addr.addr.addr4.s_addr = htonl(a);
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* interface name stuff */
|
||||
intname_restart:
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
@@ -1634,7 +1663,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* If the client asked for DNSSEC don't use cached data. */
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
|
||||
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
|
||||
!do_bit ||
|
||||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
|
||||
do
|
||||
{
|
||||
/* don't answer wildcard queries with data not from /etc/hosts
|
||||
@@ -1716,8 +1747,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
if (qtype == T_CNAME || qtype == T_ANY)
|
||||
{
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
|
||||
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME | (dryrun ? F_NO_RR : 0))) &&
|
||||
(qtype == T_CNAME || (crecp->flags & F_CONFIG)) &&
|
||||
((crecp->flags & F_CONFIG) || !do_bit || (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))))
|
||||
{
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
|
||||
112
src/rfc2131.c
112
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -32,7 +32,7 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
|
||||
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
|
||||
int opt, char *string, int null_term);
|
||||
static struct in_addr option_addr(unsigned char *opt);
|
||||
static unsigned int option_uint(unsigned char *opt, int i, int size);
|
||||
static unsigned int option_uint(unsigned char *opt, int offset, int size);
|
||||
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
int mac_len, char *interface, char *string, char *err, u32 xid);
|
||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||
@@ -42,14 +42,14 @@ static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static int in_list(unsigned char *list, int opt);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
unsigned char *end,
|
||||
unsigned char *req_options,
|
||||
char *hostname,
|
||||
char *config_domain,
|
||||
char *domain,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags,
|
||||
int null_term, int pxearch,
|
||||
int null_term, int pxe_arch,
|
||||
unsigned char *uuid,
|
||||
int vendor_class_len,
|
||||
time_t now,
|
||||
@@ -58,7 +58,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
|
||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
||||
static int do_encap_opts(struct dhcp_opt *opt, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
|
||||
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
|
||||
static int prune_vendor_opts(struct dhcp_netid *netid);
|
||||
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
|
||||
@@ -75,7 +75,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
struct dhcp_vendor *vendor;
|
||||
struct dhcp_mac *mac;
|
||||
struct dhcp_netid_list *id_list;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, selecting = 0, pxearch = -1;
|
||||
int clid_len = 0, ignore = 0, do_classes = 0, rapid_commit = 0, selecting = 0, pxearch = -1;
|
||||
struct dhcp_packet *mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
||||
unsigned char *end = (unsigned char *)(mess + 1);
|
||||
unsigned char *real_end = (unsigned char *)(mess + 1);
|
||||
@@ -157,7 +157,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
for (offset = 0; offset < (len - 5); offset += elen + 5)
|
||||
{
|
||||
elen = option_uint(opt, offset + 4 , 1);
|
||||
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA)
|
||||
if (option_uint(opt, offset, 4) == BRDBAND_FORUM_IANA && offset + elen + 5 <= len)
|
||||
{
|
||||
unsigned char *x = option_ptr(opt, offset + 5);
|
||||
unsigned char *y = option_ptr(opt, offset + elen + 5);
|
||||
@@ -626,6 +626,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
}
|
||||
|
||||
daemon->metrics[METRIC_BOOTP]++;
|
||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, NULL, message, mess->xid);
|
||||
|
||||
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
@@ -701,6 +702,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (client_hostname && option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
|
||||
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
{
|
||||
@@ -713,11 +715,15 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
else if (client_hostname)
|
||||
{
|
||||
struct dhcp_match_name *m;
|
||||
size_t nl;
|
||||
|
||||
domain = strip_hostname(client_hostname);
|
||||
|
||||
if (strlen(client_hostname) != 0)
|
||||
if ((nl = strlen(client_hostname)) != 0)
|
||||
{
|
||||
hostname = client_hostname;
|
||||
|
||||
if (!config)
|
||||
{
|
||||
/* Search again now we have a hostname.
|
||||
@@ -735,6 +741,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
netid = &known_id;
|
||||
}
|
||||
}
|
||||
|
||||
for (m = daemon->dhcp_name_match; m; m = m->next)
|
||||
{
|
||||
size_t ml = strlen(m->name);
|
||||
char save = 0;
|
||||
|
||||
if (nl < ml)
|
||||
continue;
|
||||
if (nl > ml)
|
||||
{
|
||||
save = client_hostname[ml];
|
||||
client_hostname[ml] = 0;
|
||||
}
|
||||
|
||||
if (hostname_isequal(client_hostname, m->name) &&
|
||||
(save == 0 || m->wildcard))
|
||||
{
|
||||
m->netid->next = netid;
|
||||
netid = m->netid;
|
||||
}
|
||||
|
||||
if (save != 0)
|
||||
client_hostname[ml] = save;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,7 +939,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!workaround && boot)
|
||||
{
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
/* Provide the bootfile here, for iPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
@@ -917,7 +947,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
@@ -928,6 +958,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
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);
|
||||
|
||||
daemon->metrics[METRIC_PXE]++;
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
if (!ignore)
|
||||
@@ -962,6 +993,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
|
||||
return 0;
|
||||
|
||||
daemon->metrics[METRIC_DHCPDECLINE]++;
|
||||
log_packet("DHCPDECLINE", option_ptr(opt, 0), emac, emac_len, iface_name, NULL, daemon->dhcp_buff, mess->xid);
|
||||
|
||||
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
|
||||
@@ -994,6 +1026,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
message = _("unknown lease");
|
||||
|
||||
daemon->metrics[METRIC_DHCPRELEASE]++;
|
||||
log_packet("DHCPRELEASE", &mess->ciaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
return 0;
|
||||
@@ -1040,8 +1073,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else if (have_config(config, CONFIG_DECLINED) &&
|
||||
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
|
||||
else if ((!lease || lease->addr.s_addr != config->addr.s_addr) && !do_icmp_ping(now, config->addr, 0, loopback))
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
|
||||
else
|
||||
conf = config->addr;
|
||||
}
|
||||
@@ -1062,6 +1093,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
message = _("no address available");
|
||||
}
|
||||
|
||||
daemon->metrics[METRIC_DHCPDISCOVER]++;
|
||||
log_packet("DHCPDISCOVER", opt ? option_ptr(opt, 0) : NULL, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
||||
@@ -1075,6 +1107,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
apply_delay(mess->xid, recvtime, tagif_netid);
|
||||
|
||||
if (option_bool(OPT_RAPID_COMMIT) && option_find(mess, sz, OPTION_RAPID_COMMIT, 0))
|
||||
{
|
||||
rapid_commit = 1;
|
||||
goto rapid_commit;
|
||||
}
|
||||
|
||||
daemon->metrics[METRIC_DHCPOFFER]++;
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||
@@ -1087,7 +1127,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
|
||||
|
||||
|
||||
case DHCPREQUEST:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
return 0;
|
||||
@@ -1185,9 +1226,11 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
fuzz = rand16();
|
||||
mess->yiaddr = mess->ciaddr;
|
||||
}
|
||||
|
||||
|
||||
daemon->metrics[METRIC_DHCPREQUEST]++;
|
||||
log_packet("DHCPREQUEST", &mess->yiaddr, emac, emac_len, iface_name, NULL, NULL, mess->xid);
|
||||
|
||||
|
||||
rapid_commit:
|
||||
if (!message)
|
||||
{
|
||||
struct dhcp_config *addr_config;
|
||||
@@ -1258,7 +1301,12 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (message)
|
||||
{
|
||||
log_packet("DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
daemon->metrics[rapid_commit ? METRIC_NOANSWER : METRIC_DHCPNAK]++;
|
||||
log_packet(rapid_commit ? "NOANSWER" : "DHCPNAK", &mess->yiaddr, emac, emac_len, iface_name, NULL, message, mess->xid);
|
||||
|
||||
/* rapid commit case: lease allocate failed but don't send DHCPNAK */
|
||||
if (rapid_commit)
|
||||
return 0;
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
clear_packet(mess, end);
|
||||
@@ -1415,13 +1463,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
override = lease->override;
|
||||
|
||||
daemon->metrics[METRIC_DHCPACK]++;
|
||||
log_packet("DHCPACK", &mess->yiaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
|
||||
|
||||
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
if (rapid_commit)
|
||||
option_put(mess, end, OPTION_RAPID_COMMIT, 0, 0);
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
|
||||
}
|
||||
|
||||
@@ -1431,6 +1482,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
message = _("ignored");
|
||||
|
||||
daemon->metrics[METRIC_DHCPINFORM]++;
|
||||
log_packet("DHCPINFORM", &mess->ciaddr, emac, emac_len, iface_name, message, NULL, mess->xid);
|
||||
|
||||
if (message || mess->ciaddr.s_addr == 0)
|
||||
@@ -1457,6 +1509,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
log_tags(tagif_netid, ntohl(mess->xid));
|
||||
|
||||
daemon->metrics[METRIC_DHCPACK]++;
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, NULL, mess->xid);
|
||||
|
||||
if (lease)
|
||||
@@ -1623,6 +1676,13 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void log_options(unsigned char *start, u32 xid)
|
||||
@@ -2286,7 +2346,7 @@ static void do_options(struct dhcp_context *context,
|
||||
/* See if we can send the boot stuff as options.
|
||||
To do this we need a requested option list, BOOTP
|
||||
and very old DHCP clients won't have this, we also
|
||||
provide an manual option to disable it.
|
||||
provide a manual option to disable it.
|
||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||
names, so we always send those. */
|
||||
if ((boot = find_boot(tagif)))
|
||||
@@ -2298,7 +2358,7 @@ static void do_options(struct dhcp_context *context,
|
||||
in_list(req_options, OPTION_SNAME))
|
||||
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
|
||||
else
|
||||
strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
|
||||
safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname));
|
||||
}
|
||||
|
||||
if (boot->file)
|
||||
@@ -2308,7 +2368,7 @@ static void do_options(struct dhcp_context *context,
|
||||
in_list(req_options, OPTION_FILENAME))
|
||||
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
|
||||
else
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
|
||||
}
|
||||
|
||||
if (boot->next_server.s_addr)
|
||||
@@ -2325,14 +2385,14 @@ static void do_options(struct dhcp_context *context,
|
||||
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
||||
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
{
|
||||
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
||||
safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file));
|
||||
done_file = 1;
|
||||
}
|
||||
|
||||
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
||||
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
||||
{
|
||||
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
||||
safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname));
|
||||
done_server = 1;
|
||||
}
|
||||
|
||||
@@ -2454,10 +2514,10 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
{
|
||||
p = do_rfc1035_name(p, hostname);
|
||||
p = do_rfc1035_name(p, hostname, NULL);
|
||||
if (domain)
|
||||
{
|
||||
p = do_rfc1035_name(p, domain);
|
||||
p = do_rfc1035_name(p, domain, NULL);
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
148
src/rfc3315.c
148
src/rfc3315.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -206,6 +206,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
|
||||
/* RFC-6939 */
|
||||
if ((opt = opt6_find(opts, end, OPTION6_CLIENT_MAC, 3)))
|
||||
{
|
||||
if (opt6_len(opt) - 2 > DHCP_CHADDR_MAX) {
|
||||
return 0;
|
||||
}
|
||||
state->mac_type = opt6_uint(opt, 0, 2);
|
||||
state->mac_len = opt6_len(opt) - 2;
|
||||
memcpy(&state->mac[0], opt6_ptr(opt, 2), state->mac_len);
|
||||
@@ -213,6 +216,9 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
|
||||
|
||||
for (opt = opts; opt; opt = opt6_next(opt, end))
|
||||
{
|
||||
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
|
||||
return 0;
|
||||
|
||||
int o = new_opt6(opt6_type(opt));
|
||||
if (opt6_type(opt) == OPTION6_RELAY_MSG)
|
||||
{
|
||||
@@ -490,11 +496,16 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
else if (state->client_hostname)
|
||||
{
|
||||
struct dhcp_match_name *m;
|
||||
size_t nl;
|
||||
|
||||
state->domain = strip_hostname(state->client_hostname);
|
||||
nl = strlen(state->client_hostname);
|
||||
|
||||
if (strlen(state->client_hostname) != 0)
|
||||
{
|
||||
state->hostname = state->client_hostname;
|
||||
|
||||
if (!config)
|
||||
{
|
||||
/* Search again now we have a hostname.
|
||||
@@ -504,6 +515,30 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
|
||||
config = new;
|
||||
}
|
||||
|
||||
for (m = daemon->dhcp_name_match; m; m = m->next)
|
||||
{
|
||||
size_t ml = strlen(m->name);
|
||||
char save = 0;
|
||||
|
||||
if (nl < ml)
|
||||
continue;
|
||||
if (nl > ml)
|
||||
{
|
||||
save = state->client_hostname[ml];
|
||||
state->client_hostname[ml] = 0;
|
||||
}
|
||||
|
||||
if (hostname_isequal(state->client_hostname, m->name) &&
|
||||
(save == 0 || m->wildcard))
|
||||
{
|
||||
m->netid->next = state->tags;
|
||||
state->tags = m->netid;
|
||||
}
|
||||
|
||||
if (save != 0)
|
||||
state->client_hostname[ml] = save;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -633,9 +668,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
int plain_range = 1;
|
||||
u32 lease_time;
|
||||
struct dhcp_lease *ltmp;
|
||||
struct in6_addr *req_addr;
|
||||
struct in6_addr addr;
|
||||
|
||||
struct in6_addr req_addr, addr;
|
||||
|
||||
if (!check_ia(state, opt, &ia_end, &ia_option))
|
||||
continue;
|
||||
|
||||
@@ -703,9 +737,10 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
req_addr = opt6_ptr(ia_option, 0);
|
||||
/* worry about alignment here. */
|
||||
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if ((c = address6_valid(state->context, req_addr, solicit_tags, plain_range)))
|
||||
if ((c = address6_valid(state->context, &req_addr, solicit_tags, plain_range)))
|
||||
{
|
||||
lease_time = c->lease_time;
|
||||
/* If the client asks for an address on the same network as a configured address,
|
||||
@@ -713,14 +748,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
addresses automatic. */
|
||||
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(state, &addr))
|
||||
{
|
||||
req_addr = &addr;
|
||||
req_addr = addr;
|
||||
mark_config_used(c, &addr);
|
||||
if (have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
}
|
||||
else if (!(c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
|
||||
else if (!(c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
|
||||
continue; /* not an address we're allowed */
|
||||
else if (!check_address(state, req_addr))
|
||||
else if (!check_address(state, &req_addr))
|
||||
continue; /* address leased elsewhere */
|
||||
|
||||
/* add address to output packet */
|
||||
@@ -728,8 +763,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
|
||||
state->send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(state, c, lease_time, ia_option, &min_time, req_addr, now);
|
||||
mark_context_used(state, req_addr);
|
||||
add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
|
||||
mark_context_used(state, &req_addr);
|
||||
get_context_tag(state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
@@ -762,15 +797,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
ltmp = NULL;
|
||||
while ((ltmp = lease6_find_by_client(ltmp, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state->clid, state->clid_len, state->iaid)))
|
||||
{
|
||||
req_addr = <mp->addr6;
|
||||
if ((c = address6_available(state->context, req_addr, solicit_tags, plain_range)))
|
||||
req_addr = ltmp->addr6;
|
||||
if ((c = address6_available(state->context, &req_addr, solicit_tags, plain_range)))
|
||||
{
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
|
||||
state->send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(state, c, c->lease_time, NULL, &min_time, req_addr, now);
|
||||
mark_context_used(state, req_addr);
|
||||
add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
|
||||
mark_context_used(state, &req_addr);
|
||||
get_context_tag(state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
@@ -876,7 +911,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
if (!ia_option)
|
||||
{
|
||||
/* If we get a request with a IA_*A without addresses, treat it exactly like
|
||||
/* If we get a request with an IA_*A without addresses, treat it exactly like
|
||||
a SOLICT with rapid commit set. */
|
||||
save_counter(start);
|
||||
goto request_no_address;
|
||||
@@ -886,16 +921,19 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
|
||||
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
struct in6_addr req_addr;
|
||||
struct dhcp_context *dynamic, *c;
|
||||
unsigned int lease_time;
|
||||
struct in6_addr addr;
|
||||
int config_ok = 0;
|
||||
|
||||
/* align. */
|
||||
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if ((c = address6_valid(state->context, req_addr, tagif, 1)))
|
||||
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
|
||||
if ((c = address6_valid(state->context, &req_addr, tagif, 1)))
|
||||
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr);
|
||||
|
||||
if ((dynamic = address6_available(state->context, req_addr, tagif, 1)) || c)
|
||||
if ((dynamic = address6_available(state->context, &req_addr, tagif, 1)) || c)
|
||||
{
|
||||
if (!dynamic && !config_ok)
|
||||
{
|
||||
@@ -905,7 +943,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
put_opt6_string(_("address unavailable"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
else if (!check_address(state, req_addr))
|
||||
else if (!check_address(state, &req_addr))
|
||||
{
|
||||
/* Address leased to another DUID/IAID */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
@@ -927,7 +965,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
if (dump_all_prefix_classes && state->ia_type == OPTION6_IA_NA)
|
||||
state->send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(state, dynamic, lease_time, ia_option, &min_time, req_addr, now);
|
||||
add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
|
||||
get_context_tag(state, dynamic);
|
||||
address_assigned = 1;
|
||||
}
|
||||
@@ -990,15 +1028,17 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
struct dhcp_lease *lease = NULL;
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
struct in6_addr req_addr;
|
||||
unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
|
||||
unsigned int valid_time = opt6_uint(ia_option, 20, 4);
|
||||
char *message = NULL;
|
||||
struct dhcp_context *this_context;
|
||||
|
||||
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if (!(lease = lease6_find(state->clid, state->clid_len,
|
||||
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||
state->iaid, req_addr)))
|
||||
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
|
||||
@@ -1006,7 +1046,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
save_counter(iacntr);
|
||||
t1cntr = 0;
|
||||
|
||||
log6_packet(state, "DHCPREPLY", req_addr, _("lease not found"));
|
||||
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
@@ -1018,15 +1058,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
|
||||
|
||||
if ((this_context = address6_available(state->context, req_addr, tagif, 1)) ||
|
||||
(this_context = address6_valid(state->context, req_addr, tagif, 1)))
|
||||
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
|
||||
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
|
||||
{
|
||||
struct in6_addr addr;
|
||||
unsigned int lease_time;
|
||||
|
||||
get_context_tag(state, this_context);
|
||||
|
||||
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
|
||||
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, &req_addr) && have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
else
|
||||
lease_time = this_context->lease_time;
|
||||
@@ -1039,7 +1079,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
lease_set_hwaddr(lease, state->mac, state->clid, state->mac_len, state->mac_type, state->clid_len, now, 0);
|
||||
if (state->ia_type == OPTION6_IA_NA && state->hostname)
|
||||
{
|
||||
char *addr_domain = get_domain6(req_addr);
|
||||
char *addr_domain = get_domain6(&req_addr);
|
||||
if (!state->send_domain)
|
||||
state->send_domain = addr_domain;
|
||||
lease_set_hostname(lease, state->hostname, state->hostname_auth, addr_domain, state->domain);
|
||||
@@ -1057,12 +1097,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
|
||||
if (message && (message != state->hostname))
|
||||
log6_packet(state, "DHCPREPLY", req_addr, message);
|
||||
log6_packet(state, "DHCPREPLY", &req_addr, message);
|
||||
else
|
||||
log6_quiet(state, "DHCPREPLY", req_addr, message);
|
||||
log6_quiet(state, "DHCPREPLY", &req_addr, message);
|
||||
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(req_addr, sizeof(*req_addr));
|
||||
put_opt6(&req_addr, sizeof(req_addr));
|
||||
put_opt6_long(preferred_time);
|
||||
put_opt6_long(valid_time);
|
||||
end_opt6(o1);
|
||||
@@ -1094,19 +1134,23 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
ia_option;
|
||||
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
struct in6_addr req_addr;
|
||||
|
||||
/* alignment */
|
||||
memcpy(&req_addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if (!address6_valid(state->context, req_addr, tagif, 1))
|
||||
if (!address6_valid(state->context, &req_addr, tagif, 1))
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOTONLINK);
|
||||
put_opt6_string(_("confirm failed"));
|
||||
end_opt6(o1);
|
||||
log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
good_addr = 1;
|
||||
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
|
||||
log6_quiet(state, "DHCPREPLY", &req_addr, state->hostname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,9 +1209,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
struct in6_addr addr;
|
||||
|
||||
/* align */
|
||||
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||
state->iaid, opt6_ptr(ia_option, 0))))
|
||||
state->iaid, &addr)))
|
||||
lease_prune(lease, now);
|
||||
else
|
||||
{
|
||||
@@ -1184,7 +1231,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
put_opt6(&addr, IN6ADDRSZ);
|
||||
put_opt6_long(0);
|
||||
put_opt6_long(0);
|
||||
end_opt6(o1);
|
||||
@@ -1227,12 +1274,15 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
struct in6_addr *addrp = opt6_ptr(ia_option, 0);
|
||||
struct in6_addr addr;
|
||||
|
||||
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, addrp))
|
||||
/* align */
|
||||
memcpy(&addr, opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
|
||||
if (have_config(config, CONFIG_ADDR6) && IN6_ARE_ADDR_EQUAL(&config->addr6, &addr))
|
||||
{
|
||||
prettyprint_time(daemon->dhcp_buff3, DECLINE_BACKOFF);
|
||||
inet_ntop(AF_INET6, addrp, daemon->addrbuff, ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("disabling DHCP static address %s for %s"),
|
||||
daemon->addrbuff, daemon->dhcp_buff3);
|
||||
config->flags |= CONFIG_DECLINED;
|
||||
@@ -1244,7 +1294,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
context_tmp->addr_epoch++;
|
||||
|
||||
if ((lease = lease6_find(state->clid, state->clid_len, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||
state->iaid, opt6_ptr(ia_option, 0))))
|
||||
state->iaid, &addr)))
|
||||
lease_prune(lease, now);
|
||||
else
|
||||
{
|
||||
@@ -1261,7 +1311,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
||||
}
|
||||
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(opt6_ptr(ia_option, 0), IN6ADDRSZ);
|
||||
put_opt6(&addr, IN6ADDRSZ);
|
||||
put_opt6_long(0);
|
||||
put_opt6_long(0);
|
||||
end_opt6(o1);
|
||||
@@ -1479,10 +1529,10 @@ static struct dhcp_netid *add_options(struct state *state, int do_refresh)
|
||||
if ((p = expand(len + 2)))
|
||||
{
|
||||
*(p++) = state->fqdn_flags;
|
||||
p = do_rfc1035_name(p, state->hostname);
|
||||
p = do_rfc1035_name(p, state->hostname, NULL);
|
||||
if (state->send_domain)
|
||||
{
|
||||
p = do_rfc1035_name(p, state->send_domain);
|
||||
p = do_rfc1035_name(p, state->send_domain, NULL);
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
@@ -1619,7 +1669,7 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
|
||||
{
|
||||
if (t1cntr != 0)
|
||||
{
|
||||
/* go back an fill in fields in IA_NA option */
|
||||
/* go back and fill in fields in IA_NA option */
|
||||
int sav = save_counter(t1cntr);
|
||||
unsigned int t1, t2, fuzz = 0;
|
||||
|
||||
@@ -1929,7 +1979,11 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
|
||||
}
|
||||
else if (type == OPTION6_IAADDR)
|
||||
{
|
||||
inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
|
||||
struct in6_addr addr;
|
||||
|
||||
/* align */
|
||||
memcpy(&addr, opt6_ptr(opt, 0), IN6ADDRSZ);
|
||||
inet_ntop(AF_INET6, &addr, daemon->addrbuff, ADDRSTRLEN);
|
||||
sprintf(daemon->namebuff, "%s PL=%u VL=%u",
|
||||
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
|
||||
optname = "iaaddr";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Code to safely remove RRs from an DNS answer */
|
||||
/* Code to safely remove RRs from a DNS answer */
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
@@ -247,7 +247,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
|
||||
|
||||
check_rrs(p, header, plen, 1, rrs, rr_found);
|
||||
|
||||
/* Fouth pass, elide records */
|
||||
/* Fourth pass, elide records */
|
||||
for (p = rrs[0], i = 1; i < rr_found; i += 2)
|
||||
{
|
||||
unsigned char *start = rrs[i];
|
||||
@@ -270,7 +270,7 @@ u16 *rrfilter_desc(int type)
|
||||
{
|
||||
/* List of RRtypes which include domains in the data.
|
||||
0 -> domain
|
||||
integer -> no of plain bytes
|
||||
integer -> no. of plain bytes
|
||||
-1 -> end
|
||||
|
||||
zero is not a valid RRtype, so the final entry is returned for
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -166,7 +166,8 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
|
||||
if (sendto(daemon->icmp6fd, daemon->outpacket.iov_base, save_counter(-1), 0,
|
||||
(struct sockaddr *)&addr, sizeof(addr)) == -1 &&
|
||||
errno == EHOSTUNREACH)
|
||||
errno == EHOSTUNREACH &&
|
||||
slaac->backoff == 12)
|
||||
slaac->ping_time = 0; /* Give up */
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
|
||||
static void free_transfer(struct tftp_transfer *transfer);
|
||||
static ssize_t tftp_err(int err, char *packet, char *mess, char *file);
|
||||
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
|
||||
static ssize_t tftp_err_oops(char *packet, char *file);
|
||||
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
|
||||
static char *next(char **p, char *end);
|
||||
@@ -234,7 +234,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
#endif
|
||||
}
|
||||
|
||||
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
|
||||
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
|
||||
{
|
||||
mtu = ifr.ifr_mtu;
|
||||
@@ -734,7 +734,7 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
if (transfer->opt_blocksize)
|
||||
{
|
||||
p += (sprintf(p, "blksize") + 1);
|
||||
p += (sprintf(p, "%d", transfer->blocksize) + 1);
|
||||
p += (sprintf(p, "%u", transfer->blocksize) + 1);
|
||||
}
|
||||
if (transfer->opt_transize)
|
||||
{
|
||||
|
||||
107
src/ubus.c
Normal file
107
src/ubus.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or
|
||||
(at your option) version 3 dated 29 June, 2007.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef HAVE_UBUS
|
||||
|
||||
#include <libubus.h>
|
||||
|
||||
static struct ubus_context *ubus = NULL;
|
||||
static struct blob_buf b;
|
||||
|
||||
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg);
|
||||
static struct ubus_method ubus_object_methods[] = {
|
||||
{.name = "metrics", .handler = ubus_handle_metrics},
|
||||
};
|
||||
|
||||
static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
|
||||
|
||||
static struct ubus_object ubus_object = {
|
||||
.name = "dnsmasq",
|
||||
.type = &ubus_object_type,
|
||||
.methods = ubus_object_methods,
|
||||
.n_methods = ARRAY_SIZE(ubus_object_methods),
|
||||
};
|
||||
|
||||
void set_ubus_listeners()
|
||||
{
|
||||
if (!ubus)
|
||||
return;
|
||||
|
||||
poll_listen(ubus->sock.fd, POLLIN);
|
||||
poll_listen(ubus->sock.fd, POLLERR);
|
||||
poll_listen(ubus->sock.fd, POLLHUP);
|
||||
}
|
||||
|
||||
void check_ubus_listeners()
|
||||
{
|
||||
if (!ubus)
|
||||
{
|
||||
ubus = ubus_connect(NULL);
|
||||
if (!ubus)
|
||||
return;
|
||||
ubus_add_object(ubus, &ubus_object);
|
||||
}
|
||||
|
||||
if (poll_check(ubus->sock.fd, POLLIN))
|
||||
ubus_handle_event(ubus);
|
||||
|
||||
if (poll_check(ubus->sock.fd, POLLHUP))
|
||||
{
|
||||
ubus_free(ubus);
|
||||
ubus = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method,
|
||||
struct blob_attr *msg)
|
||||
{
|
||||
int i;
|
||||
blob_buf_init(&b, 0);
|
||||
|
||||
for(i=0; i < __METRIC_MAX; i++)
|
||||
blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
|
||||
|
||||
ubus_send_reply(ctx, req, b.head);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
|
||||
{
|
||||
if (!ubus || !ubus_object.has_subscribers)
|
||||
return;
|
||||
|
||||
blob_buf_init(&b, 0);
|
||||
if (mac)
|
||||
blobmsg_add_string(&b, "mac", mac);
|
||||
if (ip)
|
||||
blobmsg_add_string(&b, "ip", ip);
|
||||
if (name)
|
||||
blobmsg_add_string(&b, "name", name);
|
||||
if (interface)
|
||||
blobmsg_add_string(&b, "interface", interface);
|
||||
|
||||
ubus_notify(ubus, &ubus_object, type, b.head, -1);
|
||||
}
|
||||
|
||||
|
||||
#endif /* HAVE_UBUS */
|
||||
133
src/util.c
133
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2017 Simon Kelley
|
||||
/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -111,6 +111,7 @@ u64 rand64(void)
|
||||
return (u64)out[outleft+1] + (((u64)out[outleft]) << 32);
|
||||
}
|
||||
|
||||
/* returns 2 if names is OK but contains one or more underscores */
|
||||
static int check_name(char *in)
|
||||
{
|
||||
/* remove trailing .
|
||||
@@ -118,6 +119,7 @@ static int check_name(char *in)
|
||||
size_t dotgap = 0, l = strlen(in);
|
||||
char c;
|
||||
int nowhite = 0;
|
||||
int hasuscore = 0;
|
||||
|
||||
if (l == 0 || l > MAXDNAME) return 0;
|
||||
|
||||
@@ -141,13 +143,17 @@ static int check_name(char *in)
|
||||
return 0;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
nowhite = 1;
|
||||
{
|
||||
nowhite = 1;
|
||||
if (c == '_')
|
||||
hasuscore = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nowhite)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return hasuscore ? 2 : 1;
|
||||
}
|
||||
|
||||
/* Hostnames have a more limited valid charset than domain names
|
||||
@@ -186,56 +192,70 @@ int legal_hostname(char *name)
|
||||
char *canonicalise(char *in, int *nomem)
|
||||
{
|
||||
char *ret = NULL;
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
|
||||
if (nomem)
|
||||
*nomem = 0;
|
||||
|
||||
if (!check_name(in))
|
||||
if (!(rc = check_name(in)))
|
||||
return NULL;
|
||||
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
#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);
|
||||
#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 (rc != IDNA_SUCCESS)
|
||||
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2)
|
||||
{
|
||||
if (ret)
|
||||
free(ret);
|
||||
|
||||
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
|
||||
# ifdef HAVE_LIBIDN2
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
|
||||
if (rc == IDN2_DISALLOWED)
|
||||
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
|
||||
# else
|
||||
rc = idna_to_ascii_lz(in, &ret, 0);
|
||||
# endif
|
||||
if (rc != IDNA_SUCCESS)
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to allocate memory"));
|
||||
*nomem = 1;
|
||||
if (ret)
|
||||
free(ret);
|
||||
|
||||
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("failed to allocate memory"));
|
||||
*nomem = 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
if ((ret = whine_malloc(strlen(in)+1)))
|
||||
strcpy(ret, in);
|
||||
else if (nomem)
|
||||
*nomem = 1;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
|
||||
unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit)
|
||||
{
|
||||
int j;
|
||||
|
||||
while (sval && *sval)
|
||||
{
|
||||
unsigned char *cp = p++;
|
||||
|
||||
if (limit && p > (unsigned char*)limit)
|
||||
return NULL;
|
||||
|
||||
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
||||
{
|
||||
if (limit && p + 1 > (unsigned char*)limit)
|
||||
return NULL;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
|
||||
*p++ = (*(++sval))-1;
|
||||
@@ -243,10 +263,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
|
||||
#endif
|
||||
*p++ = *sval;
|
||||
}
|
||||
|
||||
*cp = j;
|
||||
if (*sval)
|
||||
sval++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -259,7 +281,18 @@ void *safe_malloc(size_t size)
|
||||
die(_("could not get memory"), NULL, EC_NOMEM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure limited size string is always terminated.
|
||||
* Can be replaced by (void)strlcpy() on some platforms */
|
||||
void safe_strncpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
dest[size-1] = '\0';
|
||||
strncpy(dest, src, size-1);
|
||||
}
|
||||
}
|
||||
|
||||
void safe_pipe(int *fd, int read_noblock)
|
||||
{
|
||||
@@ -333,6 +366,44 @@ int hostname_isequal(const char *a, const char *b)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
|
||||
int hostname_issubdomain(char *a, char *b)
|
||||
{
|
||||
char *ap, *bp;
|
||||
unsigned int c1, c2;
|
||||
|
||||
/* move to the end */
|
||||
for (ap = a; *ap; ap++);
|
||||
for (bp = b; *bp; bp++);
|
||||
|
||||
/* a shorter than b or a empty. */
|
||||
if ((bp - b) < (ap - a) || ap == a)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
c1 = (unsigned char) *(--ap);
|
||||
c2 = (unsigned char) *(--bp);
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
|
||||
if (c1 != c2)
|
||||
return 0;
|
||||
} while (ap != a);
|
||||
|
||||
if (bp == b)
|
||||
return 2;
|
||||
|
||||
if (*(--bp) == '.')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
time_t dnsmasq_time(void)
|
||||
{
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
@@ -448,13 +519,13 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
{
|
||||
unsigned int x, p = 0;
|
||||
if ((x = t/86400))
|
||||
p += sprintf(&buf[p], "%dd", x);
|
||||
p += sprintf(&buf[p], "%ud", x);
|
||||
if ((x = (t/3600)%24))
|
||||
p += sprintf(&buf[p], "%dh", x);
|
||||
p += sprintf(&buf[p], "%uh", x);
|
||||
if ((x = (t/60)%60))
|
||||
p += sprintf(&buf[p], "%dm", x);
|
||||
p += sprintf(&buf[p], "%um", x);
|
||||
if ((x = t%60))
|
||||
p += sprintf(&buf[p], "%ds", x);
|
||||
p += sprintf(&buf[p], "%us", x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user