Compare commits

...
13 Commits
Author SHA1 Message Date
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
12 changed files with 433 additions and 354 deletions

No files matched your search

+10 -7
View File
@@ -15,10 +15,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 +31,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 +47,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 +57,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 +65,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 +101,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
+20 -1
View File
@@ -1,8 +1,27 @@
dnsmasq (2.85-1) unstable; urgency=low
* New upstream.
* Includes fix to CVE-2021-3448.
-- 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
+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; \
+311 -314
View File
File diff suppressed because it is too large. Load diff
+21 -11
View File
@@ -18,11 +18,20 @@
#ifdef HAVE_DNSSEC
/* Minimal version of nettle */
#define MIN_VERSION(major, minor) (NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
(NETTLE_VERSION_MAJOR > (major))
#include <nettle/rsa.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#if !defined(NETTLE_VERSION_MAJOR)
#define NETTLE_VERSION_MAJOR 2
#endif
#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
@@ -115,10 +124,8 @@ const struct nettle_hash *hash_find(char *name)
/* 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
versions. */
#if MIN_VERSION(3, 4)
return nettle_lookup_hash(name);
#else
{
@@ -171,7 +178,7 @@ int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **diges
return 1;
}
#endif
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
#ifdef HAVE_DNSSEC
@@ -238,7 +245,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 +308,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 +349,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 +376,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 +392,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 +408,17 @@ 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;
+36 -15
View File
@@ -309,6 +309,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
#endif
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
int old_src = 0;
(void)do_bit;
if (header->hb4 & HB4_CD)
@@ -323,19 +325,24 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
#endif
/* Check for retry on existing query */
if (!forward && (forward = lookup_frec_by_query(hash, fwd_flags)))
if (forward)
old_src = 1;
else if ((forward = lookup_frec_by_query(hash, fwd_flags)))
{
struct frec_src *src;
for (src = &forward->frec_src; src; src = src->next)
if (src->orig_id == ntohs(header->id) &&
sockaddr_isequal(&src->source, udpaddr))
break;
/* Existing query, but from new source, just add this
client to the list that will get the reply.*/
if (!src)
if (src)
old_src = 1;
else
{
/* Existing query, but from new source, just add this
client to the list that will get the reply.*/
/* Note whine_malloc() zeros memory. */
if (!daemon->free_frec_src &&
daemon->frec_src_count < daemon->ftabsize &&
@@ -345,9 +352,19 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
daemon->free_frec_src->next = NULL;
}
/* If we've been spammed with many duplicates, just drop the query. */
/* If we've been spammed with many duplicates, return REFUSED. */
if (!daemon->free_frec_src)
return 0;
{
static time_t last_log = 0;
if ((int)difftime(now, last_log) > 5)
{
last_log = now;
my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
}
goto frec_err;
}
src = daemon->free_frec_src;
daemon->free_frec_src = src->next;
@@ -359,6 +376,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
src->log_id = daemon->log_id;
src->iface = dst_iface;
src->fd = udpfd;
/* closely spaced identical queries cannot be a try and a retry, so
it's safe to wait for the reply from the first without
forwarding the second. */
if (difftime(now, forward->time) < 2)
return 0;
}
}
@@ -400,10 +423,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#endif
/* retry on existing query, send to all available servers */
/* retry on existing query, from original source. Send to all available servers */
domain = forward->sentto->domain;
forward->sentto->failed_queries++;
if (!option_bool(OPT_ORDER))
if (!option_bool(OPT_ORDER) && old_src)
{
forward->forwardall = 1;
daemon->last_server = NULL;
@@ -617,6 +640,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
/* could not send on, return empty answer or address if known for whole domain */
frec_err:
if (udpfd != -1)
{
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
@@ -1082,7 +1106,7 @@ void reply_query(int fd, time_t now)
while (1)
{
if (server_test_type(start, domain, type, 0))
if (server_test_type(start, domain, type, SERV_DO_DNSSEC))
{
new_server = start;
if (server == start)
@@ -2482,10 +2506,7 @@ static struct frec *lookup_frec(unsigned short id, int fd, void *hash)
type = f->sentto->flags & SERV_TYPE;
s = f->sentto;
do {
if ((type == (s->flags & SERV_TYPE)) &&
(type != SERV_HAS_DOMAIN ||
(s->domain && hostname_isequal(f->sentto->domain, s->domain))) &&
!(s->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)) &&
if (server_test_type(s, f->sentto->domain, type, 0) &&
s->sfd && s->sfd->fd == fd)
return f;
+1 -1
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));
}
+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);