Compare commits

...
9 Commits
Author SHA1 Message Date
Simon Kelley 3a610a007f Finesse allocation of memory for "struct crec" cache entries.
These normally have enough space for a name of up to SMALLDNAME characters.
When used to hold /etc/hosts entries, they are allocated with just enough
bytes for the name held. When used to hold other configured stuff, (CNAMES
DS records. DHCP names etc), the name is replaced by a pointer to a string
held elsewhere, and F_NAMEP set. Hence only enough space to hold a char *
is needed, rather than SMALLDNAME bytes.
2018-09-26 16:50:35 +01:00
Simon Kelley 48b090cb5c Fix b6f926fbef to not SEGV on startup (rarely).
Many thanks to Kristian Evensen  for finding and diagnosing this.

We can't copy the whole of a crec structure in make_non_terminals, since
crec structures allocated to represent /etc/hosts entries are allocated with
just enough space for the actual name they contain, not the full
SMALLDNAME bytes declared in struct crec. Using structure copy therefore
copies beyond the end of the allocated source and, just occaisionally,
into unmapped memory, resulting in a SEGV.

Since the crecs we're making here always have F_NAMEP set, we're not
interested in copying the name field from the source anyway, we use the
namep part of the union and set it to point some way into the name
of the source crec to get the super-domain that we're representing.

The fix is therefore to copy the relevant fields of the crec, rather
than copying the whole and overwriting.
2018-09-26 12:53:59 +01:00
Simon Kelley 4139298d28 Change behavior when RD bit unset in queries.
Change anti cache-snooping behaviour with queries with the
recursion-desired bit unset. Instead to returning SERVFAIL, we
now always forward, and never answer from the cache. This
allows "dig +trace" command to work.
2018-09-19 22:27:11 +01:00
Simon Kelley 51cc10fa54 Add warning about 0.0.0.0 and :: addresses to man page. 2018-09-19 12:49:43 +01:00
Simon Kelley ea6cc33804 Handle memory allocation failure in make_non_terminals()
Thanks to Kristian Evensen for spotting the problem.
2018-09-18 23:21:17 +01:00
Simon Kelley ad03967ee4 Add debian/tmpfiles.conf 2018-09-17 23:54:13 +01:00
Simon Kelley f4fd07d303 Debian bugfix. 2018-09-17 23:45:32 +01:00
Simon Kelley e3c08a34a7 Debian packaging fix. (restorecon) 2018-09-17 23:20:00 +01:00
Simon Kelley 118011fe2b Debian packaging fix. (tmpfiles.d) 2018-09-17 23:15:37 +01:00
9 changed files with 46 additions and 26 deletions

No files matched your search

+6 -1
View File
@@ -59,7 +59,12 @@ version 2.80
Returning null addresses is a useful technique for ad-blocking.
Thanks to Peter Russell for the suggestion.
Change anti cache-snooping behaviour with queries with the
recursion-desired bit unset. Instead to returning SERVFAIL, we
now always forward, and never answer from the cache. This
allows "dig +trace" command to work.
version 2.79
Fix parsing of CNAME arguments, which are confused by extra spaces.
Thanks to Diego Aguirre for spotting the bug.
+9
View File
@@ -1,3 +1,12 @@
dnsmasq (2.80-1) unstable; urgency=low
* New upstream. (closes: #837602) (closes: #794640) (closes: #794636)
* Close old bugs, long agp fixed. (closes: #802845) (closes: #754299)
* Provide usr/lib/tmpfiles.d/dnsmasq.conf. (closes: #872396)
* Run restorecon on /run/dnsmasq for SE Linux. (closes: #872397)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 17 Sep 2018 23:11:25 +0000
dnsmasq (2.79-1) unstable; urgency=low
* New upstream. (closes: #888200)
Vendored
+2 -1
View File
@@ -127,7 +127,8 @@ start()
mkdir /run/dnsmasq || return 2
chown dnsmasq:nogroup /run/dnsmasq || return 2
fi
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/$NAME.pid --exec $DAEMON -- \
-x /run/dnsmasq/$NAME.pid \
+2
View File
@@ -169,6 +169,7 @@ binary-indep: checkroot
-d debian/trees/daemon/usr/share/dnsmasq \
-d debian/trees/daemon/etc/default \
-d debian/trees/daemon/lib/systemd/system \
-d debian/trees/daemon/usr/lib/tmpfiles.d \
-d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
@@ -180,6 +181,7 @@ binary-indep: checkroot
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
+1
View File
@@ -0,0 +1 @@
d /run/dnsmasq 755 dnsmasq nogroup
+1 -1
View File
@@ -515,7 +515,7 @@ address of 0.0.0.0 and its IPv6 equivalent of :: so
\fB--address=/example.com/#\fP will return NULL addresses for example.com and
its subdomains. This is partly syntactic sugar for \fB--address=/example.com/0.0.0.0\fP
and \fB--address=/example.com/::\fP but is also more efficient than including both
as seperate configuration lines.
as seperate configuration lines. Note that NULL addresses normally work in the same way as localhost, so beware that clients looking up these names are likely to end up talking to themselves.
.TP
.B --ipset=/<domain>[/<domain>...]/<ipset>[,<ipset>...]
Places the resolved IP addresses of queries for one or more domains in
+19 -18
View File
@@ -825,7 +825,7 @@ static void add_hosts_cname(struct crec *target)
for (a = daemon->cnames; a; a = a->next)
if (a->alias[1] != '*' &&
hostname_isequal(cache_get_name(target), a->target) &&
(crec = whine_malloc(sizeof(struct crec))))
(crec = whine_malloc(SIZEOF_POINTER_CREC)))
{
crec->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_CONFIG | F_CNAME;
crec->ttd = a->ttl;
@@ -1029,8 +1029,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
{
/* If set, add a version of the name with a default domain appended */
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
(cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 2 + strlen(domain_suffix))))
{
strcpy(cache->name.sname, canon);
strcat(cache->name.sname, ".");
@@ -1040,7 +1039,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
if ((cache = whine_malloc(SIZEOF_BARE_CREC + strlen(canon) + 1)))
{
strcpy(cache->name.sname, canon);
cache->flags = flags;
@@ -1113,7 +1112,7 @@ void cache_reload(void)
for (intr = daemon->int_names; intr; intr = intr->next)
if (a->alias[1] != '*' &&
hostname_isequal(a->target, intr->name) &&
((cache = whine_malloc(sizeof(struct crec)))))
((cache = whine_malloc(SIZEOF_POINTER_CREC))))
{
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
cache->ttd = a->ttl;
@@ -1128,7 +1127,7 @@ void cache_reload(void)
#ifdef HAVE_DNSSEC
for (ds = daemon->ds; ds; ds = ds->next)
if ((cache = whine_malloc(sizeof(struct crec))) &&
if ((cache = whine_malloc(SIZEOF_POINTER_CREC)) &&
(cache->addr.ds.keydata = blockdata_alloc(ds->digest, ds->digestlen)))
{
cache->flags = F_FORWARD | F_IMMORTAL | F_DS | F_CONFIG | F_NAMEP;
@@ -1155,7 +1154,7 @@ void cache_reload(void)
for (nl = hr->names; nl; nl = nl->next)
{
if (hr->addr.s_addr != 0 &&
(cache = whine_malloc(sizeof(struct crec))))
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
{
cache->name.namep = nl->name;
cache->ttd = hr->ttl;
@@ -1164,7 +1163,7 @@ void cache_reload(void)
}
#ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
(cache = whine_malloc(sizeof(struct crec))))
(cache = whine_malloc(SIZEOF_POINTER_CREC)))
{
cache->name.namep = nl->name;
cache->ttd = hr->ttl;
@@ -1241,7 +1240,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
aliasc = whine_malloc(sizeof(struct crec));
aliasc = whine_malloc(SIZEOF_POINTER_CREC);
if (aliasc)
{
@@ -1332,7 +1331,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
crec = whine_malloc(sizeof(struct crec));
crec = whine_malloc(SIZEOF_POINTER_CREC);
if (crec) /* malloc may fail */
{
@@ -1360,7 +1359,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
static void make_non_terminals(struct crec *source)
{
char *name = cache_get_name(source);
struct crec* crecp, *tmp, **up;
struct crec *crecp, *tmp, **up;
int type = F_HOSTS | F_CONFIG;
#ifdef HAVE_DHCP
if (source->flags & F_DHCP)
@@ -1432,14 +1431,16 @@ static void make_non_terminals(struct crec *source)
}
else
#endif
crecp = whine_malloc(sizeof(struct crec));
crecp = whine_malloc(SIZEOF_POINTER_CREC);
*crecp = *source;
crecp->flags &= ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
crecp->flags |= F_NAMEP;
crecp->name.namep = name;
cache_hash(crecp);
if (crecp)
{
crecp->flags = (source->flags | F_NAMEP) & ~(F_IPV4 | F_IPV6 | F_CNAME | F_DNSKEY | F_DS | F_REVERSE);
crecp->ttd = source->ttd;
crecp->name.namep = name;
cache_hash(crecp);
}
}
}
+3
View File
@@ -442,6 +442,9 @@ struct crec {
} name;
};
#define SIZEOF_BARE_CREC (sizeof(struct crec) - SMALLDNAME)
#define SIZEOF_POINTER_CREC (sizeof(struct crec) + sizeof(char *) - SMALLDNAME)
#define F_IMMORTAL (1u<<0)
#define F_NAMEP (1u<<1)
#define F_REVERSE (1u<<2)
+3 -5
View File
@@ -1293,16 +1293,14 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct mx_srv_record *rec;
size_t len;
if (ntohs(header->ancount) != 0 ||
/* never answer queries with RD unset, to avoid cache snooping. */
if (!(header->hb3 & HB3_RD) ||
ntohs(header->ancount) != 0 ||
ntohs(header->nscount) != 0 ||
ntohs(header->qdcount) == 0 ||
OPCODE(header) != QUERY )
return 0;
/* always servfail queries with RD unset, to avoid cache snooping. */
if (!(header->hb3 & HB3_RD))
return setup_reply(header, qlen, NULL, F_SERVFAIL, 0);
/* Don't return AD set if checking disabled. */
if (header->hb4 & HB4_CD)
sec_data = 0;