Compare commits

...
28 Commits
Author SHA1 Message Date
Simon Kelley 88a482fdb9 Rename hash_questions.c, for consistency. 2021-06-08 22:16:05 +01:00
Simon Kelley 12a9aa7c62 Major rewrite of the DNS server and domain handling code.
This should be largely transparent, but it drastically
improves performance and reduces memory foot-print when
configuring large numbers domains of the form
local=/adserver.com/
or
local=/adserver.com/#

Lookup times now grow as log-to-base-2 of the number of domains,
rather than greater than linearly, as before.
The change makes multiple addresses associated with a domain work
address=/example.com/1.2.3.4
address=/example.com/5.6.7.8
It also handles multiple upstream servers for a domain better; using
the same try/retry alogrithms as non domain-specific servers. This
also applies to DNSSEC-generated queries.

Finally, some of the oldest and gnarliest code in dnsmasq has had
a significant clean-up. It's far from perfect, but it _is_ better.
2021-06-08 22:10:55 +01:00
Simon Kelley 50ccf9c585 Fix manpage typo.
Thanks to Bart Wolther for the report.
2021-04-30 00:01:48 +01:00
Simon Kelley d100eb05a3 <nettle/version.h> -> <nettle/bignum.h> for backward compatibility. 2021-04-14 21:15:34 +01:00
Petr Menšík 10d8b5f001 Reduce code duplication, reuse existing functions
dhcp_config_free and dhcp_opt_free already implement the same algorithm.
Reuse them. Adds forgotten hostname cleanup to config free.
2021-04-14 21:08:31 +01:00
Simon Kelley ffd3ceb856 Remove old patch droppings in manpage. 2021-04-14 01:00:48 +01:00
Brian Hartvigsen d942aa9321 Support Cisco Umbrella/OpenDNS Device ID & Remote IP
This is based on the information at
https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic and
https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic2 .
Using --umbrella by itself will enable Remote IP reporting. This can not
be used for any policy filtering in Cisco Umbrella/OpenDNS. Additional
information can be supplied using specific option specifications,
multiple can be separated by a comma:

--umbrella=orgid:1234,deviceid=0123456789abcdef

Specifies that you want to report organization 1234 using device
0123456789abcdef. For Cisco Umbrella Enterprise, see "Register (Create)
a device" (https://docs.umbrella.com/umbrella-api/docs/create-a-device)
for how to get a Device ID and "Organization ID endpoint"
(https://docs.umbrella.com/umbrella-api/docs/organization-endpoint) to
get organizations ID. For OpenDNS Home Users, there is no organization,
see Registration API endpoint
(https://docs.umbrella.com/umbrella-api/docs/registration-api-endpoint2)
for how to get a Device ID. Asset ID should be ignored unless
specifically instructed to use by support.

Signed-off-by: Brian Hartvigsen <brian.andrew@brianandjenny.com>
2021-04-14 00:16:14 +01:00
Simon Kelley 6469fefe89 Fix build failure with HAVE_CRYPTOHASH. 2021-04-13 23:33:46 +01:00
Simon Kelley b082842ee7 Add NO_LOOP to config.h docs. 2021-04-12 17:43:59 +01:00
Geert Stappers 3573ca0eec Chomp file ends
Removed empty lines from end of src/*.[ch] files.
If the new last line became '#endif'
was the condition of the '#if' added.
2021-04-09 17:27:36 +01:00
Simon Kelley ad90eb075d Fix bug in TCP process handling.
Fix bug which caused dnsmasq to lose track of processes forked
to handle TCP DNS connections under heavy load. The code
checked that at least one free process table slot was
available before listening on TCP sockets, but didn't take
into account that more than one TCP connection could
arrive, so that check was not sufficient to ensure that
there would be slots for all new processes. It compounded
this error by silently failing to store the process when
it did run out of slots. Even when this bug is triggered,
all the right things happen, and answers are still returned.
Only under very exceptional circumstances, does the bug
manifest itself: see
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q2/014976.html

Thanks to Tijs Van Buggenhout for finding the conditions under
which the bug manifests itself, and then working out
exactly what was going on.
2021-04-09 16:08:05 +01:00
Simon Kelley d55e2d086d Handle DHCPREBIND requests in the DHCPv6 server.
Patch by srk, based on submitted patch from liaichun@huawei.com
2021-04-09 15:19:28 +01:00
Simon Kelley fe9c966a49 Fix debian/changelog format problem. 2021-04-08 22:41:46 +01:00
Simon Kelley 9f20afb1a8 Manpage typo. 2021-04-07 21:39:39 +01:00
Simon Kelley f61afcfc70 Tidy error logging in 961daf8f92 2021-04-07 20:54:36 +01:00
Simon Kelley 961daf8f92 Handle resource exhaustion of struct frec_src same as struct frec.
Ie, by returning REFUSED response and (rate-limited) logging.
2021-04-06 23:52:09 +01:00
Simon Kelley 64a16cb376 Combine queries for the same DNS name if close in time.
If two queries arrive a second or so apart, they cannot be a try and
a retry from the same client (retries are at least three seconds apart.)

It's therefore safe not to forward the second query, but answer them
both when the reply arrives for the first.
2021-04-06 23:29:46 +01:00
Simon Kelley ea6b0b2665 Subtly change behaviour on repeated DNS query.
This changes the behaviour introduced in
141a26f979

We re-introduce the distinction between a query
which is retried from the same source, and one which is
repeated from different sources.

In the later case, we still forward the query, to avoid
problems when the reply to the first query is lost
(see f8cf456920) but we suppress the behaviour
that's used on a retry, when the query is sent to
all available servers in parallel.

Retry -> all servers.
Repeat -> next server.

This avoids a significant increase in upstream traffic on
busy instances which see lots of queries for common names.

It does mean the clients which repeat queries from new source ports,
rather than retrying them from the same source port, will see
different behaviour, but it in fact restores the pre-2.83 behaviour,
so it's not expected to be a practical problem.
2021-04-05 21:01:09 +01:00
Matthias Andree 89df73ac05 CHANGELOG: fix typo recieved->received 2021-04-03 23:01:46 +01:00
Simon Kelley 7d3f3c9983 Fold NMU into Debian packaging. 2021-04-03 22:43:14 +01:00
Simon Kelley 1bdbea2461 Fold NMU into Debian packaging. 2021-03-30 22:42:29 +01:00
Simon Kelley dfb1f7ccf1 TFTP tweak.
Check sender of all received packets, as specified in RFC 1350 para 4.

My understanding of the example in the RFC is that it in fact only
applies to server-to-client packets, and packet loss or duplication
cannot result in a client sending from more than one port to a server.
This check is not, therefore, strictly needed on the server side.
It's still useful, and adds a little security against packet
spoofing. (though if you're running TFTP on a public network with
bad actors, nothing can really save you.)
2021-03-30 21:32:07 +01:00
Matthias Andree b5d1b20727 Fix spacing in translatable strings.
Signed-off-by: Matthias Andree <matthias.andree@gmx.de>
2021-03-28 00:58:54 +00:00
Matthias Andree 2a407a76be CHANGELOG: spell-check and correct first few entries
Signed-off-by: Matthias Andree <matthias.andree@gmx.de>
2021-03-28 00:56:13 +00:00
Matthias Andree d1640a6338 po/de.po: Rework German translation...
for consistency, wording/language, typoes.

Signed-off-by: Matthias Andree <matthias.andree@gmx.de>
2021-03-28 00:55:44 +00:00
Simon Kelley 26b5c40d95 Replace ad-hoc libnettle version detecion with MIN_VERSION macro. 2021-03-27 23:29:36 +00:00
Petr Menšík 0b3ecf7432 Enable DNSSEC compilation on nettle 2.7.1
RHEL/CentOS 7 does not compile with DNSSEC enabled, because older
version is not supported. Add few defines to compile also on older
nettle versions.

Adds also major version 4 check, taking into account higher major
version.
2021-03-27 23:26:48 +00:00
Petr Menšík 8f9bd61505 Correct missing SERV_DO_DNSSEC flag, add new spot
One change to server_test_type forgot to set SERV_DO_DNSSEC. One new
place still can be reused.

Fixes commit e10a9239e1, thanks to
Xingcong Li for spotting it.
2021-03-27 23:16:09 +00:00
42 changed files with 2415 additions and 1926 deletions

No files matched your search

+51 -7
View File
@@ -1,3 +1,44 @@
version 2.86
Handle DHCPREBIND requests in the DHCPv6 server code.
Thanks to Aichun Li for spotting this ommision, and the initial
patch.
Fix bug which caused dnsmasq to lose track of processes forked
to handle TCP DNS connections under heavy load. The code
checked that at least one free process table slot was
available before listening on TCP sockets, but didn't take
into account that more than one TCP connection could
arrive, so that check was not sufficient to ensure that
there would be slots for all new processes. It compounded
this error by silently failing to store the process when
it did run out of slots. Even when this bug is triggered,
all the right things happen, and answers are still returned.
Only under very exceptional circumstances, does the bug
manifest itself: see
https://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2021q2/014976.html
Thanks to Tijs Van Buggenhout for finding the conditions under
which the bug manifests itself, and then working out
exactly what was going on.
Major rewrite of the DNS server and domain handling code.
This should be largely transparent, but it drastically
improves performance and reduces memory foot-print when
configuring large numbers domains of the form
local=/adserver.com/
or
local=/adserver.com/#
Lookup times now grow as log-to-base-2 of the number of domains,
rather than greater than linearly, as before.
The change makes multiple addresses associated with a domain work
address=/example.com/1.2.3.4
address=/example.com/5.6.7.8
It also handles multiple upstream servers for a domain better; using
the same try/retry alogrithms as non domain-specific servers. This
also applies to DNSSEC-generated queries.
Finally, some of the oldest and gnarliest code in dnsmasq has had
a significant clean-up. It's far from perfect, but it _is_ better.
version 2.85
Fix problem with DNS retries in 2.83/2.84.
The new logic in 2.83/2.84 which merges distinct requests
@@ -15,10 +56,10 @@ version 2.85
to 2.84 announcing itself as 2.84rc2.
Avoid treating a --dhcp-host which has an IPv6 address
as eligable for use with DHCPv4 on the grounds that it has
as eligible for use with DHCPv4 on the grounds that it has
no address, and vice-versa. Thanks to Viktor Papp for
spotting the problem. (This bug was fixed was back in 2.67, and
then regessed in 2.81).
then regressed in 2.81).
Add --dynamic-host option: A and AAAA records which take their
network part from the network of a local interface. Useful
@@ -31,7 +72,7 @@ version 2.85
addresses/interfaces in use.
CVE-2021-3448 applies. Thanks to Petr Menšík for spotting this.
It's possible to specify the source address or interface to be
used when contacting upstream nameservers: server=8.8.8.8@1.2.3.4
used when contacting upstream name servers: server=8.8.8.8@1.2.3.4
or server=8.8.8.8@1.2.3.4#66 or server=8.8.8.8@eth0, and all of
these have, until now, used a single socket, bound to a fixed
port. This was originally done to allow an error (non-existent
@@ -47,7 +88,7 @@ version 2.85
understanding of the security implications.
Note that this change changes non-existing interface, or non-local
source address errors from fatal to run-time. The error will be
logged and communiction with the server not possible.
logged and communication with the server not possible.
Change the method of allocation of random source ports for DNS.
Previously, without min-port or max-port configured, dnsmasq would
@@ -57,7 +98,7 @@ version 2.85
32768 to 60999 on Linux systems. This change eliminates the
possibility that dnsmasq may be using a registered port > 1024
when a long-running daemon starts up and wishes to claim it.
This change does likely slighly reduce the number of random ports
This change does likely slightly reduce the number of random ports
and therefore the protection from reply spoofing. The older
behaviour can be restored using the min-port and max-port config
switches should that be a concern.
@@ -65,6 +106,9 @@ version 2.85
Scale the size of the DNS random-port pool based on the
value of the --dns-forward-max configuration.
Tweak TFTP code to check sender of all received packets, as
specified in RFC 1350 para 4.
version 2.84
Fix a problem, introduced in 2.83, which could see DNS replies
@@ -98,13 +142,13 @@ version 2.83
Handle multiple identical near simultaneous DNS queries better.
Previously, such queries would all be forwarded
independently. This is, in theory, inefficent but in practise
independently. This is, in theory, inefficient but in practise
not a problem, _except_ that is means that an answer for any
of the forwarded queries will be accepted and cached.
An attacker can send a query multiple times, and for each repeat,
another {port, ID} becomes capable of accepting the answer he is
sending in the blind, to random IDs and ports. The chance of a
succesful attack is therefore multiplied by the number of repeats
successful attack is therefore multiplied by the number of repeats
of the query. The new behaviour detects repeated queries and
merely stores the clients sending repeats so that when the
first query completes, the answer can be sent to all the
+1 -1
View File
@@ -82,7 +82,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
metrics.o hash_questions.o
metrics.o hash-questions.o domain-match.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
+2 -1
View File
@@ -11,7 +11,8 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
crypto.c dump.c ubus.c metrics.c hash_questions.c
crypto.c dump.c ubus.c metrics.c hash-questions.c \
domain-match.c
LOCAL_MODULE := dnsmasq
+28 -2
View File
@@ -1,8 +1,34 @@
dnsmasq (2.86-1) unstable; urgency=low
* Fix debian/changelog format error. (closes: #986626)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 08 Apr 2021 22:39:00 +0100
dnsmasq (2.85-1) unstable; urgency=low
* New upstream.
* Includes fix to CVE-2021-3448.
* Fix manpage typos. (closes: #986150)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 2 Mar 2021 21:40:23 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 03 Apr 2021 22:17:23 +0100
dnsmasq (2.84-1.2) unstable; urgency=medium
* Non-maintainer upload.
* Bump old-version in dpkg-maintscript-helper dir_to_symlink calls to also
clean up after upgrades to an earlier version in testing.
-- Andreas Beckmann <anbe@debian.org> Thu, 01 Apr 2021 16:01:51 +0200
dnsmasq (2.84-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Fix symlink to directory conversion for /usr/share/doc/dnsmasq.
This is achieved by directly calling dpkg-maintscript-helper in the preinst,
postinst, and postrm scripts, since the package does not use debhelper.
(Closes: #985282)
-- Sébastien Villemot <sebastien@debian.org> Sun, 28 Mar 2021 10:55:07 +0200
dnsmasq (2.84-1) unstable; urgency=low
@@ -1055,7 +1081,7 @@ dnsmasq (2.6-2) unstable; urgency=low
* Added note about the --bind-interfaces option to
readme.Debian (closes: #241700)
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 13 Apr 2004 18:37:55 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 13 Apr 2004 18:37:55 +0000
dnsmasq (2.6-1) unstable; urgency=low
+3
View File
@@ -1,6 +1,9 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
# Code copied from dh_systemd_enable ----------------------
# This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
+3
View File
@@ -1,6 +1,9 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null
fi
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
+1 -1
View File
@@ -176,7 +176,7 @@ binary-indep: checkroot
-d debian/trees/daemon/usr/lib/tmpfiles.d \
-d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/preinst debian/prerm debian/trees/daemon/DEBIAN
if ! dpkg-vendor --derives-from Ubuntu; then \
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
+9 -4
View File
@@ -184,7 +184,7 @@ OS: this was the default behaviour in versions prior to 2.43.
.B --min-port=<port>
Do not use ports less than that given as source for outbound DNS
queries. Dnsmasq picks random ports as source for outbound queries:
when this option is given, the ports used will always to larger
when this option is given, the ports used will always be larger
than that specified. Useful for systems behind firewalls. If not specified,
defaults to 1024.
.TP
@@ -510,7 +510,7 @@ To include multiple IP addresses for a single query, use
Note that /etc/hosts and DHCP leases override this for individual
names. A common use of this is to redirect the entire doubleclick.net
domain to some friendly local web server to avoid banner ads. The
domain specification works in the same was as for \fB--server\fP, with
domain specification works in the same way as for \fB--server\fP, with
the additional facility that \fB/#/\fP matches any domain. Thus
\fB--address=/#/1.2.3.4\fP will always return \fB1.2.3.4\fP for any
query not answered from \fB/etc/hosts\fP or DHCP and not sent to an
@@ -711,7 +711,13 @@ will add the /24 and /96 subnets of the requestor for IPv4 and IPv6 requestors,
will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
.TP
.B --umbrella[=deviceid:<deviceid>[,orgid:<orgid>]]
Embeds the requestor's IP address in DNS queries forwarded upstream.
If device id or organization id are specified, the information is
included in the forwarded queries and may be able to be used in
filtering policies and reporting. The order of the deviceid and orgid
attributes is irrelevant, but must be separated by a comma.
.TP
.B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Note: huge cache size impacts performance.
@@ -1517,7 +1523,6 @@ instance
will enable dnsmasq to also provide proxy PXE service to those PXE clients with
.I HW-Client
in as their identifier.
>>>>>>> 907def3... pxe: support pxe clients with custom vendor-class
.TP
.B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The
+311 -314
View File
File diff suppressed because it is too large. Load diff
-2
View File
@@ -230,5 +230,3 @@ int do_arp_script_run(void)
return 0;
}
-3
View File
@@ -867,6 +867,3 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
#endif
-1
View File
@@ -174,4 +174,3 @@ struct blockdata *blockdata_read(int fd, size_t len)
{
return blockdata_alloc_real(fd, NULL, len);
}
-2
View File
@@ -440,5 +440,3 @@ void route_sock(void)
}
#endif /* HAVE_BSD_NETWORK */
+12 -20
View File
@@ -1605,16 +1605,13 @@ int cache_make_stat(struct txt_record *t)
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)))
if (!(serv->flags & SERV_COUNTED))
{
char *new, *lenp;
int port, newlen, bytes_avail, bytes_needed;
unsigned int queries = 0, failed_queries = 0;
for (serv1 = serv; serv1; serv1 = serv1->next)
if (!(serv1->flags &
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
sockaddr_isequal(&serv->addr, &serv1->addr))
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
{
serv1->flags |= SERV_COUNTED;
queries += serv1->queries;
@@ -1689,15 +1686,12 @@ void dump_cache(time_t now)
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)))
if (!(serv->flags & SERV_COUNTED))
{
int port;
unsigned int queries = 0, failed_queries = 0;
for (serv1 = serv; serv1; serv1 = serv1->next)
if (!(serv1->flags &
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
sockaddr_isequal(&serv->addr, &serv1->addr))
if (!(serv1->flags & SERV_COUNTED) && sockaddr_isequal(&serv->addr, &serv1->addr))
{
serv1->flags |= SERV_COUNTED;
queries += serv1->queries;
@@ -1885,14 +1879,14 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
{
unsigned int rcode = addr->log.rcode;
if (rcode == SERVFAIL)
dest = "SERVFAIL";
else if (rcode == REFUSED)
dest = "REFUSED";
else if (rcode == NOTIMP)
dest = "not implemented";
else
sprintf(daemon->addrbuff, "%u", rcode);
if (rcode == SERVFAIL)
dest = "SERVFAIL";
else if (rcode == REFUSED)
dest = "REFUSED";
else if (rcode == NOTIMP)
dest = "not implemented";
else
sprintf(daemon->addrbuff, "%u", rcode);
}
else
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
@@ -1980,5 +1974,3 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
else
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
}
+2 -4
View File
@@ -143,6 +143,7 @@ NO_SCRIPT
NO_LARGEFILE
NO_AUTH
NO_DUMPFILE
NO_LOOP
NO_INOTIFY
these are available to explicitly disable compile time options which would
otherwise be enabled automatically or which are enabled by default
@@ -447,7 +448,4 @@ static char *compile_opts =
#endif
"dumpfile";
#endif
#endif /* defined(HAVE_DHCP) */
+1 -4
View File
@@ -82,7 +82,4 @@ static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, vo
return NFCT_CB_CONTINUE;
}
#endif
#endif /* HAVE_CONNTRACK */
+63 -46
View File
@@ -16,21 +16,34 @@
#include "dnsmasq.h"
#ifdef HAVE_DNSSEC
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
/* Minimal version of nettle */
/* bignum.h includes version.h and works on
earlier releases of nettle which don't have version.h */
#include <nettle/bignum.h>
#if !defined(NETTLE_VERSION_MAJOR)
# define NETTLE_VERSION_MAJOR 2
# define NETTLE_VERSION_MINOR 0
#endif
#define MIN_VERSION(major, minor) ((NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
(NETTLE_VERSION_MAJOR > (major)))
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
#if defined(HAVE_DNSSEC)
#include <nettle/rsa.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#if MIN_VERSION(3, 1)
#include <nettle/eddsa.h>
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
#endif
#if MIN_VERSION(3, 6)
# include <nettle/gostdsa.h>
#endif
#endif
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
#include <nettle/nettle-meta.h>
#include <nettle/bignum.h>
#if MIN_VERSION(3, 1)
/* Implement a "hash-function" to the nettle API, which simply returns
the input data, concatenated into a single, statically maintained, buffer.
@@ -84,7 +97,6 @@ static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
ctx->len += length;
}
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
{
(void)length;
@@ -103,35 +115,7 @@ static struct nettle_hash null_hash = {
(nettle_hash_digest_func *) null_hash_digest
};
/* Find pointer to correct hash function in nettle library */
const struct nettle_hash *hash_find(char *name)
{
if (!name)
return NULL;
/* We provide a "null" hash which returns the input data as digest. */
if (strcmp(null_hash.name, name) == 0)
return &null_hash;
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library
versions. It also #defines nettle_hashes, so use that to tell
if we have the new facilities. */
#ifdef nettle_hashes
return nettle_lookup_hash(name);
#else
{
int i;
for (i = 0; nettle_hashes[i]; i++)
if (strcmp(nettle_hashes[i]->name, name) == 0)
return nettle_hashes[i];
}
return NULL;
#endif
}
#endif /* MIN_VERSION(3, 1) */
/* expand ctx and digest memory allocations if necessary and init hash function */
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
@@ -171,10 +155,6 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
return 1;
}
#endif
#ifdef HAVE_DNSSEC
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
@@ -238,7 +218,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR < 4
#if !MIN_VERSION(3, 4)
#define nettle_get_secp_256r1() (&nettle_secp_256r1)
#define nettle_get_secp_384r1() (&nettle_secp_384r1)
#endif
@@ -301,7 +281,7 @@ static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
}
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
#if MIN_VERSION(3, 6)
static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -342,6 +322,7 @@ static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_l
}
#endif
#if MIN_VERSION(3, 1)
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -368,7 +349,7 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
((struct null_hash_digest *)digest)->buff,
sig);
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
#if MIN_VERSION(3, 6)
case 16:
if (key_len != ED448_KEY_SIZE ||
sig_len != ED448_SIGNATURE_SIZE)
@@ -384,6 +365,7 @@ static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len
return 0;
}
#endif
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
@@ -399,16 +381,18 @@ static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key
case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify;
#if NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR >= 6
#if MIN_VERSION(3, 6)
case 12:
return dnsmasq_gostdsa_verify;
#endif
case 13: case 14:
return dnsmasq_ecdsa_verify;
#if MIN_VERSION(3, 1)
case 15: case 16:
return dnsmasq_eddsa_verify;
#endif
}
return NULL;
@@ -479,4 +463,37 @@ char *nsec3_digest_name(int digest)
}
}
#endif /* defined(HAVE_DNSSEC) */
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
/* Find pointer to correct hash function in nettle library */
const struct nettle_hash *hash_find(char *name)
{
if (!name)
return NULL;
#if MIN_VERSION(3,1) && defined(HAVE_DNSSEC)
/* We provide a "null" hash which returns the input data as digest. */
if (strcmp(null_hash.name, name) == 0)
return &null_hash;
#endif
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library
versions. */
#if MIN_VERSION(3, 4)
return nettle_lookup_hash(name);
#else
{
int i;
for (i = 0; nettle_hashes[i]; i++)
if (strcmp(nettle_hashes[i]->name, name) == 0)
return nettle_hashes[i];
}
return NULL;
#endif
}
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
+1 -1
View File
@@ -377,7 +377,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
/* 0.0.0.0 for server address == NULL, for Dbus */
if (addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0)
flags |= SERV_NO_ADDR;
flags |= SERV_LITERAL_ADDRESS;
if (strings)
{
-1
View File
@@ -72,4 +72,3 @@
#define DHCP6NOBINDING 3
#define DHCP6NOTONLINK 4
#define DHCP6USEMULTI 5
+1 -3
View File
@@ -825,6 +825,4 @@ void dhcp_construct_contexts(time_t now)
}
}
#endif
#endif /* HAVE_DHCP6 */
+1
View File
@@ -82,6 +82,7 @@
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
struct dns_header {
u16 id;
+25 -19
View File
@@ -1716,22 +1716,24 @@ static int set_dns_listeners(time_t now)
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
poll_listen(rfl->rfd->fd, POLLIN);
/* check to see if we have free tcp process slots. */
for (i = MAX_PROCS - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
for (listener = daemon->listeners; listener; listener = listener->next)
{
/* only listen for queries if we have resources */
if (listener->fd != -1 && wait == 0)
poll_listen(listener->fd, POLLIN);
/* death of a child goes through the select loop, so
we don't need to explicitly arrange to wake up here */
if (listener->tcpfd != -1)
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
{
poll_listen(listener->tcpfd, POLLIN);
break;
}
/* Only listen for TCP connections when a process slot
is available. Death of a child goes through the select loop, so
we don't need to explicitly arrange to wake up here,
we'll be called again when a slot becomes available. */
if (listener->tcpfd != -1 && i >= 0)
poll_listen(listener->tcpfd, POLLIN);
#ifdef HAVE_TFTP
/* tftp == 0 in single-port mode. */
if (tftp <= daemon->tftp_max && listener->tftpfd != -1)
@@ -1797,7 +1799,16 @@ static void check_dns_listeners(time_t now)
tftp_request(listener, now);
#endif
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
/* check to see if we have a free tcp process slot.
Note that we can't assume that because we had
at least one a poll() time, that we still do.
There may be more waiting connections after
poll() returns then free process slots. */
for (i = MAX_PROCS - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
{
int confd, client_ok = 1;
struct irec *iface = NULL;
@@ -1887,7 +1898,6 @@ static void check_dns_listeners(time_t now)
close(pipefd[0]);
else
{
int i;
#ifdef HAVE_LINUX_NETWORK
/* The child process inherits the netlink socket,
which it never uses, but when the parent (us)
@@ -1907,13 +1917,9 @@ static void check_dns_listeners(time_t now)
read_write(pipefd[0], &a, 1, 1);
#endif
for (i = 0; i < MAX_PROCS; i++)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
{
daemon->tcp_pids[i] = p;
daemon->tcp_pipes[i] = pipefd[0];
break;
}
/* i holds index of free slot */
daemon->tcp_pids[i] = p;
daemon->tcp_pipes[i] = pipefd[0];
}
close(confd);
+58 -18
View File
@@ -270,7 +270,9 @@ struct event_desc {
#define OPT_SINGLE_PORT 60
#define OPT_LEASE_RENEW 61
#define OPT_LOG_DEBUG 62
#define OPT_LAST 63
#define OPT_UMBRELLA 63
#define OPT_UMBRELLA_DEVID 64
#define OPT_LAST 65
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -496,7 +498,7 @@ struct crec {
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
#define F_NOEXTRA (1u<<27)
#define F_SERVFAIL (1u<<28) /* currently unused. */
#define F_DOMAINSRV (1u<<28)
#define F_RCODE (1u<<29)
#define F_SRV (1u<<30)
@@ -522,19 +524,20 @@ union mysockaddr {
#define IFACE_PERMANENT 4
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
#define SERV_HAS_DOMAIN 8 /* server for one domain only */
/* The actual values here matter, since we sort on them to get records in the order
IPv6 addr, IPv4 addr, all zero return, no-data return, send upstream. */
#define SERV_LITERAL_ADDRESS 1 /* addr is the answer, or NoDATA is the answer, depending on the next three flags */
#define SERV_ALL_ZEROS 2 /* return all zeros for A and AAAA */
#define SERV_4ADDR 4 /* addr is IPv4 */
#define SERV_6ADDR 8 /* addr is IPv6 */
#define SERV_HAS_SOURCE 16 /* source address defined */
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
#define SERV_MARK 256 /* for mark-and-delete */
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
#define SERV_COUNTED 512 /* workspace for log code */
#define SERV_USE_RESOLV 1024 /* forward this domain in the normal way */
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
#define SERV_FROM_RESOLV 2048 /* 1 for servers from resolv, 0 for command line. */
#define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
@@ -559,19 +562,46 @@ struct randfd_list {
struct randfd_list *next;
};
struct server {
int flags;
char *domain;
struct server *next;
int serial, arrayposn;
int last_server;
union mysockaddr addr, source_addr;
char interface[IF_NAMESIZE+1];
unsigned int ifindex; /* corresponding to interface, above */
struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd, edns_pktsz;
int tcpfd, edns_pktsz;
time_t pktsz_reduced;
unsigned int queries, failed_queries;
time_t forwardtime;
int forwardcount;
#ifdef HAVE_LOOP
u32 uid;
#endif
struct server *next;
};
/* First three fields must match struct server in next three definitions.. */
struct serv_addr4 {
int flags;
char *domain;
struct server *next;
struct in_addr addr;
};
struct serv_addr6 {
int flags;
char *domain;
struct server *next;
struct in6_addr addr;
};
struct serv_local {
int flags;
char *domain;
struct server *next;
};
struct ipsets {
@@ -660,6 +690,7 @@ struct hostsfile {
#define STAT_SECURE_WILDCARD 7
#define STAT_OK 8
#define STAT_ABANDONED 9
#define STAT_INPROGRESS 10
#define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2
@@ -1052,7 +1083,8 @@ extern struct daemon {
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers;
struct server *servers, *local_domains, **serverarray, *no_rebind;
int serverarraysz;
struct ipsets *ipsets;
int log_fac; /* log facility */
char *log_file; /* optional log file */
@@ -1061,6 +1093,9 @@ extern struct daemon {
int port, query_port, min_port, max_port;
unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl, dhcp_ttl, use_dhcp_ttl;
char *dns_client_id;
u32 umbrella_org;
u32 umbrella_asset;
u8 umbrella_device[8];
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces;
@@ -1121,9 +1156,6 @@ extern struct daemon {
struct serverfd *sfds;
struct irec *interfaces;
struct listener *listeners;
struct server *last_server;
time_t forwardtime;
int forwardcount;
struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */
int fd_save; /* " " */
@@ -1239,9 +1271,7 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen);
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
unsigned int extract_request(struct dns_header *header, size_t qlen,
char *name, unsigned short *typep);
size_t setup_reply(struct dns_header *header, size_t qlen,
union all_addr *addrp, unsigned int flags,
unsigned long ttl);
void setup_reply(struct dns_header *header, unsigned int flags);
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
time_t now, char **ipsets, int is_sign, int check_rebind,
int no_cache_dnssec, int secure, int *doctored);
@@ -1690,3 +1720,13 @@ int do_arp_script_run(void);
void dump_init(void);
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
#endif
/* domain-match.c */
void build_server_array(void);
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
int filter_servers(int seed, int flags, int *lowout, int *highout);
int is_local_answer(time_t now, int first, char *name);
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
#endif
+379
View File
@@ -0,0 +1,379 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv);
static int order_qsort(const void *a, const void *b);
static int order_servers(struct server *s, struct server *s2);
void build_server_array(void)
{
struct server *serv;
int count = 0;
for (serv = daemon->servers; serv; serv = serv->next)
count++;
for (serv = daemon->local_domains; serv; serv = serv->next)
count++;
if (count > daemon->serverarraysz)
{
struct server **new;
if ((new = whine_malloc(count * sizeof(struct server *))))
{
if (daemon->serverarray)
free(daemon->serverarray);
daemon->serverarray = new;
daemon->serverarraysz = count;
}
}
count = 0;
for (serv = daemon->servers; serv; serv = serv->next, count++)
{
daemon->serverarray[count] = serv;
serv->serial = count;
serv->last_server = -1;
}
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
daemon->serverarray[count] = serv;
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
/* servers need the location in the array to find all the whole
set of equivalent servers from a pointer to a single one. */
for (count = 0; count < daemon->serverarraysz; count++)
if (!(daemon->serverarray[count]->flags & SERV_LITERAL_ADDRESS))
daemon->serverarray[count]->arrayposn = count;
}
/* we're looking for the server whose domain is the longest exact match
to the RH end of qdomain, or a local address if the flags match.
Add '.' to the LHS of the query string so
server=/.example.com/ works.
A flag of F_SERVER returns an upstream server only.
A flag of F_DNSSECOK returns a DNSSEC capable server only and
also disables NODOTS servers from consideration.
A flag of F_DOMAINSRV returns a domain-specific server only.
return 0 if nothing found, 1 otherwise.
*/
int lookup_domain(char *qdomain, int flags, int *lowout, int *highout)
{
int rc, nodots, leading_dot = 1;
ssize_t qlen, maxlen;
int try, high, low = 0;
int nlow = 0, nhigh = 0;
char *cp;
/* may be no configured servers. */
if (daemon->serverarraysz == 0)
return 0;
maxlen = strlen(daemon->serverarray[0]->domain);
/* find query length and presence of '.' */
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
if (*cp == '.')
nodots = 0;
/* Handle empty name, and searches for DNSSEC queries without
diverting to NODOTS servers. */
if (qlen == 0 || flags & F_DNSSECOK)
nodots = 0;
/* No point trying to match more than the largest server domain */
if (qlen > maxlen)
{
qdomain += qlen - maxlen;
qlen = maxlen;
leading_dot = 0;
}
/* Search shorter and shorter RHS substrings for a match */
while (qlen >= 0)
{
/* Note that when we chop off a character, all the possible matches
MUST be at a larger index than the nearest failing match with one more
character, since the array is sorted longest to smallest. Hence
we don't reset low here. */
high = daemon->serverarraysz;
/* binary search */
do
{
try = (low + high)/2;
if ((rc = order(qdomain, leading_dot, qlen, daemon->serverarray[try])) == 0)
break;
if (rc < 0)
{
if (high == try)
break;
high = try;
}
else
{
if (low == try)
break;
low = try;
}
}
while (low != high);
if (rc == 0)
{
/* We've matched a setting which says to use servers without a domain.
Continue the search with empty query (the last character gets stripped
by the loop. */
if (daemon->serverarray[try]->flags & SERV_USE_RESOLV)
{
qdomain += qlen - 1;
qlen = 1;
}
else
{
/* We have a match, but it may only be (say) an IPv6 address, and
if the query wasn't for an AAAA record, it's no good, and we need
to continue generalising */
if (filter_servers(try, flags, &nlow, &nhigh))
break;
}
}
if (leading_dot)
leading_dot = 0;
else
{
qlen--;
qdomain++;
}
}
/* domain has no dots, and we have at least one server configured to handle such,
These servers always sort to the very end of the array.
A configured server eg server=/lan/ will take precdence. */
if (nodots &&
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
(nlow == nhigh || strlen(daemon->serverarray[nlow]->domain) == 0))
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
/* F_DOMAINSRV returns only domain-specific servers, so if we got to a
general server, return empty set. */
if (nlow != nhigh && (flags & F_DOMAINSRV) && strlen(daemon->serverarray[nlow]->domain) == 0)
nlow = nhigh;
if (lowout)
*lowout = nlow;
if (highout)
*highout = nhigh;
if (nlow == nhigh)
return 0;
return 1;
}
int filter_servers(int seed, int flags, int *lowout, int *highout)
{
int nlow = seed, nhigh = seed;
int i;
/* expand nlow and nhigh to cover all the records with the same domain
nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
which can happen below. */
while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
nlow--;
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
nhigh++;
nhigh++;
/* Now the servers are on order between low and high, in the order
return zero for both, IPv6 addr, IPv4 addr, no-data return, send upstream.
See which of those match our query in that priority order and narrow (low, high) */
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
if (i != nlow && (flags & F_IPV6))
nhigh = i;
else
{
nlow = i;
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
if (i != nlow && (flags & F_IPV4))
nhigh = i;
else
{
nlow = i;
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
if (i != nlow && (flags & (F_IPV4 | F_IPV6)))
nhigh = i;
else
{
nlow = i;
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
/* --local=/domain/, only return if we don't need a server. */
if (i != nlow && !(flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER)))
nhigh = i;
else
{
nlow = i;
/* If we want a server that can do DNSSEC, and this one can't,
return nothing. */
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
nlow = nhigh;
}
}
}
}
*lowout = nlow;
*highout = nhigh;
return (nlow != nhigh);
}
int is_local_answer(time_t now, int first, char *name)
{
int flags = 0;
int rc = 0;
if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
{
if (flags & SERV_4ADDR)
rc = F_IPV4;
else if (flags & SERV_6ADDR)
rc = F_IPV6;
else if (flags & SERV_ALL_ZEROS)
rc = F_IPV4 | F_IPV6;
else
rc = check_for_local_domain(name, now) ? F_NOERR : F_NXDOMAIN;
}
return rc;
}
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
{
int first, last, index;
/* Find server to send DNSSEC query to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
return -1;
for (index = first; index != last; index++)
if (daemon->serverarray[index] == server)
break;
/* No match to server used for original query.
Use newly looked up set. */
if (index == last)
index = daemon->serverarray[first]->last_server == -1 ?
first : daemon->serverarray[first]->last_server;
if (firstp)
*firstp = first;
if (lastp)
*lastp = last;
return index;
}
#endif
/* order by size, then by dictionary order */
static int order(char *qdomain, int leading_dot, size_t qlen, struct server *serv)
{
size_t dlen = 0;
int rc;
/* servers for dotless names always sort last
searched for name is never dotless. */
if (serv->flags & SERV_FOR_NODOTS)
return -1;
if (leading_dot)
qlen++;
dlen = strlen(serv->domain);
if (qlen < dlen)
return 1;
if (qlen > dlen)
return -1;
if (leading_dot && (rc = '.' - serv->domain[0]) != 0)
return rc;
return strcmp(qdomain, leading_dot ? &serv->domain[1] : serv->domain);
}
static int order_servers(struct server *s1, struct server *s2)
{
size_t dlen = strlen(s1->domain);
/* need full comparison of dotless servers in
order_qsort() and filter_servers() */
if (s1->flags & SERV_FOR_NODOTS)
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
return order(s1->domain, 0, dlen, s2);
}
static int order_qsort(const void *a, const void *b)
{
int rc;
struct server *s1 = *((struct server **)a);
struct server *s2 = *((struct server **)b);
rc = order_servers(s1, s2);
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
in a very specific order. */
if (rc == 0)
rc = (s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS)) -
(s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_ALL_ZEROS));
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
if (rc == 0)
if (!(s1->flags & SERV_LITERAL_ADDRESS))
rc = s1->serial - s2->serial;
return rc;
}
+63
View File
@@ -427,6 +427,66 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
return 1;
}
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
* detailed information on packet formating.
*/
#define UMBRELLA_VERSION 1
#define UMBRELLA_TYPESZ 2
#define UMBRELLA_ASSET 0x0004
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
#define UMBRELLA_ORG 0x0008
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
#define UMBRELLA_IPV4 0x0010
#define UMBRELLA_IPV6 0x0020
#define UMBRELLA_DEVICE 0x0040
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
struct umbrella_opt {
u8 magic[4];
u8 version;
u8 flags;
/* We have 4 possible fields since we'll never send both IPv4 and
* IPv6, so using the larger of the two to calculate max buffer size.
* Each field also has a type header. So the following accounts for
* the type headers and each field size to get a max buffer size.
*/
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
};
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
{
*cacheable = 0;
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
u8 *u = &opt.fields[0];
if (daemon->umbrella_org) {
PUTSHORT(UMBRELLA_ORG, u);
PUTLONG(daemon->umbrella_org, u);
}
int family = source->sa.sa_family;
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
memcpy(u, get_addrp(source, family), size);
u += size;
if (option_bool(OPT_UMBRELLA_DEVID)) {
PUTSHORT(UMBRELLA_DEVICE, u);
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
u += UMBRELLA_DEVICESZ;
}
if (daemon->umbrella_asset) {
PUTSHORT(UMBRELLA_ASSET, u);
PUTLONG(daemon->umbrella_asset, u);
}
int len = u - &opt.magic[0];
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
}
/* Set *check_subnet if we add a client subnet option, which needs to checked
in the reply. Set *cacheable to zero if we add an option which the answer
may depend on. */
@@ -445,6 +505,9 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
if (daemon->dns_client_id)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
if (option_bool(OPT_UMBRELLA))
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
if (option_bool(OPT_CLIENT_SUBNET))
{
+893 -1048
View File
File diff suppressed because it is too large. Load diff
File renamed without changes.
+1 -4
View File
@@ -882,7 +882,4 @@ void helper_write(void)
}
}
#endif
#endif /* HAVE_SCRIPT */
-1
View File
@@ -295,4 +295,3 @@ int inotify_check(time_t now)
}
#endif /* INOTIFY */
-1
View File
@@ -31,4 +31,3 @@
&& ((__const uint32_t *) (a))[1] == 0 \
&& ((__const uint32_t *) (a))[2] == 0 \
&& ((__const uint32_t *) (a))[3] == 0)
+2 -6
View File
@@ -378,7 +378,7 @@ void lease_update_file(time_t now)
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
next_event = LEASE_RETRY + now;
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %u s)"),
daemon->lease_file, strerror(err),
(unsigned int)difftime(next_event, now));
}
@@ -1201,8 +1201,4 @@ void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned
}
#endif
#endif
#endif /* HAVE_DHCP */
+11 -11
View File
@@ -30,8 +30,8 @@ void loop_send_probes()
/* Loop through all upstream servers not for particular domains, and send a query to that server which is
identifiable, via the uid. If we see that query back again, then the server is looping, and we should not use it. */
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)))
if (strlen(serv->domain) == 0 &&
!(serv->flags & (SERV_FOR_NODOTS | SERV_LOOP)))
{
ssize_t len = loop_make_probe(serv->uid);
int fd;
@@ -96,15 +96,15 @@ int detect_loop(char *query, int type)
uid = strtol(query, NULL, 16);
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_LOOP)) &&
uid == serv->uid)
{
serv->flags |= SERV_LOOP;
check_servers(); /* log new state */
return 1;
}
if (strlen(serv->domain) == 0 &&
!(serv->flags & SERV_LOOP) &&
uid == serv->uid)
{
serv->flags |= SERV_LOOP;
check_servers(); /* log new state */
return 1;
}
return 0;
}
+1 -3
View File
@@ -402,6 +402,4 @@ static unsigned nl_async(struct nlmsghdr *h, unsigned state)
}
return state;
}
#endif
#endif /* HAVE_LINUX_NETWORK */
+178 -159
View File
@@ -31,7 +31,7 @@ int indextoname(int fd, int index, char *name)
safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
return 1;
return 1;
}
@@ -1479,8 +1479,7 @@ void pre_allocate_sfds(void)
}
for (srv = daemon->servers; srv; srv = srv->next)
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
if (!allocate_sfd(&srv->source_addr, srv->interface, srv->ifindex) &&
errno != 0 &&
option_bool(OPT_NOWILD))
{
@@ -1509,6 +1508,10 @@ void mark_servers(int flag)
serv->flags &= ~SERV_LOOP;
#endif
}
for (serv = daemon->local_domains; serv; serv = serv->next)
if (serv->flags & flag)
serv->flags |= SERV_MARK;
}
void cleanup_servers(void)
@@ -1523,14 +1526,27 @@ void cleanup_servers(void)
{
server_gone(serv);
*up = serv->next;
if (serv->domain)
free(serv->domain);
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
*up = serv->next;
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
#ifdef HAVE_LOOP
/* Now we have a new set of servers, test for loops. */
loop_send_probes();
@@ -1543,76 +1559,80 @@ void add_update_server(int flags,
const char *interface,
const char *domain)
{
struct server *serv, *next = NULL;
char *domain_str = NULL;
struct server *serv;
char *domain_str;
if (!domain)
domain = "";
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain.
NOTE that we can get local=/domain/ here, but NOT address=/domain/1.2.3.4 */
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
/* 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;
}
for (serv = (flags & SERV_IS_LOCAL) ? daemon->local_domains : daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_MARK) && hostname_isequal(domain, serv->domain))
break;
if (serv)
{
domain_str = serv->domain;
next = serv->next;
}
domain_str = serv->domain;
else if ((serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
if (domain && !(domain_str = whine_malloc(strlen(domain)+1)))
if (!(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;
{
strcpy(domain_str, domain);
if (flags & SERV_IS_LOCAL)
{
serv->next = daemon->local_domains;
daemon->local_domains = serv;
}
else
{
for (s = daemon->servers; s->next; s = s->next);
s->next = serv;
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;
}
serv->next = NULL;
}
if (domain)
strcpy(domain_str, domain);
}
}
if (serv)
{
memset(serv, 0, sizeof(struct server));
if (!(flags & SERV_IS_LOCAL))
memset(serv, 0, sizeof(struct server));
serv->flags = flags;
serv->domain = domain_str;
serv->next = next;
serv->queries = serv->failed_queries = 0;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (domain)
serv->flags |= SERV_HAS_DOMAIN;
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
if (!(flags & SERV_IS_LOCAL))
{
serv->queries = serv->failed_queries = 0;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
}
}
@@ -1623,7 +1643,7 @@ void check_servers(void)
struct serverfd *sfd, *tmp, **up;
int port = 0, count;
int locals = 0;
/* interface may be new since startup */
if (!option_bool(OPT_NOWILD))
enumerate_interfaces(0);
@@ -1634,114 +1654,117 @@ void check_servers(void)
for (count = 0, serv = daemon->servers; serv; serv = serv->next)
{
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
/* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0)
serv->edns_pktsz = daemon->edns_pktsz;
/* Init edns_pktsz for newly created server records. */
if (serv->edns_pktsz == 0)
serv->edns_pktsz = daemon->edns_pktsz;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
if (!(serv->flags & SERV_FOR_NODOTS))
serv->flags |= SERV_DO_DNSSEC;
if (option_bool(OPT_DNSSEC_VALID))
{
if (!(serv->flags & SERV_FOR_NODOTS))
serv->flags |= SERV_DO_DNSSEC;
/* Disable DNSSEC validation when using server=/domain/.... servers
unless there's a configured trust anchor. */
if (strlen(serv->domain) != 0)
{
struct ds_config *ds;
char *domain = serv->domain;
/* Disable DNSSEC validation when using server=/domain/.... servers
unless there's a configured trust anchor. */
if (serv->flags & SERV_HAS_DOMAIN)
{
struct ds_config *ds;
char *domain = serv->domain;
/* .example.com is valid */
while (*domain == '.')
domain++;
for (ds = daemon->ds; ds; ds = ds->next)
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
break;
if (!ds)
serv->flags &= ~SERV_DO_DNSSEC;
}
/* .example.com is valid */
while (*domain == '.')
domain++;
for (ds = daemon->ds; ds; ds = ds->next)
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
break;
if (!ds)
serv->flags &= ~SERV_DO_DNSSEC;
}
}
#endif
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
if (serv->addr.sa.sa_family == AF_INET &&
serv->addr.in.sin_addr.s_addr == 0)
{
serv->flags |= SERV_MARK;
continue;
}
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&serv->addr, &iface->addr))
break;
if (iface)
{
my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
serv->flags |= SERV_MARK;
continue;
}
/* Do we need a socket set? */
if (!serv->sfd &&
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),
daemon->namebuff, strerror(errno));
serv->flags |= SERV_MARK;
continue;
}
if (serv->sfd)
serv->sfd->used = 1;
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
if (serv->addr.sa.sa_family == AF_INET &&
serv->addr.in.sin_addr.s_addr == 0)
{
serv->flags |= SERV_MARK;
continue;
}
if (!(serv->flags & SERV_NO_REBIND) && !(serv->flags & SERV_LITERAL_ADDRESS))
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&serv->addr, &iface->addr))
break;
if (iface)
{
if (++count > SERVERS_LOGGED)
continue;
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
{
char *s1, *s2, *s3 = "";
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
s3 = _("(no DNSSEC)");
#endif
if (!(serv->flags & SERV_HAS_DOMAIN))
s1 = _("unqualified"), s2 = _("names");
else if (strlen(serv->domain) == 0)
s1 = _("default"), s2 = "";
else
s1 = _("domain"), s2 = serv->domain;
if (serv->flags & SERV_NO_ADDR)
{
count--;
if (++locals <= LOCALS_LOGGED)
my_syslog(LOG_INFO, _("using only locally-known addresses for %s %s"), s1, s2);
}
else if (serv->flags & SERV_USE_RESOLV)
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
else
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
}
#ifdef HAVE_LOOP
else if (serv->flags & SERV_LOOP)
my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port);
#endif
else if (serv->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
else
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
my_syslog(LOG_WARNING, _("ignoring nameserver %s - local interface"), daemon->namebuff);
serv->flags |= SERV_MARK;
continue;
}
/* Do we need a socket set? */
if (!serv->sfd &&
!(serv->sfd = allocate_sfd(&serv->source_addr, serv->interface, serv->ifindex)) &&
errno != 0)
{
my_syslog(LOG_WARNING,
_("ignoring nameserver %s - cannot make/bind socket: %s"),
daemon->namebuff, strerror(errno));
serv->flags |= SERV_MARK;
continue;
}
if (serv->sfd)
serv->sfd->used = 1;
if (++count > SERVERS_LOGGED)
continue;
if (strlen(serv->domain) != 0 || (serv->flags & SERV_FOR_NODOTS))
{
char *s1, *s2, *s3 = "";
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
s3 = _("(no DNSSEC)");
#endif
if (serv->flags & SERV_FOR_NODOTS)
s1 = _("unqualified"), s2 = _("names");
else if (strlen(serv->domain) == 0)
s1 = _("default"), s2 = "";
else
s1 = _("domain"), s2 = serv->domain;
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
}
#ifdef HAVE_LOOP
else if (serv->flags & SERV_LOOP)
my_syslog(LOG_INFO, _("NOT using nameserver %s#%d - query loop detected"), daemon->namebuff, port);
#endif
else if (serv->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, serv->interface);
else
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
}
for (count = 0, serv = daemon->local_domains; serv; serv = serv->next)
{
if (++count > SERVERS_LOGGED)
continue;
if ((serv->flags & SERV_LITERAL_ADDRESS) &&
!(serv->flags & (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)))
{
count--;
if (++locals <= LOCALS_LOGGED)
my_syslog(LOG_INFO, _("using only locally-known addresses for %s"), serv->domain);
}
else if (serv->flags & SERV_USE_RESOLV)
my_syslog(LOG_INFO, _("using standard nameservers for %s"), serv->domain);
}
if (locals > LOCALS_LOGGED)
@@ -1764,6 +1787,7 @@ void check_servers(void)
}
cleanup_servers();
build_server_array();
}
/* Return zero if no servers found, in that case we keep polling.
@@ -1869,8 +1893,3 @@ void newaddress(time_t now)
lease_find_interfaces(now);
#endif
}
+230 -140
View File
@@ -170,6 +170,7 @@ struct myoption {
#define LOPT_PXE_VENDOR 361
#define LOPT_DYNHOST 362
#define LOPT_LOG_DEBUG 363
#define LOPT_UMBRELLA 364
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -345,6 +346,7 @@ static const struct myoption opts[] =
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
{ "umbrella", 2, 0, LOPT_UMBRELLA },
{ NULL, 0, 0, 0 }
};
@@ -527,6 +529,7 @@ static struct {
{ LOPT_DUMPFILE, ARG_ONE, "<path>", gettext_noop("Path to debug packet dump file"), NULL },
{ LOPT_DUMPMASK, ARG_ONE, "<hex>", gettext_noop("Mask which packets to dump"), NULL },
{ LOPT_SCRIPT_TIME, OPT_LEASE_RENEW, NULL, gettext_noop("Call dhcp-script when lease expiry changes."), NULL },
{ LOPT_UMBRELLA, ARG_ONE, "[=<optspec>]", gettext_noop("Send Cisco Umbrella identifiers including remote IP."), NULL },
{ 0, 0, NULL, NULL, NULL }
};
@@ -641,6 +644,9 @@ static char *canonicalise_opt(char *s)
if (!s)
return 0;
if (strlen(s) == 0)
return "";
unhide_metas(s);
if (!(ret = canonicalise(s, &nomem)) && nomem)
{
@@ -653,7 +659,7 @@ static char *canonicalise_opt(char *s)
return ret;
}
static int atoi_check(char *a, int *res)
static int numeric_check(char *a)
{
char *p;
@@ -666,10 +672,29 @@ static int atoi_check(char *a, int *res)
if (*p < '0' || *p > '9')
return 0;
return 1;
}
static int atoi_check(char *a, int *res)
{
if (!numeric_check(a))
return 0;
*res = atoi(a);
return 1;
}
static int strtoul_check(char *a, u32 *res)
{
if (!numeric_check(a))
return 0;
*res = strtoul(a, NULL, 10);
if (errno == ERANGE) {
errno = 0;
return 0;
}
return 1;
}
static int atoi_check16(char *a, int *res)
{
if (!(atoi_check(a, res)) ||
@@ -794,14 +819,14 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
char *interface_opt = NULL;
int scope_index = 0;
char *scope_id;
if (!arg || strlen(arg) == 0)
if (strcmp(arg, "#") == 0)
{
*flags |= SERV_NO_ADDR;
*interface = 0;
if (flags)
*flags |= SERV_USE_RESOLV;
return NULL;
}
if ((source = split_chr(arg, '@')) && /* is there a source. */
(portno = split_chr(source, '#')) &&
!atoi_check16(portno, &source_port))
@@ -899,7 +924,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
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);
in_addr_t a = ntohl(addr.s_addr);
char *p;
memset(serv, 0, sizeof(struct server));
@@ -927,10 +952,6 @@ static struct server *add_rev4(struct in_addr addr, int msize)
p += sprintf(p, "in-addr.arpa");
serv->flags = SERV_HAS_DOMAIN;
serv->next = daemon->servers;
daemon->servers = serv;
return serv;
}
@@ -951,10 +972,6 @@ static struct server *add_rev6(struct in6_addr *addr, int msize)
}
p += sprintf(p, "ip6.arpa");
serv->flags = SERV_HAS_DOMAIN;
serv->next = daemon->servers;
daemon->servers = serv;
return serv;
}
@@ -1045,6 +1062,8 @@ static void dhcp_config_free(struct dhcp_config *config)
if (config->flags & CONFIG_CLID)
free(config->clid);
if (config->flags & CONFIG_NAME)
free(config->hostname);
#ifdef HAVE_DHCP6
if (config->flags & CONFIG_ADDR6)
@@ -1640,16 +1659,6 @@ void reset_option_bool(unsigned int opt)
option_var(opt) &= ~(option_val(opt));
}
static void server_list_free(struct server *list)
{
while (list)
{
struct server *tmp = list;
list = list->next;
free(tmp);
}
}
static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
{
int i;
@@ -2285,15 +2294,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!serv)
ret_err_free(_("bad prefix"), new);
serv->flags |= SERV_NO_ADDR;
serv->flags |= SERV_LITERAL_ADDRESS;
serv->next = daemon->local_domains;
daemon->local_domains = serv;
/* local=/<domain>/ */
serv = opt_malloc(sizeof(struct server));
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->flags = SERV_LITERAL_ADDRESS;
serv->next = daemon->local_domains;
daemon->local_domains = serv;
}
}
}
@@ -2328,15 +2339,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
/* generate the equivalent of
local=/xxx.yyy.zzz.ip6.arpa/ */
struct server *serv = add_rev6(&new->start6, msize);
serv->flags |= SERV_NO_ADDR;
serv->flags |= SERV_LITERAL_ADDRESS;
serv->next = daemon->local_domains;
daemon->local_domains = serv;
/* local=/<domain>/ */
serv = opt_malloc(sizeof(struct server));
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->flags = SERV_LITERAL_ADDRESS;
serv->next = daemon->local_domains;
daemon->local_domains = serv;
}
}
}
@@ -2409,6 +2422,41 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->dns_client_id = opt_string_alloc(arg);
break;
case LOPT_UMBRELLA: /* --umbrella */
set_option_bool(OPT_UMBRELLA);
while (arg) {
comma = split(arg);
if (strstr(arg, "deviceid:")) {
arg += 9;
if (strlen(arg) != 16)
ret_err(gen_err);
for (char *p = arg; *p; p++) {
if (!isxdigit((int)*p))
ret_err(gen_err);
}
set_option_bool(OPT_UMBRELLA_DEVID);
u8 *u = daemon->umbrella_device;
char word[3];
for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
memcpy(word, &(arg[0]), 2);
*u++ = strtoul(word, NULL, 16);
}
}
else if (strstr(arg, "orgid:")) {
if (!strtoul_check(arg+6, &daemon->umbrella_org)) {
ret_err(gen_err);
}
}
else if (strstr(arg, "assetid:")) {
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) {
ret_err(gen_err);
}
}
arg = comma;
}
break;
case LOPT_ADD_MAC: /* --add-mac */
if (!arg)
set_option_bool(OPT_ADD_MAC);
@@ -2556,98 +2604,166 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} while (arg);
break;
case LOPT_NO_REBIND: /* --rebind-domain-ok */
{
struct server *new;
unhide_metas(arg);
if (*arg == '/')
arg++;
do {
comma = split_chr(arg, '/');
new = opt_malloc(sizeof(struct serv_local));
new->domain = opt_string_alloc(arg);
new->flags = strlen(arg);
new->next = daemon->no_rebind;
daemon->no_rebind = new;
arg = comma;
} while (arg && *arg);
break;
}
case 'S': /* --server */
case LOPT_LOCAL: /* --local */
case 'A': /* --address */
case LOPT_NO_REBIND: /* --rebind-domain-ok */
{
struct server *serv, *newlist = NULL;
struct server *new;
size_t size;
char *lastdomain = NULL, *domain = "";
char *alloc_domain;
int flags = 0;
char *err;
struct in_addr addr4;
struct in6_addr addr6;
unhide_metas(arg);
if (arg && (*arg == '/' || option == LOPT_NO_REBIND))
/* split the domain args, if any and skip to the end of them. */
if (arg && *arg == '/')
{
int rebind = !(*arg == '/');
char *end = NULL;
if (!rebind)
arg++;
while (rebind || (end = split_chr(arg, '/')))
char *last;
arg++;
domain = lastdomain = arg;
while ((last = split_chr(arg, '/')))
{
char *domain = NULL;
/* elide leading dots - they are implied in the search algorithm */
while (*arg == '.') arg++;
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0)
domain = "";
else if (strlen (arg) != 0 && !(domain = canonicalise_opt(arg)))
ret_err(gen_err);
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->next = newlist;
newlist = serv;
serv->domain = domain;
serv->flags = domain ? SERV_HAS_DOMAIN : SERV_FOR_NODOTS;
arg = end;
if (rebind)
break;
lastdomain = arg;
arg = last;
}
if (!newlist)
ret_err(gen_err);
}
else
{
newlist = opt_malloc(sizeof(struct server));
memset(newlist, 0, sizeof(struct server));
#ifdef HAVE_LOOP
newlist->uid = rand32();
#endif
}
if (servers_only && option == 'S')
newlist->flags |= SERV_FROM_FILE;
if (option == 'A')
{
newlist->flags |= SERV_LITERAL_ADDRESS;
if (!(newlist->flags & SERV_TYPE))
{
server_list_free(newlist);
ret_err(gen_err);
}
}
else if (option == LOPT_NO_REBIND)
newlist->flags |= SERV_NO_REBIND;
flags |= SERV_FROM_FILE;
if (!arg || !*arg)
flags = SERV_LITERAL_ADDRESS;
else if (option == 'A')
{
if (!(newlist->flags & SERV_NO_REBIND))
newlist->flags |= SERV_NO_ADDR; /* no server */
/* # as literal address means return zero address for 4 and 6 */
if (strcmp(arg, "#") == 0)
flags |= SERV_ALL_ZEROS | SERV_LITERAL_ADDRESS;
else if (inet_pton(AF_INET, arg, &addr4) > 0)
flags |= SERV_4ADDR | SERV_LITERAL_ADDRESS;
else if (inet_pton(AF_INET6, arg, &addr6) > 0)
flags |= SERV_6ADDR | SERV_LITERAL_ADDRESS;
else
ret_err(_("Bad address in --address"));
}
else if (strcmp(arg, "#") == 0)
newlist->flags |= SERV_USE_RESOLV; /* treat in ordinary way */
if (!(alloc_domain = canonicalise_opt(domain)))
ret_err(gen_err);
if (flags & SERV_LITERAL_ADDRESS)
{
if (flags & SERV_6ADDR)
{
size = sizeof(struct serv_addr6);
new = opt_malloc(sizeof(struct serv_addr6));
((struct serv_addr6*)new)->addr = addr6;
}
else if (flags & SERV_4ADDR)
{
size = sizeof(struct serv_addr4);
new = opt_malloc(sizeof(struct serv_addr4));
((struct serv_addr4*)new)->addr = addr4;
}
else
{
size = sizeof(struct serv_local);
new = opt_malloc(sizeof(struct serv_local));
}
new->next = daemon->local_domains;
daemon->local_domains = new;
}
else
{
char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
if (err)
size = sizeof(struct server);
new = opt_malloc(sizeof(struct server));
#ifdef HAVE_LOOP
new->uid = rand32();
#endif
if ((err = parse_server(arg, &new->addr, &new->source_addr, new->interface, &flags)))
{
server_list_free(newlist);
ret_err(err);
free(new);
ret_err(err);
}
/* Since domains that use standard servers don't have the
network stuff, it's easier to treat them as local. */
if (flags & SERV_USE_RESOLV)
{
new->next = daemon->local_domains;
daemon->local_domains = new;
}
else
{
new->next = daemon->servers;
daemon->servers = new;
}
}
serv = newlist;
while (serv->next)
{
serv->next->flags |= serv->flags & ~(SERV_HAS_DOMAIN | SERV_FOR_NODOTS);
serv->next->addr = serv->addr;
serv->next->source_addr = serv->source_addr;
strcpy(serv->next->interface, serv->interface);
serv = serv->next;
}
serv->next = daemon->servers;
daemon->servers = newlist;
break;
new->domain = alloc_domain;
/* server=//1.2.3.4 is special. */
if (strlen(domain) == 0 && lastdomain)
flags |= SERV_FOR_NODOTS;
new->flags = flags;
/* If we have more than one domain, copy and iterate */
if (lastdomain)
while (domain != lastdomain)
{
struct server *last = new;
domain += strlen(domain) + 1;
if (!(alloc_domain = canonicalise_opt(domain)))
ret_err(gen_err);
new = opt_malloc(size);
memcpy(new, last, size);
new->domain = alloc_domain;
if (flags & (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS))
{
new->next = daemon->local_domains;
daemon->local_domains = new;
}
else
{
new->next = daemon->servers;
daemon->servers = new;
}
}
break;
}
case LOPT_REV_SERV: /* --rev-server */
@@ -2672,9 +2788,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
serv = add_rev4(addr4, size);
if (!serv)
ret_err(_("bad prefix"));
serv->next = daemon->servers;
daemon->servers = serv;
}
else if (inet_pton(AF_INET6, arg, &addr6))
serv = add_rev6(&addr6, size);
{
serv = add_rev6(&addr6, size);
serv->next = daemon->servers;
daemon->servers = serv;
}
else
ret_err(gen_err);
@@ -4945,30 +5067,8 @@ static void clear_dynamic_conf(void)
if (configs->flags & CONFIG_BANK)
{
struct hwaddr_config *mac, *tmp;
struct dhcp_netid_list *list, *tmplist;
for (mac = configs->hwaddr; mac; mac = tmp)
{
tmp = mac->next;
free(mac);
}
if (configs->flags & CONFIG_CLID)
free(configs->clid);
for (list = configs->netid; list; list = tmplist)
{
free(list->list);
tmplist = list->next;
free(list);
}
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
*up = configs->next;
free(configs);
*up = cp;
dhcp_config_free(configs);
}
else
up = &configs->next;
@@ -4978,7 +5078,6 @@ static void clear_dynamic_conf(void)
static void clear_dynamic_opt(void)
{
struct dhcp_opt *opts, *cp, **up;
struct dhcp_netid *id, *next;
for (up = &daemon->dhcp_opts, opts = daemon->dhcp_opts; opts; opts = cp)
{
@@ -4986,17 +5085,8 @@ static void clear_dynamic_opt(void)
if (opts->flags & DHOPT_BANK)
{
if ((opts->flags & DHOPT_VENDOR))
free(opts->u.vendor_class);
free(opts->val);
for (id = opts->netid; id; id = next)
{
next = id->next;
free(id->net);
free(id);
}
*up = opts->next;
free(opts);
*up = cp;
dhcp_opt_free(opts);
}
else
up = &opts->next;
-3
View File
@@ -53,6 +53,3 @@ struct prefix_opt {
#define ICMP6_OPT_RT_INFO 24
#define ICMP6_OPT_RDNSS 25
#define ICMP6_OPT_DNSSL 31
+14 -66
View File
@@ -894,6 +894,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
if (typep)
*typep = 0;
*name = 0; /* return empty name if no query found. */
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
return 0; /* must be exactly one query. */
@@ -926,14 +928,8 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
return F_QUERY;
}
size_t setup_reply(struct dns_header *header, size_t qlen,
union all_addr *addrp, unsigned int flags, unsigned long ttl)
void setup_reply(struct dns_header *header, unsigned int flags)
{
unsigned char *p;
if (!(p = skip_questions(header, qlen)))
return 0;
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
/* clear AD flag, set RA flag */
@@ -946,30 +942,10 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN)
SET_RCODE(header, NXDOMAIN);
else if (flags == F_SERVFAIL)
{
union all_addr a;
a.log.rcode = SERVFAIL;
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
SET_RCODE(header, SERVFAIL);
}
else if (flags & ( F_IPV4 | F_IPV6))
{
if (flags & F_IPV4)
{ /* we know the address */
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
}
if (flags & F_IPV6)
{
SET_RCODE(header, NOERROR);
header->ancount = htons(ntohs(header->ancount) + 1);
header->hb3 |= HB3_AA;
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
}
SET_RCODE(header, NOERROR);
header->hb3 |= HB3_AA;
}
else /* nowhere to forward to */
{
@@ -978,8 +954,6 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
SET_RCODE(header, REFUSED);
}
return p - (unsigned char *)header;
}
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
@@ -1553,43 +1527,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
anscount++;
}
}
else if (option_bool(OPT_BOGUSPRIV) && (
(is_arpa == F_IPV6 && private_net6(&addr.addr6)) ||
(is_arpa == F_IPV4 && private_net(addr.addr4, 1))))
else if (option_bool(OPT_BOGUSPRIV) &&
((is_arpa == F_IPV6 && private_net6(&addr.addr6)) || (is_arpa == F_IPV4 && private_net(addr.addr4, 1))) &&
!lookup_domain(name, F_DOMAINSRV, NULL, NULL))
{
struct server *serv;
unsigned int namelen = strlen(name);
char *nameend = name + namelen;
/* see if have rev-server set */
for (serv = daemon->servers; serv; serv = serv->next)
{
unsigned int domainlen;
char *matchstart;
if ((serv->flags & (SERV_HAS_DOMAIN | SERV_NO_ADDR)) != SERV_HAS_DOMAIN)
continue;
domainlen = strlen(serv->domain);
if (domainlen == 0 || domainlen > namelen)
continue;
matchstart = nameend - domainlen;
if (hostname_isequal(matchstart, serv->domain) &&
(namelen == domainlen || *(matchstart-1) == '.' ))
break;
}
/* if no configured server, not in cache, enabled and private IPV4 address, return NXDOMAIN */
if (!serv)
{
ans = 1;
sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
name, &addr, NULL);
}
ans = 1;
sec_data = 0;
nxdomain = 1;
if (!dryrun)
log_query(F_CONFIG | F_REVERSE | is_arpa | F_NEG | F_NXDOMAIN,
name, &addr, NULL);
}
}
+1 -8
View File
@@ -2785,11 +2785,4 @@ static void apply_delay(u32 xid, time_t recvtime, struct dhcp_netid *netid)
}
}
#endif
#endif /* HAVE_DHCP */
+42 -18
View File
@@ -919,11 +919,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6RENEW:
case DHCP6REBIND:
{
int address_assigned = 0;
/* set reply message type */
*outmsgtypep = DHCP6REPLY;
log6_quiet(state, "DHCPRENEW", NULL, NULL);
log6_quiet(state, msg_type == DHCP6RENEW ? "DHCPRENEW" : "DHCPREBIND", NULL, NULL);
for (opt = state->packet_options; opt; opt = opt6_next(opt, state->end))
{
@@ -952,24 +955,35 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
state->iaid, &req_addr)))
{
/* If the server cannot find a client entry for the IA the server
returns the IA containing no addresses with a Status Code option set
to NoBinding in the Reply message. */
save_counter(iacntr);
t1cntr = 0;
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
preferred_time = valid_time = 0;
break;
if (msg_type == DHCP6REBIND)
{
/* When rebinding, we can create a lease if it doesn't exist. */
lease = lease6_allocate(&req_addr, state->ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA);
if (lease)
lease_set_iaid(lease, state->iaid);
else
break;
}
else
{
/* If the server cannot find a client entry for the IA the server
returns the IA containing no addresses with a Status Code option set
to NoBinding in the Reply message. */
save_counter(iacntr);
t1cntr = 0;
log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
preferred_time = valid_time = 0;
break;
}
}
if ((this_context = address6_available(state->context, &req_addr, tagif, 1)) ||
(this_context = address6_valid(state->context, &req_addr, tagif, 1)))
{
@@ -1000,6 +1014,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (preferred_time == 0)
message = _("deprecated");
address_assigned = 1;
}
else
{
@@ -1022,10 +1038,18 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
end_ia(t1cntr, min_time, 1);
end_opt6(o);
}
if (!address_assigned && msg_type == DHCP6REBIND)
{
/* can't create lease for any address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("no addresses available"));
end_opt6(o1);
}
tagif = add_options(state, 0);
break;
}
case DHCP6CONFIRM:
+1 -1
View File
@@ -98,7 +98,7 @@ int add_to_ipset(const char *setname, const union all_addr *ipaddr,
io.pfrio_size = 1;
if (ioctl(dev, DIOCRADDTABLES, &io))
{
my_syslog(LOG_WARNING, _("IPset: error:%s"), pfr_strerror(errno));
my_syslog(LOG_WARNING, _("IPset: error: %s"), pfr_strerror(errno));
return -1;
}
+21 -3
View File
@@ -39,6 +39,7 @@ static void sanitise(char *buf);
#define ERR_PERM 2
#define ERR_FULL 3
#define ERR_ILL 4
#define ERR_TID 5
void tftp_request(struct listener *listen, time_t now)
{
@@ -583,11 +584,27 @@ void check_tftp_listeners(time_t now)
for (transfer = daemon->tftp_trans; transfer; transfer = transfer->next)
if (poll_check(transfer->sockfd, POLLIN))
{
union mysockaddr peer;
socklen_t addr_len = sizeof(union mysockaddr);
ssize_t len;
/* we overwrote the buffer... */
daemon->srv_save = NULL;
handle_tftp(now, transfer, recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0));
if ((len = recvfrom(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0, &peer.sa, &addr_len)) > 0)
{
if (sockaddr_isequal(&peer, &transfer->peer))
handle_tftp(now, transfer, len);
else
{
/* Wrong source address. See rfc1350 para 4. */
prettyprint_addr(&peer, daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer));
}
}
}
for (transfer = daemon->tftp_trans, up = &daemon->tftp_trans; transfer; transfer = tmp)
{
tmp = transfer->next;
@@ -736,7 +753,8 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
char *errstr = strerror(errno);
memset(packet, 0, daemon->packet_buff_sz);
sanitise(file);
if (file)
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);