Compare commits
79 Commits
v2.69test6
...
v2.70
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e22cf28f8 | ||
|
|
3b1b3e9d50 | ||
|
|
ab72091de2 | ||
|
|
66f57867d8 | ||
|
|
6375838445 | ||
|
|
82a14af5e7 | ||
|
|
97dce08ed7 | ||
|
|
198d940af6 | ||
|
|
1d7e0a36e3 | ||
|
|
10068600f8 | ||
|
|
b7639d5815 | ||
|
|
49752b90d5 | ||
|
|
e98bd52e25 | ||
|
|
8a8bbad0cf | ||
|
|
fec216df32 | ||
|
|
4e1fe44428 | ||
|
|
51967f9807 | ||
|
|
b37f8b99ae | ||
|
|
fc2833f172 | ||
|
|
490f90758d | ||
|
|
56618c31f6 | ||
|
|
604f7598c2 | ||
|
|
2a7a2b84ec | ||
|
|
3e21a1a6fa | ||
|
|
2b29191e7c | ||
|
|
03431d6373 | ||
|
|
cc1a29e250 | ||
|
|
e62e9b6187 | ||
|
|
19c51cfa49 | ||
|
|
d5082158ee | ||
|
|
3f7483e816 | ||
|
|
0c8584eabc | ||
|
|
f00690f93e | ||
|
|
89b12ed35b | ||
|
|
1a9a3489ec | ||
|
|
c8a80487cd | ||
|
|
4ea8e80dd9 | ||
|
|
c07d30dcb1 | ||
|
|
d588ab54d4 | ||
|
|
f8b422a7b6 | ||
|
|
29fe922b14 | ||
|
|
8707019237 | ||
|
|
d1fbb77e0f | ||
|
|
1fbe4d2f5f | ||
|
|
0575610fa1 | ||
|
|
e3f1455850 | ||
|
|
bd9b3cf55b | ||
|
|
14db4212ab | ||
|
|
00a5b5d477 | ||
|
|
b8eac19177 | ||
|
|
b47b04c846 | ||
|
|
613ad15d02 | ||
|
|
24187530fb | ||
|
|
a857daa351 | ||
|
|
f01d7be6c6 | ||
|
|
d387380a25 | ||
|
|
f2e4c277c4 | ||
|
|
5107ace14a | ||
|
|
7b1eae4f50 | ||
|
|
c152dc8492 | ||
|
|
7bcca0060f | ||
|
|
d68c2ca2b7 | ||
|
|
de73a497ca | ||
|
|
e3ec15af10 | ||
|
|
dac74312da | ||
|
|
2ecd9bd5c0 | ||
|
|
a0ab18f6eb | ||
|
|
ebe95a831f | ||
|
|
ee4158678a | ||
|
|
83349b8aa4 | ||
|
|
7fa836e105 | ||
|
|
1633e30834 | ||
|
|
c8ca33f810 | ||
|
|
e243c072b5 | ||
|
|
da4f372271 | ||
|
|
610e782a29 | ||
|
|
854cf26907 | ||
|
|
bb201c211a | ||
|
|
12fae49fff |
70
CHANGELOG
70
CHANGELOG
@@ -1,3 +1,12 @@
|
||||
version 2.70
|
||||
Fix crash, introduced in 2.69, on TCP request when dnsmasq
|
||||
compiled with DNSSEC support, but running without DNSSEC
|
||||
enabled. Thanks to Manish Sing for spotting that one.
|
||||
|
||||
Fix regression which broke ipset functionality. Thanks to
|
||||
Wang Jian for the bug report.
|
||||
|
||||
|
||||
version 2.69
|
||||
Implement dynamic interface discovery on *BSD. This allows
|
||||
the contructor: syntax to be used in dhcp-range for DHCPv6
|
||||
@@ -28,9 +37,9 @@ version 2.69
|
||||
|
||||
make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
|
||||
|
||||
which bloats the dnsmasq binary to over a megabyte, but
|
||||
saves the size of the shared libraries which are five
|
||||
times that size.
|
||||
which bloats the dnsmasq binary, but saves the size of
|
||||
the shared libraries which are much bigger.
|
||||
|
||||
To enable, DNSSEC, you will need a set of
|
||||
trust-anchors. Now that the TLDs are signed, this can be
|
||||
the keys for the root zone, and for convenience they are
|
||||
@@ -56,13 +65,68 @@ version 2.69
|
||||
downstream validators. Setting --log-queries will show
|
||||
DNSSEC in action.
|
||||
|
||||
If a domain is returned from an upstream nameserver without
|
||||
DNSSEC signature, dnsmasq by default trusts this. This
|
||||
means that for unsigned zone (still the majority) there
|
||||
is effectively no cost for having DNSSEC enabled. Of course
|
||||
this allows an attacker to replace a signed record with a
|
||||
false unsigned record. This is addressed by the
|
||||
--dnssec-check-unsigned flag, which instructs dnsmasq
|
||||
to prove that an unsigned record is legitimate, by finding
|
||||
a secure proof that the zone containing the record is not
|
||||
signed. Doing this has costs (typically one or two extra
|
||||
upstream queries). It also has a nasty failure mode if
|
||||
dnsmasq's upstream nameservers are not DNSSEC capable.
|
||||
Without --dnssec-check-unsigned using such an upstream
|
||||
server will simply result in not queries being validated;
|
||||
with --dnssec-check-unsigned enabled and a
|
||||
DNSSEC-ignorant upstream server, _all_ queries will fail.
|
||||
|
||||
Note that DNSSEC requires that the local time is valid and
|
||||
accurate, if not then DNSSEC validation will fail. NTP
|
||||
should be running. This presents a problem for routers
|
||||
without a battery-backed clock. To set the time needs NTP
|
||||
to do DNS lookups, but lookups will fail until NTP has run.
|
||||
To address this, there's a flag, --dnssec-no-timecheck
|
||||
which disables the time checks (only) in DNSSEC. When dnsmasq
|
||||
is started and the clock is not synced, this flag should
|
||||
be used. As soon as the clock is synced, SIGHUP dnsmasq.
|
||||
The SIGHUP clears the cache of partially-validated data and
|
||||
resets the no-timecheck flag, so that all DNSSEC checks
|
||||
henceforward will be complete.
|
||||
|
||||
The development of DNSSEC in dnsmasq was started by
|
||||
Giovanni Bajo, to whom huge thanks are owed. It has been
|
||||
supported by Comcast, whose techfund grant has allowed for
|
||||
an invaluable period of full-time work to get it to
|
||||
a workable state.
|
||||
|
||||
Add --rev-server. Thanks to Dave Taht for suggesting this.
|
||||
|
||||
Add --servers-file. Allows dynamic update of upstream servers
|
||||
full access to configuration.
|
||||
|
||||
Add --local-service. Accept DNS queries only from hosts
|
||||
whose address is on a local subnet, ie a subnet for which
|
||||
an interface exists on the server. This option
|
||||
only has effect if there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended
|
||||
to be set as a default on installation, to allow
|
||||
unconfigured installations to be useful but also safe from
|
||||
being used for DNS amplification attacks.
|
||||
|
||||
Fix crashes in cache_get_cname_target() when dangling CNAMEs
|
||||
encountered. Thanks to Andy and the rt-n56u project for
|
||||
find this and helping to chase it down.
|
||||
|
||||
Fix wrong RCODE in authoritative DNS replies to PTR queries. The
|
||||
correct answer was included, but the RCODE was set to NXDOMAIN.
|
||||
Thanks to Craig McQueen for spotting this.
|
||||
|
||||
Make statistics available as DNS queries in the .bind TLD as
|
||||
well as logging them.
|
||||
|
||||
|
||||
version 2.68
|
||||
Use random addresses for DHCPv6 temporary address
|
||||
allocations, instead of algorithmically determined stable
|
||||
|
||||
@@ -14,8 +14,11 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
|
||||
|
||||
if [ $op = "--copy" ]; then
|
||||
pkg="$*"
|
||||
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
|
||||
pkg=`$pkg --static $op $*`
|
||||
else
|
||||
pkg=`$pkg $op $*`
|
||||
pkg=`$pkg $op $*`
|
||||
fi
|
||||
|
||||
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
|
||||
|
||||
14
debian/changelog
vendored
14
debian/changelog
vendored
@@ -1,6 +1,20 @@
|
||||
dnsmasq (2.70-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 23 Apr 2014 15:14:42 +0000
|
||||
|
||||
dnsmasq (2.69-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
* Set --local-service. (closes: #732610)
|
||||
This tells dnsmasq to ignore DNS requests that don't come
|
||||
from a local network. It's automatically ignored if
|
||||
--interface --except-interface, --listen-address or
|
||||
--auth-server exist in the configuration, so for most
|
||||
installations, it will have no effect, but for
|
||||
otherwise-unconfigured installations, it stops dnsmasq
|
||||
from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
|
||||
|
||||
|
||||
2
debian/default
vendored
2
debian/default
vendored
@@ -27,7 +27,7 @@ CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||
# If the resolvconf package is installed, dnsmasq will use its output
|
||||
# rather than the contents of /etc/resolv.conf to find upstream
|
||||
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||
# Not that including a "resolv-file=<filename>" line in
|
||||
# Note that including a "resolv-file=<filename>" line in
|
||||
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||
# installed: the line below must be uncommented.
|
||||
#IGNORE_RESOLVCONF=yes
|
||||
|
||||
8
debian/init
vendored
8
debian/init
vendored
@@ -90,6 +90,14 @@ if [ ! "$DNSMASQ_USER" ]; then
|
||||
DNSMASQ_USER="dnsmasq"
|
||||
fi
|
||||
|
||||
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
|
||||
# It's automatically ignored if --interface --except-interface, --listen-address
|
||||
# or --auth-server exist in the configuration, so for most installations, it will
|
||||
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
|
||||
# from being vulnerable to DNS-reflection attacks.
|
||||
|
||||
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
|
||||
|
||||
start()
|
||||
{
|
||||
# Return
|
||||
|
||||
6
debian/rules
vendored
6
debian/rules
vendored
@@ -19,6 +19,10 @@ LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
|
||||
|
||||
DEB_COPTS = $(COPTS)
|
||||
|
||||
# The nettle library in Debian is too old to include
|
||||
# ECC support.
|
||||
DEB_COPTS += -DNO_NETTLE_ECC
|
||||
|
||||
TARGET = install-i18n
|
||||
|
||||
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||
@@ -126,12 +130,14 @@ binary-arch: checkroot
|
||||
-d debian/base/usr/share/doc/$(package) \
|
||||
-d debian/base/usr/share/doc/$(package)/examples \
|
||||
-d debian/base/var/run \
|
||||
-d debian/base/usr/share/$(package) \
|
||||
-d debian/base/var/lib/misc
|
||||
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
|
||||
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
|
||||
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||
|
||||
@@ -20,6 +20,18 @@
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
#bogus-priv
|
||||
|
||||
# Uncomment these to enable DNSSEC validation and caching:
|
||||
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
|
||||
130
doc.html
130
doc.html
@@ -1,6 +1,6 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<TITLE> Dnsmasq - network services for small networks.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
@@ -11,82 +11,48 @@
|
||||
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
|
||||
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
|
||||
</table>
|
||||
Dnsmasq provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be
|
||||
lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used
|
||||
for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
|
||||
Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
|
||||
|
||||
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
|
||||
server. It is designed to provide DNS and, optionally, DHCP, to a
|
||||
small network. It can serve the names of local machines which are
|
||||
not in the global DNS. The DHCP server integrates with the DNS
|
||||
server and allows machines with DHCP-allocated addresses
|
||||
to appear in the DNS with names configured either in each host or
|
||||
in a central configuration file. Dnsmasq supports static and dynamic
|
||||
DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
|
||||
<P>
|
||||
Dnsmasq is targeted at home networks using NAT and
|
||||
connected to the internet via a modem, cable-modem or ADSL
|
||||
connection but would be a good choice for any smallish network (up to
|
||||
1000 clients is known to work) where low
|
||||
resource use and ease of configuration are important.
|
||||
<P>
|
||||
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
|
||||
Solaris and Mac OS X.
|
||||
Dnsmasq is included in at least the following Linux distributions:
|
||||
Gentoo, Debian, Slackware, Suse, Fedora,
|
||||
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
|
||||
CoyoteLinux, Endian Firewall and
|
||||
Clarkconnect. It is also available as FreeBSD, OpenBSD and NetBSD ports and is used in
|
||||
Linksys wireless routers (dd-wrt, openwrt and the stock firmware) and the m0n0wall project.
|
||||
<P>
|
||||
Dnsmasq provides the following features:
|
||||
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
|
||||
cacheing of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
|
||||
<DIR>
|
||||
|
||||
<LI>
|
||||
The DNS configuration of machines behind the firewall is simple and
|
||||
doesn't depend on the details of the ISP's dns servers
|
||||
<LI>
|
||||
Clients which try to do DNS lookups while a modem link to the
|
||||
internet is down will time out immediately.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq will serve names from the /etc/hosts file on the firewall
|
||||
machine: If the names of local machines are there, then they can all
|
||||
be addressed without having to maintain /etc/hosts on each machine.
|
||||
</LI>
|
||||
<LI>
|
||||
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||
multiple networks and IP ranges. It works across BOOTP relays and
|
||||
supports DHCP options including RFC3397 DNS search lists.
|
||||
Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address in the dnsmasq
|
||||
config file.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||
mappings (PTR records), reducing the load on upstream servers and
|
||||
improving performance (especially on modem connections).
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to automatically pick up the addresses of
|
||||
its upstream nameservers from ppp or dhcp configuration. It will
|
||||
automatically reload this information if it changes. This facility
|
||||
will be of particular interest to maintainers of Linux firewall
|
||||
distributions since it allows dns configuration to be made automatic.
|
||||
</LI>
|
||||
<LI>
|
||||
On IPv6-enabled boxes, dnsmasq can both talk to upstream servers via IPv6
|
||||
and offer DNS service via IPv6. On dual-stack (IPv4 and IPv6) boxes it talks
|
||||
both protocols and can even act as IPv6-to-IPv4 or IPv4-to-IPv6 forwarder.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq can be configured to send queries for certain domains to
|
||||
upstream servers handling only those domains. This makes integration
|
||||
with private DNS systems easy.
|
||||
</LI>
|
||||
<LI>
|
||||
Dnsmasq supports MX and SRV records and can be configured to return MX records
|
||||
for any or all local machines.
|
||||
</LI>
|
||||
<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
|
||||
<LI>Upstream servers can be configured in a variety of convenient ways, including dynamic configuration as these change on moving upstream network.
|
||||
<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides
|
||||
zone transfer to secondaries for the zone, if required.</LI>
|
||||
<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
|
||||
<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
|
||||
<LI>Internationalised domain names are supported.
|
||||
</DIR>
|
||||
<P>
|
||||
The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
|
||||
<DIR>
|
||||
<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
|
||||
<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
|
||||
includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
|
||||
<LI> There is a built in read-only TFTP server to support netboot.</LI>
|
||||
<LI> Machines which are configured by DHCP have their names automatically
|
||||
included in the DNS and the names can specified by each machine or
|
||||
centrally by associating a name with a MAC address or UID in the dnsmasq
|
||||
configuration file.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
|
||||
<DIR>
|
||||
<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
|
||||
<LI> Router advertisements can include the RDNSS option.</LI>
|
||||
<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
|
||||
for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
|
||||
</DIR>
|
||||
<P>
|
||||
|
||||
For extra compactness, unused features may be omitted at compile time.
|
||||
|
||||
|
||||
<H2>Get code.</H2>
|
||||
|
||||
@@ -102,7 +68,7 @@ the repo, or get a copy using git protocol with the command
|
||||
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
|
||||
|
||||
<H2>License.</H2>
|
||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
|
||||
for details.
|
||||
|
||||
<H2>Contact.</H2>
|
||||
@@ -110,7 +76,21 @@ There is a dnsmasq mailing list at <A
|
||||
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||
first location for queries, bugreports, suggestions etc.
|
||||
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||
You can contact me at <A
|
||||
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||
|
||||
<H2>Donations.</H2>
|
||||
Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project.
|
||||
These days I'm working on it as my main activity.
|
||||
I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make
|
||||
a contribution towards my expenses, please use the donation button below.
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online.">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
|
||||
|
||||
</BODY>
|
||||
|
||||
|
||||
@@ -13,7 +13,10 @@ Dnsmasq accepts DNS queries and either answers them from a small, local,
|
||||
cache or forwards them to a real, recursive, DNS server. It loads the
|
||||
contents of /etc/hosts so that local hostnames
|
||||
which do not appear in the global DNS can be resolved and also answers
|
||||
DNS queries for DHCP configured hosts. It can also act as the authoritative DNS server for one or more domains, allowing local names to appear in the global DNS.
|
||||
DNS queries for DHCP configured hosts. It can also act as the
|
||||
authoritative DNS server for one or more domains, allowing local names
|
||||
to appear in the global DNS. It can be configured to do DNSSEC
|
||||
validation.
|
||||
.PP
|
||||
The dnsmasq DHCP server supports static address assignments and multiple
|
||||
networks. It automatically
|
||||
@@ -205,6 +208,14 @@ resolve in the global DNS to a A and/or AAAA record which points to
|
||||
the address dnsmasq is listening on. When an interface is specified,
|
||||
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
|
||||
addresses associated with the interface.
|
||||
.TP
|
||||
.B --local-service
|
||||
Accept DNS queries only from hosts whose address is on a local subnet,
|
||||
ie a subnet for which an interface exists on the server. This option
|
||||
only has effect is there are no --interface --except-interface,
|
||||
--listen-address or --auth-server options. It is intended to be set as
|
||||
a default on installation, to allow unconfigured installations to be
|
||||
useful but also safe from being used for DNS amplification attacks.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<interface name>
|
||||
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
|
||||
@@ -412,6 +423,14 @@ source address specified but the port may be specified directly as
|
||||
part of the source address. Forcing queries to an interface is not
|
||||
implemented on all platforms supported by dnsmasq.
|
||||
.TP
|
||||
.B --rev-server=<ip-address>/<prefix-len>,<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
This is functionally the same as
|
||||
.B --server,
|
||||
but provides some syntactic sugar to make specifying address-to-name queries easier. For example
|
||||
.B --rev-server=1.2.3.0/24,192.168.0.1
|
||||
is exactly equivalent to
|
||||
.B --server=/3.2.1.in-addr.arpa/192.168.0.1
|
||||
.TP
|
||||
.B \-A, --address=/<domain>/[domain/]<ipaddr>
|
||||
Specify an IP address to return for any host in the given domains.
|
||||
Queries in the domains are never forwarded and always replied to
|
||||
@@ -587,12 +606,44 @@ validation by clients more efficient. Note that validation by clients is the mos
|
||||
clients unable to do validation, use of the AD bit set by dnsmasq is useful, provided that the network between
|
||||
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
|
||||
trust anchors provided, see
|
||||
.B --dnsskey.
|
||||
Because the DNSSEC validation process uses the cache, it is not permitted to reduce the cache size below the default when DNSSEC is enabled.
|
||||
.B --trust-anchor.
|
||||
Because the DNSSEC validation process uses the cache, it is not
|
||||
permitted to reduce the cache size below the default when DNSSEC is
|
||||
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
|
||||
ie capable of returning DNSSEC records with data. If they are not,
|
||||
then dnsmasq will not be able to determine the trusted status of
|
||||
answers. In the default mode, this menas that all replies will be
|
||||
marked as untrusted. If
|
||||
.B --dnssec-check-unsigned
|
||||
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
|
||||
.TP
|
||||
.B --dnskey=[<class>],<domain>,<flags>,<algorithm>,<base64-key>
|
||||
Provide DNSKEY records to act a trust anchors for DNSSEC validation. Typically these will be the keys for root zone,
|
||||
but trust anchors for limited domains are also possible.
|
||||
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
|
||||
Provide DS records to act a trust anchors for DNSSEC
|
||||
validation. Typically these will be the DS record(s) for Zone Signing
|
||||
key(s) of the root zone,
|
||||
but trust anchors for limited domains are also possible. The current
|
||||
root-zone trust anchors may be donwloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
.TP
|
||||
.B --dnssec-check-unsigned
|
||||
As a default, dnsmasq does not check that unsigned DNS replies are
|
||||
legitimate: they are assumed to be valid and passed on (without the
|
||||
"authentic data" bit set, of course). This does not protect against an
|
||||
attacker forging unsigned replies for signed DNS zones, but it is
|
||||
fast. If this flag is set, dnsmasq will check the zones of unsigned
|
||||
replies, to ensure that unsigned replies are allowed in those
|
||||
zones. The cost of this is more upstream queries and slower
|
||||
performance. See also the warning about upstream servers in the
|
||||
section on
|
||||
.B --dnssec
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
|
||||
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
|
||||
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
|
||||
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
|
||||
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
|
||||
which have not been throughly checked.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
|
||||
@@ -601,7 +652,10 @@ dnsmasq and the upstream servers, and the trustworthiness of the upstream server
|
||||
.TP
|
||||
.B --dnssec-debug
|
||||
Set debugging mode for the DNSSEC validation, set the Checking Disabled bit on upstream queries,
|
||||
and don't convert BOGUS replies to SERVFAIL responses.
|
||||
and don't convert replies which do not validate to responses with
|
||||
a return code of SERVFAIL. Note that
|
||||
setting this may affect DNS behaviour in bad ways, it is not an
|
||||
extra-logging flag and should not be set in production.
|
||||
.TP
|
||||
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
|
||||
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
|
||||
@@ -621,7 +675,7 @@ Interface-name and address-literal subnet specifications may be used
|
||||
freely in the same --auth-zone declaration.
|
||||
|
||||
The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. If not
|
||||
ip6.arpa domains which are served for reverse-DNS queries. If not
|
||||
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
|
||||
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
|
||||
unless you are familiar with RFC 2317 and have arranged the
|
||||
@@ -728,7 +782,7 @@ or from /etc/ethers will be served. A static-only subnet with address
|
||||
all zeros may be used as a "catch-all" address to enable replies to all
|
||||
Information-request packets on a subnet which is provided with
|
||||
stateless DHCPv6, ie
|
||||
.B --dhcp=range=::,static
|
||||
.B --dhcp-range=::,static
|
||||
|
||||
For IPv4, the <mode> may be
|
||||
.B proxy
|
||||
@@ -1661,6 +1715,13 @@ files. If extension(s) are given, any files which end in those
|
||||
extensions are skipped. Any files whose names end in ~ or start with . or start and end
|
||||
with # are always skipped. This flag may be given on the command
|
||||
line or in a configuration file.
|
||||
.TP
|
||||
.B --servers-file=<file>
|
||||
A special case of
|
||||
.B --conf-file
|
||||
which differs in two respects. Firstly, only --server and --rev-server are allowed
|
||||
in the configuration file included. Secondly, the file is re-read and the configuration
|
||||
therein is updated when dnsmasq recieves SIGHUP.
|
||||
.SH CONFIG FILE
|
||||
At startup, dnsmasq reads
|
||||
.I /etc/dnsmasq.conf,
|
||||
@@ -1701,12 +1762,22 @@ When it receives a SIGUSR1,
|
||||
writes statistics to the system log. It writes the cache size,
|
||||
the number of names which have had to removed from the cache before
|
||||
they expired in order to make room for new names and the total number
|
||||
of names that have been inserted into the cache. For each upstream
|
||||
of names that have been inserted into the cache. The number of cache hits and
|
||||
misses and the number of authoritative queries answered are also given. For each upstream
|
||||
server it gives the number of queries sent, and the number which
|
||||
resulted in an error. In
|
||||
.B --no-daemon
|
||||
mode or when full logging is enabled (-q), a complete dump of the
|
||||
contents of the cache is made.
|
||||
contents of the cache is made.
|
||||
|
||||
The cache statistics are also available in the DNS as answers to
|
||||
queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
|
||||
misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
|
||||
.B dig
|
||||
utility would be
|
||||
|
||||
dig +short chaos txt cachesize.bind
|
||||
|
||||
.PP
|
||||
When it receives SIGUSR2 and it is logging direct to a file (see
|
||||
.B --log-facility
|
||||
@@ -1810,7 +1881,7 @@ which has tags will be used in preference to an untagged
|
||||
.B dhcp-option,
|
||||
provided that _all_ the tags match somewhere in the
|
||||
set collected as described above. The prefix '!' on a tag means 'not'
|
||||
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
|
||||
tag purple is not in the set of valid tags. (If using this in a
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
which is a shell metacharacter)
|
||||
@@ -1962,7 +2033,7 @@ to particular hosts then
|
||||
will do so.
|
||||
|
||||
Dnsmasq acts as an authoritative server for in-addr.arpa and
|
||||
ipv6.arpa domains associated with the subnets given in auth-zone
|
||||
ip6.arpa domains associated with the subnets given in auth-zone
|
||||
declarations, so reverse (address to name) lookups can be simply
|
||||
configured with a suitable NS record, for instance in this example,
|
||||
where we allow 1.2.3.0/24 addresses.
|
||||
|
||||
@@ -706,7 +706,7 @@ l'un des sous-réseaux définis, ou dans un réseau correspondant à une plage D
|
||||
(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 ipv6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
in-addr.arpa et ip6.arpa servant à l'interrogation DNS inverse. Si la longueur
|
||||
de préfixe n'est pas spécifiée, elle sera par défaut de 24 pour IPv4 et 64 pour
|
||||
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
|
||||
@@ -2186,7 +2186,7 @@ spécifiques, vous pouvez le faire via :
|
||||
.fi
|
||||
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ipv6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
et ip6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
|
||||
@@ -231,8 +231,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
|
||||
|
||||
if (!found)
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
|
||||
if (found)
|
||||
nxdomain = 0;
|
||||
else
|
||||
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
272
src/cache.c
272
src/cache.c
@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL;
|
||||
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
||||
static union bigname *big_free = NULL;
|
||||
static int bignames_left, hash_size;
|
||||
static int uid = 1;
|
||||
|
||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||
static const struct {
|
||||
@@ -55,7 +54,9 @@ static const struct {
|
||||
{ 41, "OPT" },
|
||||
{ 43, "DS" },
|
||||
{ 46, "RRSIG" },
|
||||
{ 47, "NSEC" },
|
||||
{ 48, "DNSKEY" },
|
||||
{ 50, "NSEC3" },
|
||||
{ 249, "TKEY" },
|
||||
{ 250, "TSIG" },
|
||||
{ 251, "IXFR" },
|
||||
@@ -71,6 +72,19 @@ 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)
|
||||
{
|
||||
static unsigned int uid = 0;
|
||||
|
||||
uid++;
|
||||
|
||||
/* uid == 0 used to indicate CNAME to interface name. */
|
||||
if (uid == SRC_INTERFACE)
|
||||
uid++;
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
void cache_init(void)
|
||||
{
|
||||
struct crec *crecp;
|
||||
@@ -86,7 +100,7 @@ void cache_init(void)
|
||||
{
|
||||
cache_link(crecp);
|
||||
crecp->flags = 0;
|
||||
crecp->uid = uid++;
|
||||
crecp->uid = next_uid();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +195,7 @@ static void cache_blockdata_free(struct crec *crecp)
|
||||
else
|
||||
blockdata_free(crecp->addr.key.keydata);
|
||||
}
|
||||
else if (crecp->flags & F_DS)
|
||||
else if ((crecp->flags & F_DS) && !(crecp->flags & F_NEG))
|
||||
blockdata_free(crecp->addr.ds.keydata);
|
||||
}
|
||||
#endif
|
||||
@@ -190,10 +204,7 @@ static void cache_free(struct crec *crecp)
|
||||
{
|
||||
crecp->flags &= ~F_FORWARD;
|
||||
crecp->flags &= ~F_REVERSE;
|
||||
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (uid == -1)
|
||||
uid++;
|
||||
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
|
||||
|
||||
if (cache_tail)
|
||||
cache_tail->next = crecp;
|
||||
@@ -254,7 +265,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
|
||||
char *cache_get_cname_target(struct crec *crecp)
|
||||
{
|
||||
if (crecp->addr.cname.uid != -1)
|
||||
if (crecp->addr.cname.uid != SRC_INTERFACE)
|
||||
return cache_get_name(crecp->addr.cname.target.cache);
|
||||
|
||||
return crecp->addr.cname.target.int_name->name;
|
||||
@@ -287,7 +298,7 @@ struct crec *cache_enumerate(int init)
|
||||
|
||||
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||
{
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1)
|
||||
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
return 0;
|
||||
|
||||
/* NB. record may be reused as DS or DNSKEY, where uid is
|
||||
@@ -446,19 +457,21 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
int freed_all = flags & F_REVERSE;
|
||||
int free_avail = 0;
|
||||
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
|
||||
/* Don't log keys here, done elsewhere */
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
{
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don;t mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
}
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
|
||||
/* First remove any expired entries and entries for the name/address we
|
||||
are currently inserting. Fail is we attempt to delete a name from
|
||||
are currently inserting. Fail if we attempt to delete a name from
|
||||
/etc/hosts or DHCP. */
|
||||
if (!cache_scan_free(name, addr, now, flags))
|
||||
{
|
||||
@@ -560,7 +573,14 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
*cache_get_name(new) = 0;
|
||||
|
||||
if (addr)
|
||||
new->addr.addr = *addr;
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DS | F_DNSKEY))
|
||||
new->uid = addr->addr.dnssec.class;
|
||||
else
|
||||
#endif
|
||||
new->addr.addr = *addr;
|
||||
}
|
||||
|
||||
new->ttd = now + (time_t)ttl;
|
||||
new->next = new_chain;
|
||||
@@ -592,10 +612,13 @@ void cache_end_insert(void)
|
||||
new_chain = NULL;
|
||||
}
|
||||
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
|
||||
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
int no_rr = prot & F_NO_RR;
|
||||
|
||||
prot &= ~F_NO_RR;
|
||||
|
||||
if (crecp) /* iterating */
|
||||
ans = crecp->next;
|
||||
else
|
||||
@@ -643,7 +666,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!insert)
|
||||
if (!insert && !no_rr)
|
||||
{
|
||||
insert = up;
|
||||
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
|
||||
@@ -683,7 +706,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
}
|
||||
|
||||
struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
||||
time_t now, unsigned short prot)
|
||||
time_t now, unsigned int prot)
|
||||
{
|
||||
struct crec *ans;
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -760,13 +783,14 @@ static void add_hosts_cname(struct crec *target)
|
||||
crec->name.namep = a->alias;
|
||||
crec->addr.cname.target.cache = target;
|
||||
crec->addr.cname.uid = target->uid;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
add_hosts_cname(crec); /* handle chains */
|
||||
}
|
||||
}
|
||||
|
||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||
int index, struct crec **rhash, int hashsz)
|
||||
unsigned int index, struct crec **rhash, int hashsz)
|
||||
{
|
||||
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
|
||||
int i, nameexists = 0;
|
||||
@@ -870,7 +894,7 @@ static int gettok(FILE *f, char *token)
|
||||
}
|
||||
}
|
||||
|
||||
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
char *token = daemon->namebuff, *domain_suffix = NULL;
|
||||
@@ -980,7 +1004,7 @@ void cache_reload(void)
|
||||
struct cname *a;
|
||||
struct interface_name *intr;
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct dnskey *key;
|
||||
struct ds_config *ds;
|
||||
#endif
|
||||
|
||||
cache_inserted = cache_live_freed = 0;
|
||||
@@ -1020,23 +1044,24 @@ void cache_reload(void)
|
||||
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
|
||||
cache->name.namep = a->alias;
|
||||
cache->addr.cname.target.int_name = intr;
|
||||
cache->addr.cname.uid = -1;
|
||||
cache->addr.cname.uid = SRC_INTERFACE;
|
||||
cache->uid = next_uid();
|
||||
cache_hash(cache);
|
||||
add_hosts_cname(cache); /* handle chains */
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
for (key = daemon->dnskeys; key; key = key->next)
|
||||
for (ds = daemon->ds; ds; ds = ds->next)
|
||||
if ((cache = whine_malloc(sizeof(struct crec))) &&
|
||||
(cache->addr.key.keydata = blockdata_alloc(key->key, key->keylen)))
|
||||
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
|
||||
{
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DNSKEY | F_CONFIG | F_NAMEP;
|
||||
cache->name.namep = key->name;
|
||||
cache->addr.key.keylen = key->keylen;
|
||||
cache->addr.key.algo = key->algo;
|
||||
cache->addr.key.flags = key->flags;
|
||||
cache->addr.key.keytag = dnskey_keytag(key->algo, key->flags, (unsigned char *)key->key, key->keylen);
|
||||
cache->uid = key->class;
|
||||
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
|
||||
cache->name.namep = ds->name;
|
||||
cache->addr.ds.keylen = ds->digestlen;
|
||||
cache->addr.ds.algo = ds->algo;
|
||||
cache->addr.ds.keytag = ds->keytag;
|
||||
cache->addr.ds.digest = ds->digest_type;
|
||||
cache->uid = ds->class;
|
||||
cache_hash(cache);
|
||||
}
|
||||
#endif
|
||||
@@ -1056,7 +1081,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
|
||||
@@ -1064,7 +1089,7 @@ void cache_reload(void)
|
||||
{
|
||||
cache->name.namep = nl->name;
|
||||
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
|
||||
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1077,7 +1102,7 @@ void cache_reload(void)
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1141,6 +1166,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
|
||||
aliasc->name.namep = a->alias;
|
||||
aliasc->addr.cname.target.cache = target;
|
||||
aliasc->addr.cname.uid = target->uid;
|
||||
aliasc->uid = next_uid();
|
||||
cache_hash(aliasc);
|
||||
add_dhcp_cname(aliasc, ttd);
|
||||
}
|
||||
@@ -1228,7 +1254,7 @@ 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 = uid++;
|
||||
crec->uid = next_uid();
|
||||
cache_hash(crec);
|
||||
|
||||
add_dhcp_cname(crec, ttd);
|
||||
@@ -1236,6 +1262,101 @@ void cache_add_dhcp_entry(char *host_name, int prot,
|
||||
}
|
||||
#endif
|
||||
|
||||
int cache_make_stat(struct txt_record *t)
|
||||
{
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 60;
|
||||
int len;
|
||||
struct server *serv, *serv1;
|
||||
char *p;
|
||||
|
||||
if (!buff && !(buff = whine_malloc(60)))
|
||||
return 0;
|
||||
|
||||
p = buff;
|
||||
|
||||
switch (t->stat)
|
||||
{
|
||||
case TXT_STAT_CACHESIZE:
|
||||
sprintf(buff+1, "%d", daemon->cachesize);
|
||||
break;
|
||||
|
||||
case TXT_STAT_INSERTS:
|
||||
sprintf(buff+1, "%d", cache_inserted);
|
||||
break;
|
||||
|
||||
case TXT_STAT_EVICTIONS:
|
||||
sprintf(buff+1, "%d", cache_live_freed);
|
||||
break;
|
||||
|
||||
case TXT_STAT_MISSES:
|
||||
sprintf(buff+1, "%u", daemon->queries_forwarded);
|
||||
break;
|
||||
|
||||
case TXT_STAT_HITS:
|
||||
sprintf(buff+1, "%u", daemon->local_answer);
|
||||
break;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
case TXT_STAT_AUTH:
|
||||
sprintf(buff+1, "%u", daemon->auth_answer);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case TXT_STAT_SERVERS:
|
||||
/* sum counts from different records for same server */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
char *new, *lenp;
|
||||
int port, newlen, bytes_avail, bytes_needed;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
failed_queries += serv1->failed_queries;
|
||||
}
|
||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
lenp = p++; /* length */
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
if (bytes_needed >= bytes_avail)
|
||||
{
|
||||
/* expand buffer if necessary */
|
||||
newlen = bytes_needed + 1 + bufflen - bytes_avail;
|
||||
if (!(new = whine_malloc(newlen)))
|
||||
return 0;
|
||||
memcpy(new, buff, bufflen);
|
||||
free(buff);
|
||||
p = new + (p - buff);
|
||||
lenp = p - 1;
|
||||
buff = new;
|
||||
bufflen = newlen;
|
||||
bytes_avail = (p - buff) + bufflen;
|
||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
*lenp = bytes_needed;
|
||||
p += bytes_needed;
|
||||
}
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = p - buff;
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = strlen(buff+1);
|
||||
t->txt = (unsigned char *)buff;
|
||||
t->len = len + 1;
|
||||
*buff = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void dump_cache(time_t now)
|
||||
{
|
||||
@@ -1297,27 +1418,16 @@ void dump_cache(time_t now)
|
||||
else if (cache->flags & F_DS)
|
||||
{
|
||||
if (cache->flags & F_DNSKEY)
|
||||
{
|
||||
char tp[20];
|
||||
/* RRSIG */
|
||||
querystr("", tp, cache->addr.sig.type_covered);
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, tp);
|
||||
}
|
||||
else
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
/* RRSIG */
|
||||
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
|
||||
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
|
||||
else if (!(cache->flags & F_NEG))
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.ds.keytag,
|
||||
cache->addr.ds.algo, cache->addr.ds.digest);
|
||||
}
|
||||
else if (cache->flags & F_DNSKEY)
|
||||
{
|
||||
a = daemon->addrbuff;
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
cache->addr.key.algo, cache->addr.key.flags);
|
||||
}
|
||||
sprintf(a, "%5u %3u %3u", cache->addr.key.keytag,
|
||||
cache->addr.key.algo, cache->addr.key.flags);
|
||||
#endif
|
||||
else if (!(cache->flags & F_NEG) || !(cache->flags & F_FORWARD))
|
||||
{
|
||||
@@ -1365,11 +1475,13 @@ void dump_cache(time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
char *record_source(int index)
|
||||
char *record_source(unsigned int index)
|
||||
{
|
||||
struct hostsfile *ah;
|
||||
|
||||
if (index == 0)
|
||||
if (index == SRC_CONFIG)
|
||||
return "config";
|
||||
else if (index == SRC_HOSTS)
|
||||
return HOSTSFILE;
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
@@ -1379,14 +1491,45 @@ char *record_source(int index)
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
void querystr(char *desc, char *str, unsigned short type)
|
||||
char *querystr(char *desc, unsigned short type)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
sprintf(str, "%s[type=%d]", desc, type);
|
||||
int len = 10; /* strlen("type=xxxxx") */
|
||||
const char *types = NULL;
|
||||
static char *buff = NULL;
|
||||
static int bufflen = 0;
|
||||
|
||||
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
|
||||
if (typestr[i].type == type)
|
||||
sprintf(str,"%s[%s]", desc, typestr[i].name);
|
||||
{
|
||||
types = typestr[i].name;
|
||||
len = strlen(types);
|
||||
break;
|
||||
}
|
||||
|
||||
len += 3; /* braces, terminator */
|
||||
len += strlen(desc);
|
||||
|
||||
if (!buff || bufflen < len)
|
||||
{
|
||||
if (buff)
|
||||
free(buff);
|
||||
else if (len < 20)
|
||||
len = 20;
|
||||
|
||||
buff = whine_malloc(len);
|
||||
bufflen = len;
|
||||
}
|
||||
|
||||
if (buff)
|
||||
{
|
||||
if (types)
|
||||
sprintf(buff, "%s[%s]", desc, types);
|
||||
else
|
||||
sprintf(buff, "%s[type=%d]", desc, type);
|
||||
}
|
||||
|
||||
return buff ? buff : "";
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
@@ -1466,6 +1609,13 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||
source = arg;
|
||||
verb = "to";
|
||||
}
|
||||
else if (flags & F_IPSET)
|
||||
{
|
||||
source = "ipset add";
|
||||
dest = name;
|
||||
name = arg;
|
||||
verb = daemon->addrbuff;
|
||||
}
|
||||
else
|
||||
source = "cached";
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define KEYBLOCK_LEN 35 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
|
||||
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
@@ -30,7 +31,8 @@
|
||||
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
|
||||
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
|
||||
132
src/dbus.c
132
src/dbus.c
@@ -108,108 +108,6 @@ static void remove_watch(DBusWatch *watch, void *data)
|
||||
w = data; /* no warning */
|
||||
}
|
||||
|
||||
static void add_update_server(union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if ((serv->flags & SERV_FROM_DBUS) &&
|
||||
(serv->flags & SERV_MARK))
|
||||
{
|
||||
if (domain)
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
continue;
|
||||
}
|
||||
|
||||
serv->flags &= ~SERV_MARK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!serv && (serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
|
||||
if (domain && !(serv->domain = whine_malloc(strlen(domain)+1)))
|
||||
{
|
||||
free(serv);
|
||||
serv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
serv->flags = SERV_FROM_DBUS;
|
||||
if (domain)
|
||||
{
|
||||
strcpy(serv->domain, domain);
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
if (interface)
|
||||
strcpy(serv->interface, interface);
|
||||
else
|
||||
serv->interface[0] = 0;
|
||||
|
||||
if (source_addr->in.sin_family == AF_INET &&
|
||||
addr->in.sin_addr.s_addr == 0 &&
|
||||
serv->domain)
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
else
|
||||
{
|
||||
serv->flags &= ~SERV_NO_ADDR;
|
||||
serv->addr = *addr;
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_dbus(void)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* mark everything from DBUS */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_FROM_DBUS)
|
||||
serv->flags |= SERV_MARK;
|
||||
}
|
||||
|
||||
static void cleanup_dbus()
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
if (serv->domain)
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void dbus_read_servers(DBusMessage *message)
|
||||
{
|
||||
DBusMessageIter iter;
|
||||
@@ -218,8 +116,8 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
|
||||
dbus_message_iter_init(message, &iter);
|
||||
|
||||
mark_dbus();
|
||||
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int skip = 0;
|
||||
@@ -289,13 +187,13 @@ static void dbus_read_servers(DBusMessage *message)
|
||||
domain = NULL;
|
||||
|
||||
if (!skip)
|
||||
add_update_server(&addr, &source_addr, NULL, domain);
|
||||
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain);
|
||||
|
||||
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
cleanup_dbus();
|
||||
cleanup_servers();
|
||||
}
|
||||
|
||||
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
@@ -319,7 +217,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
strings ? "Expected array of string" : "Expected array of string arrays");
|
||||
}
|
||||
|
||||
mark_dbus();
|
||||
mark_servers(SERV_FROM_DBUS);
|
||||
|
||||
/* array_iter points to each "as" element in the outer array */
|
||||
dbus_message_iter_recurse(&iter, &array_iter);
|
||||
@@ -327,6 +225,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
{
|
||||
const char *str = NULL;
|
||||
union mysockaddr addr, source_addr;
|
||||
int flags = 0;
|
||||
char interface[IF_NAMESIZE];
|
||||
char *str_addr, *str_domain = NULL;
|
||||
|
||||
@@ -416,16 +315,19 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
memset(&interface, 0, sizeof(interface));
|
||||
|
||||
/* parse the IP address */
|
||||
addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, NULL);
|
||||
|
||||
if (addr_err)
|
||||
{
|
||||
if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
|
||||
{
|
||||
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
|
||||
"Invalid IP address '%s': %s",
|
||||
str, addr_err);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* 0.0.0.0 for server address == NULL, for Dbus */
|
||||
if (addr.in.sin_family == AF_INET &&
|
||||
addr.in.sin_addr.s_addr == 0)
|
||||
flags |= SERV_NO_ADDR;
|
||||
|
||||
if (strings)
|
||||
{
|
||||
char *p;
|
||||
@@ -439,7 +341,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str_domain);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain);
|
||||
} while ((str_domain = p));
|
||||
}
|
||||
else
|
||||
@@ -454,7 +356,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
dbus_message_iter_get_basic(&string_iter, &str);
|
||||
dbus_message_iter_next (&string_iter);
|
||||
|
||||
add_update_server(&addr, &source_addr, interface, str);
|
||||
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str);
|
||||
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
|
||||
}
|
||||
|
||||
@@ -462,7 +364,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
dbus_message_iter_next(&array_iter);
|
||||
}
|
||||
|
||||
cleanup_dbus();
|
||||
cleanup_servers();
|
||||
|
||||
if (dup)
|
||||
free(dup);
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#define T_RRSIG 46
|
||||
#define T_NSEC 47
|
||||
#define T_DNSKEY 48
|
||||
#define T_NSEC3 50
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_AXFR 252
|
||||
|
||||
@@ -98,7 +98,10 @@ int main (int argc, char **argv)
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
daemon->keyname = safe_malloc(MAXDNAME);
|
||||
{
|
||||
daemon->keyname = safe_malloc(MAXDNAME);
|
||||
daemon->workspacename = safe_malloc(MAXDNAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
@@ -144,7 +147,7 @@ int main (int argc, char **argv)
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!daemon->dnskeys)
|
||||
if (!daemon->ds)
|
||||
die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
|
||||
|
||||
if (daemon->cachesize < CACHESIZ)
|
||||
@@ -394,7 +397,7 @@ int main (int argc, char **argv)
|
||||
piperead = pipefd[0];
|
||||
pipewrite = pipefd[1];
|
||||
/* prime the pipe to load stuff first time. */
|
||||
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||
send_event(pipewrite, EVENT_INIT, 0, NULL);
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
@@ -658,10 +661,17 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
{
|
||||
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
|
||||
if (option_bool(OPT_DNSSEC_TIME))
|
||||
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (log_err != 0)
|
||||
@@ -1114,7 +1124,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
pid_t p;
|
||||
struct event_desc ev;
|
||||
int i;
|
||||
int i, check = 0;
|
||||
char *msg;
|
||||
|
||||
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||
@@ -1124,12 +1134,36 @@ static void async_event(int pipe, time_t now)
|
||||
switch (ev.event)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
|
||||
reset_option_bool(OPT_DNSSEC_TIME);
|
||||
}
|
||||
#endif
|
||||
/* fall through */
|
||||
|
||||
case EVENT_INIT:
|
||||
clear_cache_and_reload(now);
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if (daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check = 1;
|
||||
}
|
||||
|
||||
if (daemon->servers_file)
|
||||
{
|
||||
read_servers_file();
|
||||
check = 1;
|
||||
}
|
||||
|
||||
if (check)
|
||||
check_servers();
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
rerun_scripts();
|
||||
#endif
|
||||
|
||||
@@ -164,6 +164,7 @@ struct event_desc {
|
||||
#define EVENT_FORK_ERR 18
|
||||
#define EVENT_LUA_ERR 19
|
||||
#define EVENT_TFTP_ERR 20
|
||||
#define EVENT_INIT 21
|
||||
|
||||
/* Exit codes. */
|
||||
#define EC_GOOD 0
|
||||
@@ -230,9 +231,11 @@ struct event_desc {
|
||||
#define OPT_QUIET_DHCP6 43
|
||||
#define OPT_QUIET_RA 44
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_DNSSEC_PERMISS 46
|
||||
#define OPT_DNSSEC_TIME 46
|
||||
#define OPT_DNSSEC_DEBUG 47
|
||||
#define OPT_LAST 48
|
||||
#define OPT_DNSSEC_NO_SIGN 48
|
||||
#define OPT_LOCAL_SERVICE 49
|
||||
#define OPT_LAST 50
|
||||
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||
@@ -278,10 +281,19 @@ struct naptr {
|
||||
struct naptr *next;
|
||||
};
|
||||
|
||||
#define TXT_STAT_CACHESIZE 1
|
||||
#define TXT_STAT_INSERTS 2
|
||||
#define TXT_STAT_EVICTIONS 3
|
||||
#define TXT_STAT_MISSES 4
|
||||
#define TXT_STAT_HITS 5
|
||||
#define TXT_STAT_AUTH 6
|
||||
#define TXT_STAT_SERVERS 7
|
||||
|
||||
struct txt_record {
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
int stat;
|
||||
struct txt_record *next;
|
||||
};
|
||||
|
||||
@@ -295,10 +307,10 @@ struct cname {
|
||||
struct cname *next;
|
||||
};
|
||||
|
||||
struct dnskey {
|
||||
char *name, *key;
|
||||
int keylen, class, algo, flags;
|
||||
struct dnskey *next;
|
||||
struct ds_config {
|
||||
char *name, *digest;
|
||||
int digestlen, class, algo, keytag, digest_type;
|
||||
struct ds_config *next;
|
||||
};
|
||||
|
||||
#define ADDRLIST_LITERAL 1
|
||||
@@ -365,7 +377,7 @@ struct crec {
|
||||
struct crec *cache;
|
||||
struct interface_name *int_name;
|
||||
} target;
|
||||
int uid; /* -1 if union is interface-name */
|
||||
unsigned int uid; /* 0 if union is interface-name */
|
||||
} cname;
|
||||
struct {
|
||||
struct blockdata *keydata;
|
||||
@@ -386,7 +398,7 @@ struct crec {
|
||||
} addr;
|
||||
time_t ttd; /* time to die */
|
||||
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
|
||||
int uid;
|
||||
unsigned int uid;
|
||||
unsigned short flags;
|
||||
union {
|
||||
char sname[SMALLDNAME];
|
||||
@@ -423,6 +435,14 @@ struct crec {
|
||||
#define F_DNSSEC (1u<<22)
|
||||
#define F_KEYTAG (1u<<23)
|
||||
#define F_SECSTAT (1u<<24)
|
||||
#define F_NO_RR (1u<<25)
|
||||
#define F_IPSET (1u<<26)
|
||||
|
||||
/* Values of uid in crecs with F_CONFIG bit set. */
|
||||
#define SRC_INTERFACE 0
|
||||
#define SRC_CONFIG 1
|
||||
#define SRC_HOSTS 2
|
||||
#define SRC_AH 3
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
@@ -455,6 +475,7 @@ union mysockaddr {
|
||||
#define SERV_COUNTED 512 /* workspace for log code */
|
||||
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
|
||||
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
|
||||
#define SERV_FROM_FILE 4096 /* read from --servers-file */
|
||||
|
||||
struct serverfd {
|
||||
int fd;
|
||||
@@ -521,7 +542,7 @@ struct hostsfile {
|
||||
struct hostsfile *next;
|
||||
int flags;
|
||||
char *fname;
|
||||
int index; /* matches to cache entries for logging */
|
||||
unsigned int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
|
||||
@@ -532,12 +553,21 @@ struct hostsfile {
|
||||
#define STAT_NEED_DS 4
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_NO_SIG 8
|
||||
#define STAT_NO_DS 9
|
||||
#define STAT_NEED_DS_NEG 10
|
||||
#define STAT_CHASE_CNAME 11
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
#define FREC_HAS_SUBNET 4
|
||||
#define FREC_DNSKEY_QUERY 8
|
||||
#define FREC_DS_QUERY 16
|
||||
#define FREC_AD_QUESTION 32
|
||||
#define FREC_DO_QUESTION 64
|
||||
#define FREC_ADDED_PHEADER 128
|
||||
#define FREC_CHECK_NOSIGN 256
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
#define HASH_SIZE 20 /* SHA-1 digest size */
|
||||
@@ -559,7 +589,7 @@ struct frec {
|
||||
time_t time;
|
||||
unsigned char *hash[HASH_SIZE];
|
||||
#ifdef HAVE_DNSSEC
|
||||
int class;
|
||||
int class, work_counter;
|
||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||
size_t stash_len;
|
||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||
@@ -862,6 +892,7 @@ extern struct daemon {
|
||||
unsigned int options, options2;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
char *servers_file;
|
||||
struct mx_srv_record *mxnames;
|
||||
struct naptr *naptr;
|
||||
struct txt_record *txt, *rr;
|
||||
@@ -928,7 +959,7 @@ extern struct daemon {
|
||||
struct prefix_class *prefix_classes;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct dnskey *dnskeys;
|
||||
struct ds_config *ds;
|
||||
#endif
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
@@ -937,6 +968,7 @@ extern struct daemon {
|
||||
char *namebuff; /* MAXDNAME size buffer */
|
||||
#ifdef HAVE_DNSSEC
|
||||
char *keyname; /* MAXDNAME size buffer */
|
||||
char *workspacename; /* ditto */
|
||||
#endif
|
||||
unsigned int local_answer, queries_forwarded, auth_answer;
|
||||
struct frec *frec_list;
|
||||
@@ -952,6 +984,7 @@ extern struct daemon {
|
||||
pid_t tcp_pids[MAX_PROCS];
|
||||
struct randfd randomsocks[RANDOM_SOCKS];
|
||||
int v6pktinfo;
|
||||
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
|
||||
|
||||
/* DHCP state */
|
||||
int dhcpfd, helperfd, pxefd;
|
||||
@@ -989,13 +1022,13 @@ extern struct daemon {
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *desc, char *str, unsigned short type);
|
||||
char *record_source(unsigned int index);
|
||||
char *querystr(char *desc, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
struct all_addr *addr, time_t now,
|
||||
unsigned short prot);
|
||||
unsigned int prot);
|
||||
struct crec *cache_find_by_name(struct crec *crecp,
|
||||
char *name, time_t now, unsigned short prot);
|
||||
char *name, time_t now, unsigned int prot);
|
||||
void cache_end_insert(void);
|
||||
void cache_start_insert(void);
|
||||
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
@@ -1005,6 +1038,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||
void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
int cache_make_stat(struct txt_record *t);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *cache_get_cname_target(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
@@ -1031,6 +1065,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes);
|
||||
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
|
||||
unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
@@ -1040,7 +1075,8 @@ 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);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd, int *do_bit);
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
@@ -1075,8 +1111,10 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer);
|
||||
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
|
||||
|
||||
/* util.c */
|
||||
@@ -1104,9 +1142,6 @@ void prettyprint_time(char *buf, unsigned int t);
|
||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type);
|
||||
#ifdef HAVE_DNSSEC
|
||||
int parse_base64(char *in, char *out);
|
||||
#endif
|
||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||
unsigned int mask);
|
||||
int expand_buf(struct iovec *iov, size_t size);
|
||||
@@ -1130,6 +1165,7 @@ void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
void reread_dhcp(void);
|
||||
void read_servers_file(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
void reset_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
@@ -1153,6 +1189,13 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
|
||||
int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void mark_servers(int flag);
|
||||
void cleanup_servers(void);
|
||||
void add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
|
||||
1385
src/dnssec.c
1385
src/dnssec.c
File diff suppressed because it is too large
Load Diff
793
src/forward.c
793
src/forward.c
File diff suppressed because it is too large
Load Diff
263
src/network.c
263
src/network.c
@@ -268,7 +268,40 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
|
||||
if (!label)
|
||||
label = ifr.ifr_name;
|
||||
|
||||
/* maintain a list of all addresses on all interfaces for --local-service option */
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *al;
|
||||
|
||||
if (param->spare)
|
||||
{
|
||||
al = param->spare;
|
||||
param->spare = al->next;
|
||||
}
|
||||
else
|
||||
al = whine_malloc(sizeof(struct addrlist));
|
||||
|
||||
if (al)
|
||||
{
|
||||
al->next = daemon->interface_addrs;
|
||||
daemon->interface_addrs = al;
|
||||
al->prefixlen = prefixlen;
|
||||
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
al->addr.addr.addr4 = addr->in.sin_addr;
|
||||
al->flags = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->flags = ADDRLIST_IPV6;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||
@@ -565,6 +598,15 @@ int enumerate_interfaces(int reset)
|
||||
intname->addr = NULL;
|
||||
}
|
||||
|
||||
/* Remove list of addresses of local interfaces */
|
||||
for (addr = daemon->interface_addrs; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
daemon->interface_addrs = NULL;
|
||||
|
||||
#ifdef HAVE_AUTH
|
||||
/* remove addresses stored against auth_zone subnets, but not
|
||||
ones configured as address literals */
|
||||
@@ -1254,87 +1296,187 @@ void pre_allocate_sfds(void)
|
||||
}
|
||||
}
|
||||
|
||||
void mark_servers(int flag)
|
||||
{
|
||||
struct server *serv;
|
||||
|
||||
/* mark everything with argument flag */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & flag)
|
||||
serv->flags |= SERV_MARK;
|
||||
}
|
||||
|
||||
void cleanup_servers(void)
|
||||
{
|
||||
struct server *serv, *tmp, **up;
|
||||
|
||||
/* unlink and free anything still marked. */
|
||||
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
|
||||
{
|
||||
tmp = serv->next;
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
server_gone(serv);
|
||||
*up = serv->next;
|
||||
if (serv->domain)
|
||||
free(serv->domain);
|
||||
free(serv);
|
||||
}
|
||||
else
|
||||
up = &serv->next;
|
||||
}
|
||||
}
|
||||
|
||||
void add_update_server(int flags,
|
||||
union mysockaddr *addr,
|
||||
union mysockaddr *source_addr,
|
||||
const char *interface,
|
||||
const char *domain)
|
||||
{
|
||||
struct server *serv, *next = NULL;
|
||||
char *domain_str = NULL;
|
||||
|
||||
/* See if there is a suitable candidate, and unmark */
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_MARK)
|
||||
{
|
||||
if (domain)
|
||||
{
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (serv->flags & SERV_HAS_DOMAIN)
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
domain_str = serv->domain;
|
||||
next = serv->next;
|
||||
}
|
||||
else if ((serv = whine_malloc(sizeof (struct server))))
|
||||
{
|
||||
/* Not found, create a new one. */
|
||||
if (domain && !(domain_str = whine_malloc(strlen(domain)+1)))
|
||||
{
|
||||
free(serv);
|
||||
serv = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct server *s;
|
||||
/* Add to the end of the chain, for order */
|
||||
if (!daemon->servers)
|
||||
daemon->servers = serv;
|
||||
else
|
||||
{
|
||||
for (s = daemon->servers; s->next; s = s->next);
|
||||
s->next = serv;
|
||||
}
|
||||
if (domain)
|
||||
strcpy(domain_str, domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (serv)
|
||||
{
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->flags = flags;
|
||||
serv->domain = domain_str;
|
||||
serv->next = next;
|
||||
serv->queries = serv->failed_queries = 0;
|
||||
|
||||
if (domain)
|
||||
serv->flags |= SERV_HAS_DOMAIN;
|
||||
|
||||
if (interface)
|
||||
strcpy(serv->interface, interface);
|
||||
if (addr)
|
||||
serv->addr = *addr;
|
||||
if (source_addr)
|
||||
serv->source_addr = *source_addr;
|
||||
}
|
||||
}
|
||||
|
||||
void check_servers(void)
|
||||
{
|
||||
struct irec *iface;
|
||||
struct server *new, *tmp, *ret = NULL;
|
||||
struct server *serv;
|
||||
int port = 0;
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
{
|
||||
tmp = new->next;
|
||||
|
||||
if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
port = prettyprint_addr(&new->addr, daemon->namebuff);
|
||||
port = prettyprint_addr(&serv->addr, daemon->namebuff);
|
||||
|
||||
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
|
||||
if (new->addr.sa.sa_family == AF_INET &&
|
||||
new->addr.in.sin_addr.s_addr == 0)
|
||||
if (serv->addr.sa.sa_family == AF_INET &&
|
||||
serv->addr.in.sin_addr.s_addr == 0)
|
||||
{
|
||||
free(new);
|
||||
serv->flags |= SERV_MARK;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&new->addr, &iface->addr))
|
||||
if (sockaddr_isequal(&serv->addr, &iface->addr))
|
||||
break;
|
||||
if (iface)
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
|
||||
free(new);
|
||||
serv->flags |= SERV_MARK;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Do we need a socket set? */
|
||||
if (!new->sfd &&
|
||||
!(new->sfd = allocate_sfd(&new->source_addr, new->interface)) &&
|
||||
if (!serv->sfd &&
|
||||
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface)) &&
|
||||
errno != 0)
|
||||
{
|
||||
my_syslog(LOG_WARNING,
|
||||
_("ignoring nameserver %s - cannot make/bind socket: %s"),
|
||||
daemon->namebuff, strerror(errno));
|
||||
free(new);
|
||||
serv->flags |= SERV_MARK;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* reverse order - gets it right. */
|
||||
new->next = ret;
|
||||
ret = new;
|
||||
|
||||
if (!(new->flags & SERV_NO_REBIND))
|
||||
if (!(serv->flags & SERV_NO_REBIND))
|
||||
{
|
||||
if (new->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
|
||||
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
|
||||
{
|
||||
char *s1, *s2;
|
||||
if (!(new->flags & SERV_HAS_DOMAIN))
|
||||
if (!(serv->flags & SERV_HAS_DOMAIN))
|
||||
s1 = _("unqualified"), s2 = _("names");
|
||||
else if (strlen(new->domain) == 0)
|
||||
else if (strlen(serv->domain) == 0)
|
||||
s1 = _("default"), s2 = "";
|
||||
else
|
||||
s1 = _("domain"), s2 = new->domain;
|
||||
s1 = _("domain"), s2 = serv->domain;
|
||||
|
||||
if (new->flags & SERV_NO_ADDR)
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
my_syslog(LOG_INFO, _("using local addresses only for %s %s"), s1, s2);
|
||||
else if (new->flags & SERV_USE_RESOLV)
|
||||
else if (serv->flags & SERV_USE_RESOLV)
|
||||
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
|
||||
else if (!(new->flags & SERV_LITERAL_ADDRESS))
|
||||
else if (!(serv->flags & SERV_LITERAL_ADDRESS))
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
|
||||
}
|
||||
else if (new->interface[0] != 0)
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
|
||||
else if (serv->interface[0] != 0)
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
|
||||
else
|
||||
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
|
||||
}
|
||||
}
|
||||
|
||||
daemon->servers = ret;
|
||||
|
||||
cleanup_servers();
|
||||
}
|
||||
|
||||
/* Return zero if no servers found, in that case we keep polling.
|
||||
@@ -1343,9 +1485,6 @@ int reload_servers(char *fname)
|
||||
{
|
||||
FILE *f;
|
||||
char *line;
|
||||
struct server *old_servers = NULL;
|
||||
struct server *new_servers = NULL;
|
||||
struct server *serv;
|
||||
int gotone = 0;
|
||||
|
||||
/* buff happens to be MAXDNAME long... */
|
||||
@@ -1354,28 +1493,9 @@ int reload_servers(char *fname)
|
||||
my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* move old servers to free list - we can reuse the memory
|
||||
and not risk malloc if there are the same or fewer new servers.
|
||||
Servers which were specced on the command line go to the new list. */
|
||||
for (serv = daemon->servers; serv;)
|
||||
{
|
||||
struct server *tmp = serv->next;
|
||||
if (serv->flags & SERV_FROM_RESOLV)
|
||||
{
|
||||
serv->next = old_servers;
|
||||
old_servers = serv;
|
||||
/* forward table rules reference servers, so have to blow them away */
|
||||
server_gone(serv);
|
||||
}
|
||||
else
|
||||
{
|
||||
serv->next = new_servers;
|
||||
new_servers = serv;
|
||||
}
|
||||
serv = tmp;
|
||||
}
|
||||
|
||||
|
||||
mark_servers(SERV_FROM_RESOLV);
|
||||
|
||||
while ((line = fgets(daemon->namebuff, MAXDNAME, f)))
|
||||
{
|
||||
union mysockaddr addr, source_addr;
|
||||
@@ -1434,38 +1554,12 @@ int reload_servers(char *fname)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (old_servers)
|
||||
{
|
||||
serv = old_servers;
|
||||
old_servers = old_servers->next;
|
||||
}
|
||||
else if (!(serv = whine_malloc(sizeof (struct server))))
|
||||
continue;
|
||||
|
||||
/* this list is reverse ordered:
|
||||
it gets reversed again in check_servers */
|
||||
serv->next = new_servers;
|
||||
new_servers = serv;
|
||||
serv->addr = addr;
|
||||
serv->source_addr = source_addr;
|
||||
serv->domain = NULL;
|
||||
serv->interface[0] = 0;
|
||||
serv->sfd = NULL;
|
||||
serv->flags = SERV_FROM_RESOLV;
|
||||
serv->queries = serv->failed_queries = 0;
|
||||
add_update_server(SERV_FROM_RESOLV, &addr, &source_addr, NULL, NULL);
|
||||
gotone = 1;
|
||||
}
|
||||
|
||||
/* Free any memory not used. */
|
||||
while (old_servers)
|
||||
{
|
||||
struct server *tmp = old_servers->next;
|
||||
free(old_servers);
|
||||
old_servers = tmp;
|
||||
}
|
||||
|
||||
daemon->servers = new_servers;
|
||||
fclose(f);
|
||||
cleanup_servers();
|
||||
|
||||
return gotone;
|
||||
}
|
||||
@@ -1476,7 +1570,8 @@ void newaddress(time_t now)
|
||||
{
|
||||
(void)now;
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
|
||||
daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
|
||||
452
src/option.c
452
src/option.c
@@ -64,83 +64,88 @@ struct myoption {
|
||||
#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
|
||||
|
||||
/* options which don't have a one-char version */
|
||||
#define LOPT_RELOAD 256
|
||||
#define LOPT_NO_NAMES 257
|
||||
#define LOPT_TFTP 258
|
||||
#define LOPT_SECURE 259
|
||||
#define LOPT_PREFIX 260
|
||||
#define LOPT_PTR 261
|
||||
#define LOPT_BRIDGE 262
|
||||
#define LOPT_TFTP_MAX 263
|
||||
#define LOPT_FORCE 264
|
||||
#define LOPT_NOBLOCK 265
|
||||
#define LOPT_LOG_OPTS 266
|
||||
#define LOPT_MAX_LOGS 267
|
||||
#define LOPT_CIRCUIT 268
|
||||
#define LOPT_REMOTE 269
|
||||
#define LOPT_SUBSCR 270
|
||||
#define LOPT_INTNAME 271
|
||||
#define LOPT_BANK 272
|
||||
#define LOPT_DHCP_HOST 273
|
||||
#define LOPT_APREF 274
|
||||
#define LOPT_OVERRIDE 275
|
||||
#define LOPT_TFTPPORTS 276
|
||||
#define LOPT_REBIND 277
|
||||
#define LOPT_NOLAST 278
|
||||
#define LOPT_OPTS 279
|
||||
#define LOPT_DHCP_OPTS 280
|
||||
#define LOPT_MATCH 281
|
||||
#define LOPT_BROADCAST 282
|
||||
#define LOPT_NEGTTL 283
|
||||
#define LOPT_ALTPORT 284
|
||||
#define LOPT_SCRIPTUSR 285
|
||||
#define LOPT_LOCAL 286
|
||||
#define LOPT_NAPTR 287
|
||||
#define LOPT_MINPORT 288
|
||||
#define LOPT_DHCP_FQDN 289
|
||||
#define LOPT_CNAME 290
|
||||
#define LOPT_PXE_PROMT 291
|
||||
#define LOPT_PXE_SERV 292
|
||||
#define LOPT_TEST 293
|
||||
#define LOPT_TAG_IF 294
|
||||
#define LOPT_PROXY 295
|
||||
#define LOPT_GEN_NAMES 296
|
||||
#define LOPT_MAXTTL 297
|
||||
#define LOPT_NO_REBIND 298
|
||||
#define LOPT_LOC_REBND 299
|
||||
#define LOPT_ADD_MAC 300
|
||||
#define LOPT_DNSSEC 301
|
||||
#define LOPT_INCR_ADDR 302
|
||||
#define LOPT_CONNTRACK 303
|
||||
#define LOPT_FQDN 304
|
||||
#define LOPT_LUASCRIPT 305
|
||||
#define LOPT_RA 306
|
||||
#define LOPT_DUID 307
|
||||
#define LOPT_HOST_REC 308
|
||||
#define LOPT_TFTP_LC 309
|
||||
#define LOPT_RR 310
|
||||
#define LOPT_CLVERBIND 311
|
||||
#define LOPT_MAXCTTL 312
|
||||
#define LOPT_AUTHZONE 313
|
||||
#define LOPT_AUTHSERV 314
|
||||
#define LOPT_AUTHTTL 315
|
||||
#define LOPT_AUTHSOA 316
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#define LOPT_RELOAD 256
|
||||
#define LOPT_NO_NAMES 257
|
||||
#define LOPT_TFTP 258
|
||||
#define LOPT_SECURE 259
|
||||
#define LOPT_PREFIX 260
|
||||
#define LOPT_PTR 261
|
||||
#define LOPT_BRIDGE 262
|
||||
#define LOPT_TFTP_MAX 263
|
||||
#define LOPT_FORCE 264
|
||||
#define LOPT_NOBLOCK 265
|
||||
#define LOPT_LOG_OPTS 266
|
||||
#define LOPT_MAX_LOGS 267
|
||||
#define LOPT_CIRCUIT 268
|
||||
#define LOPT_REMOTE 269
|
||||
#define LOPT_SUBSCR 270
|
||||
#define LOPT_INTNAME 271
|
||||
#define LOPT_BANK 272
|
||||
#define LOPT_DHCP_HOST 273
|
||||
#define LOPT_APREF 274
|
||||
#define LOPT_OVERRIDE 275
|
||||
#define LOPT_TFTPPORTS 276
|
||||
#define LOPT_REBIND 277
|
||||
#define LOPT_NOLAST 278
|
||||
#define LOPT_OPTS 279
|
||||
#define LOPT_DHCP_OPTS 280
|
||||
#define LOPT_MATCH 281
|
||||
#define LOPT_BROADCAST 282
|
||||
#define LOPT_NEGTTL 283
|
||||
#define LOPT_ALTPORT 284
|
||||
#define LOPT_SCRIPTUSR 285
|
||||
#define LOPT_LOCAL 286
|
||||
#define LOPT_NAPTR 287
|
||||
#define LOPT_MINPORT 288
|
||||
#define LOPT_DHCP_FQDN 289
|
||||
#define LOPT_CNAME 290
|
||||
#define LOPT_PXE_PROMT 291
|
||||
#define LOPT_PXE_SERV 292
|
||||
#define LOPT_TEST 293
|
||||
#define LOPT_TAG_IF 294
|
||||
#define LOPT_PROXY 295
|
||||
#define LOPT_GEN_NAMES 296
|
||||
#define LOPT_MAXTTL 297
|
||||
#define LOPT_NO_REBIND 298
|
||||
#define LOPT_LOC_REBND 299
|
||||
#define LOPT_ADD_MAC 300
|
||||
#define LOPT_DNSSEC 301
|
||||
#define LOPT_INCR_ADDR 302
|
||||
#define LOPT_CONNTRACK 303
|
||||
#define LOPT_FQDN 304
|
||||
#define LOPT_LUASCRIPT 305
|
||||
#define LOPT_RA 306
|
||||
#define LOPT_DUID 307
|
||||
#define LOPT_HOST_REC 308
|
||||
#define LOPT_TFTP_LC 309
|
||||
#define LOPT_RR 310
|
||||
#define LOPT_CLVERBIND 311
|
||||
#define LOPT_MAXCTTL 312
|
||||
#define LOPT_AUTHZONE 313
|
||||
#define LOPT_AUTHSERV 314
|
||||
#define LOPT_AUTHTTL 315
|
||||
#define LOPT_AUTHSOA 316
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#endif
|
||||
#define LOPT_RELAY 323
|
||||
#define LOPT_RA_PARAM 324
|
||||
#define LOPT_ADD_SBNET 325
|
||||
#define LOPT_QUIET_DHCP 326
|
||||
#define LOPT_QUIET_DHCP6 327
|
||||
#define LOPT_QUIET_RA 328
|
||||
#define LOPT_SEC_VALID 329
|
||||
#define LOPT_DNSKEY 330
|
||||
#define LOPT_DNSSEC_DEBUG 331
|
||||
#define LOPT_RELAY 323
|
||||
#define LOPT_RA_PARAM 324
|
||||
#define LOPT_ADD_SBNET 325
|
||||
#define LOPT_QUIET_DHCP 326
|
||||
#define LOPT_QUIET_DHCP6 327
|
||||
#define LOPT_QUIET_RA 328
|
||||
#define LOPT_SEC_VALID 329
|
||||
#define LOPT_TRUST_ANCHOR 330
|
||||
#define LOPT_DNSSEC_DEBUG 331
|
||||
#define LOPT_REV_SERV 332
|
||||
#define LOPT_SERVERS_FILE 333
|
||||
#define LOPT_DNSSEC_CHECK 334
|
||||
#define LOPT_LOCAL_SERVICE 335
|
||||
#define LOPT_DNSSEC_TIME 336
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -157,6 +162,7 @@ static const struct myoption opts[] =
|
||||
{ "user", 2, 0, 'u' },
|
||||
{ "group", 2, 0, 'g' },
|
||||
{ "resolv-file", 2, 0, 'r' },
|
||||
{ "servers-file", 1, 0, LOPT_SERVERS_FILE },
|
||||
{ "mx-host", 1, 0, 'm' },
|
||||
{ "mx-target", 1, 0, 't' },
|
||||
{ "cache-size", 2, 0, 'c' },
|
||||
@@ -171,6 +177,7 @@ static const struct myoption opts[] =
|
||||
{ "domain-suffix", 1, 0, 's' },
|
||||
{ "interface", 1, 0, 'i' },
|
||||
{ "listen-address", 1, 0, 'a' },
|
||||
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
|
||||
{ "bogus-priv", 0, 0, 'b' },
|
||||
{ "bogus-nxdomain", 1, 0, 'B' },
|
||||
{ "selfmx", 0, 0, 'e' },
|
||||
@@ -178,6 +185,7 @@ static const struct myoption opts[] =
|
||||
{ "pid-file", 2, 0, 'x' },
|
||||
{ "strict-order", 0, 0, 'o' },
|
||||
{ "server", 1, 0, 'S' },
|
||||
{ "rev-server", 1, 0, LOPT_REV_SERV },
|
||||
{ "local", 1, 0, LOPT_LOCAL },
|
||||
{ "address", 1, 0, 'A' },
|
||||
{ "conf-file", 2, 0, 'C' },
|
||||
@@ -277,8 +285,10 @@ static const struct myoption opts[] =
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||
{ "dnssec", 0, 0, LOPT_SEC_VALID },
|
||||
{ "dnskey", 1, 0, LOPT_DNSKEY },
|
||||
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
|
||||
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
|
||||
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
|
||||
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
@@ -347,7 +357,9 @@ static struct {
|
||||
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
|
||||
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
|
||||
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
|
||||
{ LOPT_SERVERS_FILE, ARG_ONE, "<path>", gettext_noop("Specify path to file with server= options"), NULL },
|
||||
{ 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
|
||||
{ LOPT_REV_SERV, ARG_DUP, "<addr>/<prefix>,<ipaddr>", gettext_noop("Specify address of upstream servers for reverse address queries"), NULL },
|
||||
{ LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
|
||||
{ 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
|
||||
{ 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
|
||||
@@ -430,8 +442,10 @@ static struct {
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
{ LOPT_DNSKEY, ARG_DUP, "<domain>,<algo>,<key>", gettext_noop("Specify trust anchor DNSKEY"), 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_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
@@ -439,6 +453,7 @@ static struct {
|
||||
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
|
||||
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), NULL },
|
||||
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
|
||||
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -590,20 +605,37 @@ static int atoi_check16(char *a, int *res)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void add_txt(char *name, char *txt)
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
static int atoi_check8(char *a, int *res)
|
||||
{
|
||||
if (!(atoi_check(a, res)) ||
|
||||
*res < 0 ||
|
||||
*res > 0xff)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_txt(char *name, char *txt, int stat)
|
||||
{
|
||||
size_t len = strlen(txt);
|
||||
struct txt_record *r = opt_malloc(sizeof(struct txt_record));
|
||||
|
||||
if (txt)
|
||||
{
|
||||
size_t len = strlen(txt);
|
||||
r->txt = opt_malloc(len+1);
|
||||
r->len = len+1;
|
||||
*(r->txt) = len;
|
||||
memcpy((r->txt)+1, txt, len);
|
||||
}
|
||||
|
||||
r->stat = stat;
|
||||
r->name = opt_string_alloc(name);
|
||||
r->next = daemon->txt;
|
||||
daemon->txt = r;
|
||||
r->class = C_CHAOS;
|
||||
r->txt = opt_malloc(len+1);
|
||||
r->len = len+1;
|
||||
*(r->txt) = len;
|
||||
memcpy((r->txt)+1, txt, len);
|
||||
}
|
||||
|
||||
static void do_usage(void)
|
||||
@@ -674,6 +706,13 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
char *scope_id;
|
||||
#endif
|
||||
|
||||
if (!arg || strlen(arg) == 0)
|
||||
{
|
||||
*flags |= SERV_NO_ADDR;
|
||||
*interface = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
||||
(portno = split_chr(source, '#')) &&
|
||||
!atoi_check16(portno, &source_port))
|
||||
@@ -752,6 +791,54 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct server *add_rev4(struct in_addr addr, int msize)
|
||||
{
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
in_addr_t a = ntohl(addr.s_addr) >> 8;
|
||||
char *p;
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
|
||||
|
||||
if (msize == 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (msize != 8)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
return serv;
|
||||
|
||||
}
|
||||
|
||||
static struct server *add_rev6(struct in6_addr *addr, int msize)
|
||||
{
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
|
||||
for (i = msize-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)addr)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
return serv;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
static int is_tag_prefix(char *arg)
|
||||
@@ -1315,7 +1402,7 @@ void reset_option_bool(unsigned int opt)
|
||||
daemon->options2 &= ~(1u << (opt - 32));
|
||||
}
|
||||
|
||||
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line)
|
||||
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
|
||||
{
|
||||
int i;
|
||||
char *comma;
|
||||
@@ -1518,6 +1605,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
daemon->resolv_files = list;
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_SERVERS_FILE:
|
||||
daemon->servers_file = opt_string_alloc(arg);
|
||||
break;
|
||||
|
||||
case 'm': /* --mx-host */
|
||||
{
|
||||
@@ -1581,7 +1672,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'H': /* --addn-hosts */
|
||||
{
|
||||
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
|
||||
static int hosts_index = 1;
|
||||
static unsigned int hosts_index = SRC_AH;
|
||||
new->fname = opt_string_alloc(arg);
|
||||
new->index = hosts_index++;
|
||||
new->flags = 0;
|
||||
@@ -1814,34 +1905,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
in_addr_t a = ntohl(new->start.s_addr) >> 8;
|
||||
char *p;
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
|
||||
|
||||
if (msize == 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (msize != 8)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
struct server *serv = add_rev4(new->start, msize);
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1877,29 +1945,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
char *p;
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(73); /* strlen("32*<n.>ip6.arpa")+1 */
|
||||
|
||||
for (i = msize-1; i >= 0; i -= 4)
|
||||
{
|
||||
int dig = ((unsigned char *)&new->start6)[i>>3];
|
||||
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
|
||||
}
|
||||
p += sprintf(p, "ip6.arpa");
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
struct server *serv = add_rev6(&new->start6, msize);
|
||||
serv->flags |= SERV_NO_ADDR;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2126,6 +2173,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
memset(newlist, 0, sizeof(struct server));
|
||||
}
|
||||
|
||||
if (servers_only && option == 'S')
|
||||
newlist->flags |= SERV_FROM_FILE;
|
||||
|
||||
if (option == 'A')
|
||||
{
|
||||
newlist->flags |= SERV_LITERAL_ADDRESS;
|
||||
@@ -2170,6 +2220,40 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_REV_SERV: /* --rev-server */
|
||||
{
|
||||
char *string;
|
||||
int size;
|
||||
struct server *serv;
|
||||
struct in_addr addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr addr6;
|
||||
#endif
|
||||
|
||||
unhide_metas(arg);
|
||||
if (!arg || !(comma=split(arg)) || !(string = split_chr(arg, '/')) || !atoi_check(string, &size))
|
||||
ret_err(gen_err);
|
||||
|
||||
if (inet_pton(AF_INET, arg, &addr4))
|
||||
serv = add_rev4(addr4, size);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &addr6))
|
||||
serv = add_rev6(&addr6, size);
|
||||
#endif
|
||||
else
|
||||
ret_err(gen_err);
|
||||
|
||||
string = parse_server(comma, &serv->addr, &serv->source_addr, serv->interface, &serv->flags);
|
||||
|
||||
if (string)
|
||||
ret_err(string);
|
||||
|
||||
if (servers_only)
|
||||
serv->flags |= SERV_FROM_FILE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LOPT_IPSET: /* --ipset */
|
||||
#ifndef HAVE_IPSET
|
||||
ret_err(_("recompile with HAVE_IPSET defined to enable ipset directives"));
|
||||
@@ -3533,7 +3617,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->txt;
|
||||
daemon->txt = new;
|
||||
new->class = C_IN;
|
||||
|
||||
new->stat = 0;
|
||||
|
||||
if (!(new->name = canonicalise_opt(arg)))
|
||||
ret_err(_("bad TXT record"));
|
||||
|
||||
@@ -3675,10 +3760,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
case LOPT_DNSKEY:
|
||||
case LOPT_TRUST_ANCHOR:
|
||||
{
|
||||
struct dnskey *new = opt_malloc(sizeof(struct dnskey));
|
||||
char *key64, *algo = NULL;
|
||||
struct ds_config *new = opt_malloc(sizeof(struct ds_config));
|
||||
char *cp, *cp1, *keyhex, *digest, *algo = NULL;
|
||||
int len;
|
||||
|
||||
new->class = C_IN;
|
||||
|
||||
@@ -3700,20 +3786,30 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
|
||||
if (!comma || !algo || !(key64 = split(algo)) ||
|
||||
!atoi_check16(comma, &new->flags) || !atoi_check16(algo, &new->algo) ||
|
||||
if (!comma || !algo || !(digest = split(algo)) || !(keyhex = split(digest)) ||
|
||||
!atoi_check16(comma, &new->keytag) ||
|
||||
!atoi_check8(algo, &new->algo) ||
|
||||
!atoi_check8(digest, &new->digest_type) ||
|
||||
!(new->name = canonicalise_opt(arg)))
|
||||
ret_err(_("bad DNSKEY"));
|
||||
ret_err(_("bad trust anchor"));
|
||||
|
||||
/* Upper bound on length */
|
||||
new->key = opt_malloc((3*strlen(key64)/4)+1);
|
||||
unhide_metas(key64);
|
||||
if ((new->keylen = parse_base64(key64, new->key)) == -1)
|
||||
ret_err(_("bad base64 in DNSKEY"));
|
||||
len = (2*strlen(keyhex))+1;
|
||||
new->digest = opt_malloc(len);
|
||||
unhide_metas(keyhex);
|
||||
/* 4034: "Whitespace is allowed within digits" */
|
||||
for (cp = keyhex; *cp; )
|
||||
if (isspace(*cp))
|
||||
for (cp1 = cp; *cp1; cp1++)
|
||||
*cp1 = *(cp1+1);
|
||||
else
|
||||
cp++;
|
||||
if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
|
||||
ret_err(_("bad HEX in trust anchor"));
|
||||
|
||||
new->next = daemon->ds;
|
||||
daemon->ds = new;
|
||||
|
||||
new->next = daemon->dnskeys;
|
||||
daemon->dnskeys = new;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@@ -3733,12 +3829,13 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
|
||||
while (fgets(buff, MAXDNAME, f))
|
||||
{
|
||||
int white, i, option = hard_opt;
|
||||
int white, i;
|
||||
volatile int option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt;
|
||||
char *errmess, *p, *arg = NULL, *start;
|
||||
size_t len;
|
||||
|
||||
/* Memory allocation failure longjmps here if mem_recover == 1 */
|
||||
if (option != 0)
|
||||
if (option != 0 || hard_opt == LOPT_REV_SERV)
|
||||
{
|
||||
if (setjmp(mem_jmp))
|
||||
continue;
|
||||
@@ -3839,13 +3936,15 @@ static void read_file(char *file, FILE *f, int hard_opt)
|
||||
errmess = _("extraneous parameter");
|
||||
else if (opts[i].has_arg == 1 && !arg)
|
||||
errmess = _("missing parameter");
|
||||
else if (hard_opt == LOPT_REV_SERV && option != 'S' && option != LOPT_REV_SERV)
|
||||
errmess = _("illegal option");
|
||||
}
|
||||
|
||||
oops:
|
||||
if (errmess)
|
||||
strcpy(daemon->namebuff, errmess);
|
||||
|
||||
if (errmess || !one_opt(option, arg, buff, _("error"), 0))
|
||||
if (errmess || !one_opt(option, arg, buff, _("error"), 0, hard_opt == LOPT_REV_SERV))
|
||||
{
|
||||
sprintf(daemon->namebuff + strlen(daemon->namebuff), _(" at line %d of %s"), lineno, file);
|
||||
if (hard_opt != 0)
|
||||
@@ -3930,10 +4029,11 @@ static int one_file(char *file, int hard_opt)
|
||||
/* expand any name which is a directory */
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct hostsfile *ah;
|
||||
|
||||
for (i = 0, ah = list; ah; ah = ah->next)
|
||||
/* find largest used index */
|
||||
for (i = SRC_AH, ah = list; ah; ah = ah->next)
|
||||
{
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
@@ -4027,6 +4127,22 @@ struct hostsfile *expand_filelist(struct hostsfile *list)
|
||||
return list;
|
||||
}
|
||||
|
||||
void read_servers_file(void)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (!(f = fopen(daemon->servers_file, "r")))
|
||||
{
|
||||
my_syslog(LOG_ERR, _("cannot read %s: %s"), daemon->servers_file, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
mark_servers(SERV_FROM_FILE);
|
||||
cleanup_servers();
|
||||
|
||||
read_file(daemon->servers_file, f, LOPT_REV_SERV);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
void reread_dhcp(void)
|
||||
@@ -4151,9 +4267,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
daemon->soa_refresh = SOA_REFRESH;
|
||||
daemon->soa_retry = SOA_RETRY;
|
||||
daemon->soa_expiry = SOA_EXPIRY;
|
||||
add_txt("version.bind", "dnsmasq-" VERSION );
|
||||
add_txt("authors.bind", "Simon Kelley");
|
||||
add_txt("copyright.bind", COPYRIGHT);
|
||||
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
|
||||
add_txt("authors.bind", "Simon Kelley", 0);
|
||||
add_txt("copyright.bind", COPYRIGHT, 0);
|
||||
add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
|
||||
add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
|
||||
add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
|
||||
add_txt("misses.bind", NULL, TXT_STAT_MISSES);
|
||||
add_txt("hits.bind", NULL, TXT_STAT_HITS);
|
||||
#ifdef HAVE_AUTH
|
||||
add_txt("auth.bind", NULL, TXT_STAT_AUTH);
|
||||
#endif
|
||||
add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -4220,9 +4345,9 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1))
|
||||
if (!one_opt(option, arg, daemon->namebuff, _("try --help"), 1, 0))
|
||||
#else
|
||||
if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1))
|
||||
if (!one_opt(option, arg, daemon->namebuff, _("try -w"), 1, 0))
|
||||
#endif
|
||||
die(_("bad command line options: %s"), daemon->namebuff, EC_BADCONF);
|
||||
}
|
||||
@@ -4354,6 +4479,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
||||
else if (option_bool(OPT_DHCP_FQDN))
|
||||
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
|
||||
|
||||
/* If there's access-control config, then ignore --local-service, it's intended
|
||||
as a system default to keep otherwise unconfigured installations safe. */
|
||||
if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
|
||||
reset_option_bool(OPT_LOCAL_SERVICE);
|
||||
|
||||
if (testmode)
|
||||
{
|
||||
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
|
||||
|
||||
238
src/rfc1035.c
238
src/rfc1035.c
@@ -337,7 +337,7 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
|
||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
|
||||
{
|
||||
int i, rdlen;
|
||||
|
||||
@@ -601,11 +601,11 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
||||
|
||||
if (family == parm->l3->sa.sa_family)
|
||||
{
|
||||
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
if (family == AF_INET && memcmp(&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
match = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
if (family == AF_INET6 && memcmp(&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
match = 1;
|
||||
#endif
|
||||
}
|
||||
@@ -917,8 +917,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name, doctored);
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (*doctored)
|
||||
secure = 0;
|
||||
if (*doctored && secure)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -927,7 +927,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
int found = 0, cname_count = 5;
|
||||
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;
|
||||
@@ -988,9 +988,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
|
||||
if (aqtype == T_CNAME)
|
||||
{
|
||||
if (!cname_count--)
|
||||
return 0; /* looped CNAMES */
|
||||
secflag = 0; /* no longer DNSSEC */
|
||||
if (!cname_count-- || secure)
|
||||
return 0; /* looped CNAMES, or DNSSEC, which we can't cache. */
|
||||
goto cname_loop;
|
||||
}
|
||||
|
||||
@@ -1066,6 +1065,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
if (newc)
|
||||
{
|
||||
newc->addr.cname.target.cache = NULL;
|
||||
/* anything other than zero, to avoid being mistaken for CNAME to interface-name */
|
||||
newc->addr.cname.uid = 1;
|
||||
if (cpp)
|
||||
{
|
||||
cpp->addr.cname.target.cache = newc;
|
||||
@@ -1101,7 +1102,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
{
|
||||
ipsets_cur = ipsets;
|
||||
while (*ipsets_cur)
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
{
|
||||
log_query((flags & (F_IPV4 | F_IPV6)) | F_IPSET, name, &addr, *ipsets_cur);
|
||||
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1242,7 +1246,7 @@ int check_for_local_domain(char *name, time_t now)
|
||||
struct ptr_record *ptr;
|
||||
struct naptr *naptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
|
||||
return 1;
|
||||
|
||||
@@ -1452,11 +1456,12 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
struct in_addr local_addr, struct in_addr local_netmask,
|
||||
time_t now, int *ad_reqd, int *do_bit)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
unsigned char *p, *ansp, *pheader;
|
||||
int qtype, qclass;
|
||||
unsigned int qtype, qclass;
|
||||
struct all_addr addr;
|
||||
int nameoffset;
|
||||
unsigned short flag;
|
||||
@@ -1468,9 +1473,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct mx_srv_record *rec;
|
||||
size_t len;
|
||||
|
||||
/* Don't return AD set even for local data if checking disabled. */
|
||||
/* Don't return AD set if checking disabled. */
|
||||
if (header->hb4 & HB4_CD)
|
||||
sec_data = 0;
|
||||
|
||||
/* RFC 6840 5.7 */
|
||||
*ad_reqd = header->hb4 & HB4_AD;
|
||||
*do_bit = 0;
|
||||
|
||||
/* If there is an RFC2671 pseudoheader then it will be overwritten by
|
||||
partial replies, so we have to do a dry run to see if we can answer
|
||||
@@ -1489,7 +1498,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
pheader += 2; /* ext_rcode */
|
||||
GETSHORT(flags, pheader);
|
||||
|
||||
sec_reqd = flags & 0x8000; /* do bit */
|
||||
if ((sec_reqd = flags & 0x8000))
|
||||
*do_bit = 1;/* do bit */
|
||||
*ad_reqd = 1;
|
||||
|
||||
/* If our client is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get an overlarge
|
||||
@@ -1539,10 +1550,20 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned long ttl = daemon->local_ttl;
|
||||
int ok = 1;
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
/* Dynamically generate stat record */
|
||||
if (t->stat != 0)
|
||||
{
|
||||
ttl = 0;
|
||||
if (!cache_make_stat(t))
|
||||
ok = 0;
|
||||
}
|
||||
|
||||
if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
@@ -1551,58 +1572,60 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS || qtype == T_RRSIG))
|
||||
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DNSKEY || qtype == T_DS))
|
||||
{
|
||||
int gotone = 0, have_rrsig = 0;
|
||||
int gotone = 0;
|
||||
struct blockdata *keydata;
|
||||
|
||||
/* Do we have RRSIG? Can't do DS or DNSKEY otherwise. */
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
if (crecp->uid == qclass && (qtype == T_RRSIG || crecp->addr.sig.type_covered == qtype))
|
||||
{
|
||||
have_rrsig = 1;
|
||||
break;
|
||||
}
|
||||
if (sec_reqd)
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype)
|
||||
break;
|
||||
}
|
||||
|
||||
if (qtype == T_RRSIG && have_rrsig)
|
||||
if (!sec_reqd || crecp)
|
||||
{
|
||||
ans = gotone = 1;
|
||||
auth = 0;
|
||||
}
|
||||
else if (qtype == T_DS && have_rrsig)
|
||||
{
|
||||
auth = 0;
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
|
||||
if (crecp->uid == qclass)
|
||||
{
|
||||
ans = gotone = 1;
|
||||
if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.keytag = crecp->addr.ds.keytag;
|
||||
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_DS, qclass, "sbbt",
|
||||
crecp->addr.ds.keytag, crecp->addr.ds.algo, crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (qtype == T_DNSKEY)
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
|
||||
if (crecp->uid == qclass)
|
||||
{
|
||||
if ((crecp->flags & F_CONFIG) || have_rrsig) /* Return configured keys without an RRISG */
|
||||
if (qtype == T_DS)
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS)))
|
||||
if (crecp->uid == qclass)
|
||||
{
|
||||
if (!(crecp->flags & F_CONFIG))
|
||||
auth = 0, gotone = 1;
|
||||
ans = 1;
|
||||
gotone = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
if (crecp->flags & F_NEG)
|
||||
{
|
||||
if (crecp->flags & F_NXDOMAIN)
|
||||
nxdomain = 1;
|
||||
log_query(F_UPSTREAM, name, NULL, "secure no DS");
|
||||
}
|
||||
else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
|
||||
{
|
||||
struct all_addr a;
|
||||
a.addr.keytag = crecp->addr.ds.keytag;
|
||||
log_query(F_KEYTAG | (crecp->flags & F_CONFIG), name, &a, "DS keytag %u");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_DS, qclass, "sbbt",
|
||||
crecp->addr.ds.keytag, crecp->addr.ds.algo,
|
||||
crecp->addr.ds.digest, crecp->addr.ds.keylen, keydata))
|
||||
anscount++;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* DNSKEY */
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY)))
|
||||
if (crecp->uid == qclass)
|
||||
{
|
||||
gotone = 1;
|
||||
if (!dryrun && (keydata = blockdata_retrieve(crecp->addr.key.keydata, crecp->addr.key.keylen, NULL)))
|
||||
{
|
||||
struct all_addr a;
|
||||
@@ -1615,30 +1638,27 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now do RRSIGs */
|
||||
if (gotone)
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
if (crecp->uid == qclass && (qtype == T_RRSIG || (sec_reqd && crecp->addr.sig.type_covered == qtype)) &&
|
||||
!dryrun &&
|
||||
(keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
|
||||
{
|
||||
if (qtype == T_RRSIG)
|
||||
ans = 1;
|
||||
auth = 0;
|
||||
if (!dryrun && sec_reqd)
|
||||
{
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DNSKEY | F_DS)))
|
||||
if (crecp->uid == qclass && crecp->addr.sig.type_covered == qtype &&
|
||||
(keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
|
||||
{
|
||||
char types[20];
|
||||
querystr("rrsig", types, crecp->addr.sig.type_covered);
|
||||
log_query(F_RRNAME, name, NULL, types);
|
||||
}
|
||||
if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crec_ttl(crecp, now), &nameoffset,
|
||||
T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata))
|
||||
anscount++;
|
||||
}
|
||||
T_RRSIG, qclass, "t", crecp->addr.sig.keylen, keydata);
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1742,24 +1762,25 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
else if (crecp->flags & F_DNSSECOK)
|
||||
{
|
||||
int gotsig = 0;
|
||||
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
|
||||
struct crec *rr_crec = NULL;
|
||||
|
||||
while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
|
||||
{
|
||||
if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
|
||||
if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
|
||||
{
|
||||
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
|
||||
char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
|
||||
gotsig = 1;
|
||||
|
||||
if (!dryrun &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crecp->ttd - now, &nameoffset,
|
||||
rr_crec->ttd - now, &nameoffset,
|
||||
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
/* Need to re-run original cache search */
|
||||
crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
|
||||
|
||||
if (!gotsig)
|
||||
crecp = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1923,7 +1944,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
|
||||
{
|
||||
int localise = 0;
|
||||
|
||||
@@ -1954,7 +1975,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
else if (crecp->flags & F_DNSSECOK)
|
||||
{
|
||||
/* We're returning validated data, need to return the RRSIG too. */
|
||||
|
||||
struct crec *rr_crec = NULL;
|
||||
int sigtype = type;
|
||||
/* The signature may have expired even though the data is still in cache,
|
||||
forward instead of answering from cache if so. */
|
||||
@@ -1963,23 +1984,23 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (crecp->flags & F_CNAME)
|
||||
sigtype = T_CNAME;
|
||||
|
||||
crecp = NULL;
|
||||
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
|
||||
while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
|
||||
{
|
||||
if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
|
||||
if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
|
||||
{
|
||||
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
|
||||
char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
|
||||
gotsig = 1;
|
||||
|
||||
if (!dryrun &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
crecp->ttd - now, &nameoffset,
|
||||
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
|
||||
rr_crec->ttd - now, &nameoffset,
|
||||
T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
/* Need to re-run original cache search */
|
||||
crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
|
||||
|
||||
if (!gotsig)
|
||||
crecp = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -2010,7 +2031,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
|
||||
strcpy(name, cname_target);
|
||||
/* check if target interface_name */
|
||||
if (crecp->addr.cname.uid == -1)
|
||||
if (crecp->addr.cname.uid == SRC_INTERFACE)
|
||||
goto intname_restart;
|
||||
else
|
||||
goto cname_restart;
|
||||
@@ -2072,7 +2093,7 @@ 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))))
|
||||
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
|
||||
{
|
||||
if (!(crecp->flags & F_DNSSECOK))
|
||||
sec_data = 0;
|
||||
@@ -2111,7 +2132,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -2263,17 +2284,16 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(addncount);
|
||||
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
len = ansp - (unsigned char *)header;
|
||||
|
||||
if (have_pseudoheader)
|
||||
{
|
||||
len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
|
||||
if (sec_reqd && sec_data)
|
||||
header->hb4 |= HB4_AD;
|
||||
|
||||
}
|
||||
len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd);
|
||||
|
||||
if (*ad_reqd && sec_data)
|
||||
header->hb4 |= HB4_AD;
|
||||
else
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -962,6 +962,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
case DHCPDISCOVER:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
{
|
||||
if (option_bool(OPT_QUIET_DHCP))
|
||||
return 0;
|
||||
message = _("ignored");
|
||||
opt = NULL;
|
||||
}
|
||||
|
||||
60
src/util.c
60
src/util.c
@@ -482,66 +482,6 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
static int charval(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
return c - 'A';
|
||||
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 26;
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0' + 52;
|
||||
|
||||
if (c == '+')
|
||||
return 62;
|
||||
|
||||
if (c == '/')
|
||||
return 63;
|
||||
|
||||
if (c == '=')
|
||||
return -1;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
int parse_base64(char *in, char *out)
|
||||
{
|
||||
char *p = out;
|
||||
int i, val[4];
|
||||
|
||||
while (*in)
|
||||
{
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
while (*in == ' ')
|
||||
in++;
|
||||
if (*in == 0)
|
||||
return -1;
|
||||
if ((val[i] = charval(*in++)) == -2)
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*in == ' ')
|
||||
in++;
|
||||
|
||||
if (val[1] == -1)
|
||||
return -1; /* too much padding */
|
||||
|
||||
*p++ = (val[0] << 2) | (val[1] >> 4);
|
||||
|
||||
if (val[2] != -1)
|
||||
*p++ = (val[1] << 4) | ( val[2] >> 2);
|
||||
|
||||
if (val[3] != -1)
|
||||
*p++ = (val[2] << 6) | val[3];
|
||||
}
|
||||
|
||||
return p - out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return 0 for no match, or (no matched octets) + 1 */
|
||||
int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# The root DNSSEC trust anchors, valid as at 30/01/2014
|
||||
# The root DNSSEC trust anchor, valid as at 30/01/2014
|
||||
|
||||
# Note that this is a DS record (ie a hash of the root Zone Signing Key)
|
||||
# If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml
|
||||
|
||||
trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5
|
||||
|
||||
|
||||
dnskey=.,257,8,AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq QxA+Uk1ihz0=
|
||||
dnskey=.,256,8,AwEAAb8sU6pbYMWRbkRnEuEZw9NSir707TkOcF+UL1XiK4NDJOvXRyX1 95Am5dQ7bRnnuySZ3daf37vvjUUhuIWUAQ4stht8nJfYxVQXDYjSpGH5 I6Hf/0CZEoNP6cNvrQ7AFmKkmv00xWExKQjbvnRPI4bqpMwtHVzn6Wyb BZ6kuqED
|
||||
dnskey=.,256,8,AwEAAYRU41/8smgAvuSojEP4jaj5Yll7WPaUKpYvnz2pnX2VIvRn4jsy Jns80bloenG6X9ebJVy2CFtZQLKHP8DcKmIFotdgs2HolyocY1am/+33 4RtzusM2ojkhjn1FRGtuSE9s2TSz1ISv0yVnFyu+EP/ZkiWnDfWeVrJI SEWBEr4V
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user