Compare commits

..
13 changed files with 192 additions and 67 deletions

No files matched your search

+45
View File
@@ -17,7 +17,52 @@ version 2.69
dnsmasq, [fe80::] with the link-local address.
Thanks to Tsachi Kimeldorfer for championing this.
DNSSEC validation and caching. Dnsmasq needs to be
compiled with this enabled, with
make dnsmasq COPTS=-DHAVE_DNSSEC
this add dependencies on the nettle crypto library and the
gmp maths library. It's possible to have these linked
statically with
make dnsmasq COPTS='-DHAVE_DNSSEC -DHAVE_DNSSEC_STATIC'
which bloats the dnsmasq binary to over a megabyte, but
saves the size of the shared libraries which are five
times that size.
To enable, DNSSEC, you will need a set of
trust-anchors. Now that the TLDs are signed, this can be
the keys for the root zone, and for convenience they are
included in trust-anchors.conf in the dnsmasq
distribution. You should of course check that these are
legitimate and up-to-date. So, adding
conf-file=/path/to/trust-anchors.conf
dnssec
to your config is all thats needed to get things
working. The upstream nameservers have to be DNSSEC-capable
too, of course. Many ISP nameservers aren't, but the
Google public nameservers (8.8.8.8 and 8.8.4.4) are.
When DNSSEC is configured, dnsmasq validates any queries
for domains which are signed. Query results which are
bogus are replaced with SERVFAIL replies, and results
which are correctly signed have the AD bit set. In
addition, and just as importantly, dnsmasq supplies
correct DNSSEC information to clients which are doing
their own validation, and caches DNSKEY, DS and RRSIG
records, which significantly improve the performance of
downstream validators. Setting --log-queries will show
DNSSEC in action.
The development of DNSSEC in dnsmasq was started by
Giovanni Bajo, to whom huge thanks are owed. It has been
supported by Comcast, whose techfund grant has allowed for
an invaluable period of full-time work to get it to
a workable state.
version 2.68
Use random addresses for DHCPv6 temporary address
allocations, instead of algorithmically determined stable
+3 -2
View File
@@ -61,6 +61,7 @@ lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CON
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags nettle hogweed`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs nettle hogweed`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
@@ -77,7 +78,7 @@ all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs)" \
-f $(top)/Makefile dnsmasq
mostly_clean :
@@ -101,7 +102,7 @@ all-i18n : $(BUILDDIR)
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) `$(PKG_CONFIG) --libs libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) `$(PKG_CONFIG) --libs libidn`" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
+17 -12
View File
@@ -9,19 +9,24 @@ shift
in=`cat`
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
if [ $op = "--libs" ]; then
pkg=`$pkg --static $op $*`
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
exit 0
fi
fi
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
echo $in | grep $search >/dev/null 2>&1; then
pkg=`$pkg $op $*`
echo "$pkg"
if [ $op = "--copy" ]; then
pkg="$*"
else
pkg=`$pkg $op $*`
fi
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
else
echo "$pkg"
fi
else
echo "$pkg"
fi
fi
@@ -0,0 +1,29 @@
From: Jesse Glick <jglick@cloudbees.com>
To: dnsmasq-discuss@lists.thekelleys.org.uk
Subject: Re: [Dnsmasq-discuss] Ability to delegate to one server but fall
back to another after NXDOMAIN?
On Wed, Jan 15, 2014 at 12:30 PM, Simon Kelley <simon@thekelleys.org.uk> wrote:
> > There's a (very old) patch in contrib/try-all-ns that would make a starting point
This does not apply against trunk, so I tried to rework it. The
following appears to do what I expect:
diff --git a/src/forward.c b/src/forward.c
index 8167229..76070b5 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -610,7 +610,11 @@ void reply_query(int fd, int family, time_t now)
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
!option_bool(OPT_ORDER) &&
- forward->forwardall == 0)
+ forward->forwardall == 0 ||
+ /* try each in turn */
+ RCODE(header) == NXDOMAIN &&
+ option_bool(OPT_ORDER) &&
+ server->next != NULL)
/* for broken servers, attempt to send to another one. */
{
unsigned char *pheader;
+7 -1
View File
@@ -1,7 +1,13 @@
dnsmasq (2.69-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
dnsmasq (2.68-1) unstable; urgency=low
* New upstream. (closes: #730553)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 8 Dec 2013 15:57:32 +0000
dnsmasq (2.67-1) unstable; urgency=low
+2 -1
View File
@@ -1,7 +1,8 @@
Source: dnsmasq
Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev, nettle-dev (>=2.4-3)
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.3
+3 -1
View File
@@ -77,7 +77,7 @@ ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_LUASCRIPT
endif
ifneq (,$(filter usednssec,$(DEB_BUILD_OPTIONS)))
ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DNSSEC
endif
@@ -126,12 +126,14 @@ binary-arch: checkroot
-d debian/base/usr/share/doc/$(package) \
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/var/run \
-d debian/base/usr/share/$(package) \
-d debian/base/var/lib/misc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=gcc
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
install -m 644 trust-anchors.conf debian/base/usr/share/$(package)/.
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
+4
View File
@@ -20,6 +20,10 @@
# Never forward addresses in the non-routed address spaces.
#bogus-priv
# Uncomment these to enable DNSSEC validation and caching:
# (Requires dnsmasq to be built with DNSSEC option.)
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
#dnssec
# Uncomment this to filter useless windows-originated DNS requests
# which can trigger dial-on-demand links needlessly.
+44 -10
View File
@@ -55,7 +55,9 @@ static const struct {
{ 41, "OPT" },
{ 43, "DS" },
{ 46, "RRSIG" },
{ 47, "NSEC" },
{ 48, "DNSKEY" },
{ 50, "NSEC3" },
{ 249, "TKEY" },
{ 250, "TSIG" },
{ 251, "IXFR" },
@@ -592,10 +594,13 @@ void cache_end_insert(void)
new_chain = NULL;
}
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned short prot)
struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsigned int prot)
{
struct crec *ans;
int no_rr = prot & F_NO_RR;
prot &= ~F_NO_RR;
if (crecp) /* iterating */
ans = crecp->next;
else
@@ -643,7 +648,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
}
else
{
if (!insert)
if (!insert && !no_rr)
{
insert = up;
ins_flags = crecp->flags & (F_REVERSE | F_IMMORTAL);
@@ -683,7 +688,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
}
struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
time_t now, unsigned short prot)
time_t now, unsigned int prot)
{
struct crec *ans;
#ifdef HAVE_IPV6
@@ -1298,12 +1303,10 @@ void dump_cache(time_t now)
{
if (cache->flags & F_DNSKEY)
{
char tp[20];
/* RRSIG */
querystr("", tp, cache->addr.sig.type_covered);
a = daemon->addrbuff;
sprintf(a, "%5u %3u %s", cache->addr.sig.keytag,
cache->addr.sig.algo, tp);
cache->addr.sig.algo, querystr("", cache->addr.sig.type_covered));
}
else
{
@@ -1379,14 +1382,45 @@ char *record_source(int index)
return "<unknown>";
}
void querystr(char *desc, char *str, unsigned short type)
char *querystr(char *desc, unsigned short type)
{
unsigned int i;
sprintf(str, "%s[type=%d]", desc, type);
int len = 10; /* strlen("type=xxxxx") */
const char *types = NULL;
static char *buff = NULL;
static int bufflen = 0;
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(str,"%s[%s]", desc, typestr[i].name);
{
types = typestr[i].name;
len = strlen(types);
break;
}
len += 3; /* braces, terminator */
len += strlen(desc);
if (!buff || bufflen < len)
{
if (buff)
free(buff);
else if (len < 20)
len = 20;
buff = whine_malloc(len);
bufflen = len;
}
if (buff)
{
if (types)
sprintf(buff, "%s[%s]", desc, types);
else
sprintf(buff, "%s[type=%d]", desc, type);
}
return buff ? buff : "";
}
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
+4 -3
View File
@@ -423,6 +423,7 @@ struct crec {
#define F_DNSSEC (1u<<22)
#define F_KEYTAG (1u<<23)
#define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25)
/* struct sockaddr is not large enough to hold any address,
@@ -990,12 +991,12 @@ extern struct daemon {
void cache_init(void);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(int index);
void querystr(char *desc, char *str, unsigned short type);
char *querystr(char *desc, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
unsigned short prot);
unsigned int prot);
struct crec *cache_find_by_name(struct crec *crecp,
char *name, time_t now, unsigned short prot);
char *name, time_t now, unsigned int prot);
void cache_end_insert(void);
void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
+8 -5
View File
@@ -505,7 +505,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
j != 0; j--)
{
unsigned char *pstart, *pdata;
int stype, sclass, ttl;
int stype, sclass;
pstart = p;
@@ -514,7 +514,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
GETSHORT(stype, p);
GETSHORT(sclass, p);
GETLONG(ttl, p);
p += 4; /* TTL */
pdata = p;
@@ -531,6 +531,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
{
unsigned char **new;
/* Protect against insane/maliciuos queries which bloat the workspace
and eat CPU in the sort */
if (rrsetidx >= 100)
return STAT_INSECURE;
/* expand */
if (!(new = whine_malloc((rrset_sz + 5) * sizeof(unsigned char **))))
return STAT_INSECURE;
@@ -1382,9 +1387,7 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
{
unsigned char *p;
char types[20];
querystr("dnssec-query", types, type);
char *types = querystr("dnssec-query", type);
if (addr->sa.sa_family == AF_INET)
log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
+3 -6
View File
@@ -1117,13 +1117,11 @@ void receive_query(struct listener *listen, time_t now)
if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{
char types[20];
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
querystr(auth_dns ? "auth" : "query", types, type);
char *types = querystr(auth_dns ? "auth" : "query", type);
if (listen->family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&source_addr.in.sin_addr, types);
@@ -1290,11 +1288,10 @@ unsigned char *tcp_request(int confd, time_t now,
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
{
char types[20];
#ifdef HAVE_AUTH
struct auth_zone *zone;
#endif
querystr(auth_dns ? "auth" : "query", types, qtype);
char *types = querystr(auth_dns ? "auth" : "query", qtype);
if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
+23 -26
View File
@@ -1242,7 +1242,7 @@ int check_for_local_domain(char *name, time_t now)
struct ptr_record *ptr;
struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
@@ -1628,11 +1628,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
(keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)))
{
if (qtype == T_RRSIG)
{
char types[20];
querystr("rrsig", types, crecp->addr.sig.type_covered);
log_query(F_RRNAME, name, NULL, types);
}
log_query(F_RRNAME, name, NULL, querystr("rrsig", crecp->addr.sig.type_covered));
if ((keydata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL)) &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
@@ -1742,24 +1738,25 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
else if (crecp->flags & F_DNSSECOK)
{
int gotsig = 0;
crecp = NULL;
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
struct crec *rr_crec = NULL;
while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
{
if (crecp->addr.sig.type_covered == T_PTR && crecp->uid == C_IN)
if (rr_crec->addr.sig.type_covered == T_PTR && rr_crec->uid == C_IN)
{
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
gotsig = 1;
if (!dryrun &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crecp->ttd - now, &nameoffset,
rr_crec->ttd - now, &nameoffset,
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
anscount++;
}
}
/* Need to re-run original cache search */
crecp = gotsig ? cache_find_by_addr(NULL, &addr, now, is_arpa) : NULL;
if (!gotsig)
crecp = NULL;
}
#endif
}
@@ -1923,7 +1920,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
cname_restart:
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME | (dryrun ? F_NO_RR : 0))))
{
int localise = 0;
@@ -1954,7 +1951,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
else if (crecp->flags & F_DNSSECOK)
{
/* We're returning validated data, need to return the RRSIG too. */
struct crec *rr_crec = NULL;
int sigtype = type;
/* The signature may have expired even though the data is still in cache,
forward instead of answering from cache if so. */
@@ -1963,23 +1960,23 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (crecp->flags & F_CNAME)
sigtype = T_CNAME;
crecp = NULL;
while ((crecp = cache_find_by_name(crecp, name, now, F_DS | F_DNSKEY)))
while ((rr_crec = cache_find_by_name(rr_crec, name, now, F_DS | F_DNSKEY)))
{
if (crecp->addr.sig.type_covered == sigtype && crecp->uid == C_IN)
if (rr_crec->addr.sig.type_covered == sigtype && rr_crec->uid == C_IN)
{
char *sigdata = blockdata_retrieve(crecp->addr.sig.keydata, crecp->addr.sig.keylen, NULL);
char *sigdata = blockdata_retrieve(rr_crec->addr.sig.keydata, rr_crec->addr.sig.keylen, NULL);
gotsig = 1;
if (!dryrun &&
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crecp->ttd - now, &nameoffset,
T_RRSIG, C_IN, "t", crecp->addr.sig.keylen, sigdata))
rr_crec->ttd - now, &nameoffset,
T_RRSIG, C_IN, "t", rr_crec->addr.sig.keylen, sigdata))
anscount++;
}
}
/* Need to re-run original cache search */
crecp = gotsig ? cache_find_by_name(NULL, name, now, flag | F_CNAME) : NULL;
if (!gotsig)
crecp = NULL;
}
#endif
}
@@ -2072,7 +2069,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (qtype == T_CNAME || qtype == T_ANY)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_CNAME)) &&
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))))
(qtype == T_CNAME || (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | (dryrun ? F_NO_RR : 0)))))
{
if (!(crecp->flags & F_DNSSECOK))
sec_data = 0;
@@ -2111,7 +2108,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP | F_NO_RR))
{
ans = 1;
if (!dryrun)