mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-10 16:31:00 +00:00
Compare commits
12
Commits
v2.90test2
...
v2.90test4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c8e5385fd | ||
|
|
3de7289bd6 | ||
|
|
febeea9d01 | ||
|
|
762a3f2430 | ||
|
|
6d35601da4 | ||
|
|
a827127c77 | ||
|
|
d4a6f3a93e | ||
|
|
86c15032ba | ||
|
|
12ddb2a4b9 | ||
|
|
db07664f2a | ||
|
|
1205fc3541 | ||
|
|
3a8ebcac77 |
No files matched your search
@@ -26,6 +26,12 @@ version 2.90
|
|||||||
when the usptream server is a DOH/DOT proxy. Thanks to Justin He
|
when the usptream server is a DOH/DOT proxy. Thanks to Justin He
|
||||||
for the bug report.
|
for the bug report.
|
||||||
|
|
||||||
|
Add configurable caching for arbitrary RR-types.
|
||||||
|
|
||||||
|
Add --filter-rr option, to filter arbitrary RR-types.
|
||||||
|
--filter-rr=ANY has a special meaning: it filters the
|
||||||
|
answers to queries for the ANY RR-type.
|
||||||
|
|
||||||
|
|
||||||
version 2.89
|
version 2.89
|
||||||
Fix bug introduced in 2.88 (commit fe91134b) which can result
|
Fix bug introduced in 2.88 (commit fe91134b) which can result
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ LDFLAGS =
|
|||||||
COPTS =
|
COPTS =
|
||||||
RPM_OPT_FLAGS =
|
RPM_OPT_FLAGS =
|
||||||
LIBS =
|
LIBS =
|
||||||
|
LUA = lua
|
||||||
|
|
||||||
#################################################################
|
#################################################################
|
||||||
|
|
||||||
@@ -60,8 +61,8 @@ idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFI
|
|||||||
idn2_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
|
idn2_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
|
||||||
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||||
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||||
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.4`
|
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags $(LUA)`
|
||||||
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.4`
|
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs $(LUA)`
|
||||||
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
|
||||||
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \
|
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \
|
||||||
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
|
||||||
|
|||||||
Vendored
+5
-3
@@ -1,7 +1,9 @@
|
|||||||
dnsmasq (2.90-1) experimental; urgency=medium
|
dnsmasq (2.90~test4-1) experimental; urgency=medium
|
||||||
|
|
||||||
[ Simon Kelley ]
|
[ Simon Kelley ]
|
||||||
* New upstream. (closes: #1033165)
|
* New upstream. (closes: #1033165)
|
||||||
|
* Move hard-coding of Lua version from the upstream Makefile
|
||||||
|
to d/rules.
|
||||||
[ Sven Geuer ]
|
[ Sven Geuer ]
|
||||||
* Introduce autokpgtests per d/tests/* (closes: #1034135).
|
* Introduce autokpgtests per d/tests/* (closes: #1034135).
|
||||||
* Switch to dpkg-source 3.0 (quilt) format (closes: #1007041).
|
* Switch to dpkg-source 3.0 (quilt) format (closes: #1007041).
|
||||||
@@ -11,7 +13,7 @@ dnsmasq (2.90-1) experimental; urgency=medium
|
|||||||
* Rename d/systemd.service to d/dnsmasq.service.
|
* Rename d/systemd.service to d/dnsmasq.service.
|
||||||
* Rename d/systemd@.service to d/dnsmasq@.service.
|
* Rename d/systemd@.service to d/dnsmasq@.service.
|
||||||
* Refactor d/rules to use the DH sequencer and fix major lintian issues
|
* Refactor d/rules to use the DH sequencer and fix major lintian issues
|
||||||
(closes: #844989, #1040923).
|
(closes: #844989, #1040923, #1063551).
|
||||||
Modified files:
|
Modified files:
|
||||||
- d/rules
|
- d/rules
|
||||||
Complete rewrite making use of debhelper and its tools, fixes lintian
|
Complete rewrite making use of debhelper and its tools, fixes lintian
|
||||||
@@ -78,7 +80,7 @@ dnsmasq (2.90-1) experimental; urgency=medium
|
|||||||
* Introduce d/u/metadata.
|
* Introduce d/u/metadata.
|
||||||
* Fix lintian issue duplicate-short-description.
|
* Fix lintian issue duplicate-short-description.
|
||||||
* Fix lintian issue capitalization-error-in-description.
|
* Fix lintian issue capitalization-error-in-description.
|
||||||
* Bump LUA version to 5.4 (closes: #1050750).
|
* Bump Lua version to 5.4 (closes: #1050750).
|
||||||
Modified files:
|
Modified files:
|
||||||
- d/control
|
- d/control
|
||||||
- d/t/functions.d/log.patterns
|
- d/t/functions.d/log.patterns
|
||||||
|
|||||||
Vendored
+1
-1
@@ -87,7 +87,7 @@ override_dh_auto_install:
|
|||||||
BUILDDIR=debian/auto-build/dnsmasq-base-lua \
|
BUILDDIR=debian/auto-build/dnsmasq-base-lua \
|
||||||
DESTDIR=$(CURDIR)/debian/dnsmasq-base-lua \
|
DESTDIR=$(CURDIR)/debian/dnsmasq-base-lua \
|
||||||
PREFIX=$(PREFIX) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \
|
PREFIX=$(PREFIX) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" \
|
||||||
COPTS="$(COPTS) -DHAVE_LUASCRIPT"
|
LUA=lua5.4 COPTS="$(COPTS) -DHAVE_LUASCRIPT"
|
||||||
dh_auto_build -p dnsmasq-utils -D contrib/lease-tools
|
dh_auto_build -p dnsmasq-utils -D contrib/lease-tools
|
||||||
|
|
||||||
override_dh_auto_clean:
|
override_dh_auto_clean:
|
||||||
|
|||||||
+5
-1
@@ -386,7 +386,11 @@ Remove A records from answers. No IPv4 addresses will be returned.
|
|||||||
Remove AAAA records from answers. No IPv6 addresses will be returned.
|
Remove AAAA records from answers. No IPv6 addresses will be returned.
|
||||||
.TP
|
.TP
|
||||||
.B --filter-rr=<rrtype>[,<rrtype>...]
|
.B --filter-rr=<rrtype>[,<rrtype>...]
|
||||||
Remove records of the specified type(s) from answers.
|
Remove records of the specified type(s) from answers. The otherwise-nonsensical --filter-rr=ANY has
|
||||||
|
a special meaning: it filters replies to queries for type ANY. Everything other than A, AAAA, MX and CNAME
|
||||||
|
records are removed. Since ANY queries with forged source addresses can be used in DNS amplification attacks
|
||||||
|
(replies to ANY queries can be large) this defangs such attacks, whilst still supporting the
|
||||||
|
one remaining possible use of ANY queries. See RFC 8482 para 4.3 for details.
|
||||||
.TP
|
.TP
|
||||||
.B --cache-rr=<rrtype>[,<rrtype>...]
|
.B --cache-rr=<rrtype>[,<rrtype>...]
|
||||||
By default, dnsmasq caches A, AAAA, CNAME and SRV DNS record types.
|
By default, dnsmasq caches A, AAAA, CNAME and SRV DNS record types.
|
||||||
|
|||||||
+13
-13
@@ -802,9 +802,6 @@ void cache_end_insert(void)
|
|||||||
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
|
read_write(daemon->pipe_to_parent, (unsigned char *)name, m, 0);
|
||||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->ttd, sizeof(new_chain->ttd), 0);
|
||||||
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
read_write(daemon->pipe_to_parent, (unsigned char *)&flags, sizeof(flags), 0);
|
||||||
|
|
||||||
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
|
|
||||||
{
|
|
||||||
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
read_write(daemon->pipe_to_parent, (unsigned char *)&new_chain->addr, sizeof(new_chain->addr), 0);
|
||||||
|
|
||||||
if (flags & F_RR)
|
if (flags & F_RR)
|
||||||
@@ -829,7 +826,6 @@ void cache_end_insert(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
new_chain = tmp;
|
new_chain = tmp;
|
||||||
}
|
}
|
||||||
@@ -871,7 +867,8 @@ int cache_recv_insert(time_t now, int fd)
|
|||||||
|
|
||||||
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
|
if (!read_write(fd, (unsigned char *)daemon->namebuff, m, 1) ||
|
||||||
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
|
!read_write(fd, (unsigned char *)&ttd, sizeof(ttd), 1) ||
|
||||||
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1))
|
!read_write(fd, (unsigned char *)&flags, sizeof(flags), 1) ||
|
||||||
|
!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
daemon->namebuff[m] = 0;
|
daemon->namebuff[m] = 0;
|
||||||
@@ -902,11 +899,6 @@ int cache_recv_insert(time_t now, int fd)
|
|||||||
{
|
{
|
||||||
unsigned short class = C_IN;
|
unsigned short class = C_IN;
|
||||||
|
|
||||||
if (flags & (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS | F_RR))
|
|
||||||
{
|
|
||||||
if (!read_write(fd, (unsigned char *)&addr, sizeof(addr), 1))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
if ((flags & F_RR) && !(flags & F_NEG) && (flags & F_KEYTAG)
|
||||||
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
&& !(addr.rrblock.rrdata = blockdata_read(fd, addr.rrblock.datalen)))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -924,8 +916,6 @@ int cache_recv_insert(time_t now, int fd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
crecp = really_insert(daemon->namebuff, &addr, class, now, ttl, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1809,8 +1799,18 @@ static void dump_cache_entry(struct crec *cache, time_t now)
|
|||||||
p = buff;
|
p = buff;
|
||||||
|
|
||||||
*a = 0;
|
*a = 0;
|
||||||
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
|
|
||||||
|
if (cache->flags & F_REVERSE)
|
||||||
|
{
|
||||||
|
if ((cache->flags & F_NEG))
|
||||||
|
n = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strlen(n) == 0)
|
||||||
n = "<Root>";
|
n = "<Root>";
|
||||||
|
}
|
||||||
|
|
||||||
p += sprintf(p, "%-30.30s ", sanitise(n));
|
p += sprintf(p, "%-30.30s ", sanitise(n));
|
||||||
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
|
||||||
a = sanitise(cache_get_cname_target(cache));
|
a = sanitise(cache_get_cname_target(cache));
|
||||||
|
|||||||
+2
-10
@@ -131,20 +131,12 @@ int main (int argc, char **argv)
|
|||||||
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
||||||
presentation format would be twice as long as the spec. */
|
presentation format would be twice as long as the spec. */
|
||||||
daemon->keyname = safe_malloc((MAXDNAME * 2) + 1);
|
daemon->keyname = safe_malloc((MAXDNAME * 2) + 1);
|
||||||
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
|
|
||||||
/* one char flag per possible RR in answer section (may get extended). */
|
/* one char flag per possible RR in answer section (may get extended). */
|
||||||
daemon->rr_status_sz = 64;
|
daemon->rr_status_sz = 64;
|
||||||
daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz);
|
daemon->rr_status = safe_malloc(sizeof(*daemon->rr_status) * daemon->rr_status_sz);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
|
||||||
/* CONNTRACK UBUS code uses this buffer, so if not allocated above,
|
|
||||||
we need to allocate it here. */
|
|
||||||
if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename)
|
|
||||||
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (!daemon->lease_file)
|
if (!daemon->lease_file)
|
||||||
{
|
{
|
||||||
@@ -429,8 +421,8 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_INOTIFY
|
#ifdef HAVE_INOTIFY
|
||||||
if ((daemon->port != 0 || daemon->dhcp || daemon->doing_dhcp6)
|
if ((daemon->port != 0 && !option_bool(OPT_NO_RESOLV)) ||
|
||||||
&& (!option_bool(OPT_NO_RESOLV) || daemon->dynamic_dirs))
|
daemon->dynamic_dirs)
|
||||||
inotify_dnsmasq_init();
|
inotify_dnsmasq_init();
|
||||||
else
|
else
|
||||||
daemon->inotifyfd = -1;
|
daemon->inotifyfd = -1;
|
||||||
|
|||||||
+3
-5
@@ -341,7 +341,7 @@ union all_addr {
|
|||||||
in the cache flags. */
|
in the cache flags. */
|
||||||
struct datablock {
|
struct datablock {
|
||||||
unsigned short rrtype;
|
unsigned short rrtype;
|
||||||
unsigned char datalen;
|
unsigned char datalen; /* also length of SOA in negative records. */
|
||||||
char data[];
|
char data[];
|
||||||
} rrdata;
|
} rrdata;
|
||||||
};
|
};
|
||||||
@@ -1233,10 +1233,7 @@ extern struct daemon {
|
|||||||
char *packet; /* packet buffer */
|
char *packet; /* packet buffer */
|
||||||
int packet_buff_sz; /* size of above */
|
int packet_buff_sz; /* size of above */
|
||||||
char *namebuff; /* MAXDNAME size buffer */
|
char *namebuff; /* MAXDNAME size buffer */
|
||||||
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
|
|
||||||
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
|
|
||||||
char *workspacename;
|
char *workspacename;
|
||||||
#endif
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
char *keyname; /* MAXDNAME size buffer */
|
char *keyname; /* MAXDNAME size buffer */
|
||||||
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
|
||||||
@@ -1376,6 +1373,7 @@ int is_name_synthetic(int flags, char *name, union all_addr *addr);
|
|||||||
int is_rev_synth(int flag, union all_addr *addr, char *name);
|
int is_rev_synth(int flag, union all_addr *addr, char *name);
|
||||||
|
|
||||||
/* rfc1035.c */
|
/* rfc1035.c */
|
||||||
|
int do_doctor(struct dns_header *header, size_t qlen, char *namebuff);
|
||||||
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||||
char *name, int isExtract, int extrabytes);
|
char *name, int isExtract, int extrabytes);
|
||||||
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
|
unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes);
|
||||||
@@ -1386,7 +1384,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen,
|
|||||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||||
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
time_t now, struct ipsets *ipsets, struct ipsets *nftsets, int is_sign,
|
||||||
int check_rebind, int no_cache_dnssec, int secure, int *doctored);
|
int check_rebind, int no_cache_dnssec, int secure);
|
||||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
void report_addresses(struct dns_header *header, size_t len, u32 mark);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -1804,7 +1804,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
|||||||
|
|
||||||
When validating replies to DS records, we're only interested in the NSEC{3} RRs in the auth section.
|
When validating replies to DS records, we're only interested in the NSEC{3} RRs in the auth section.
|
||||||
Other RRs in that section missing sigs will not cause am INSECURE reply. We determine this mode
|
Other RRs in that section missing sigs will not cause am INSECURE reply. We determine this mode
|
||||||
is the nons argument is non-NULL.
|
if the nons argument is non-NULL.
|
||||||
*/
|
*/
|
||||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
||||||
int *class, int check_unsigned, int *neganswer, int *nons, int *nsec_ttl)
|
int *class, int check_unsigned, int *neganswer, int *nons, int *nsec_ttl)
|
||||||
|
|||||||
+58
-54
@@ -687,13 +687,12 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
{
|
{
|
||||||
unsigned char *pheader, *sizep;
|
unsigned char *pheader, *sizep;
|
||||||
struct ipsets *ipsets = NULL, *nftsets = NULL;
|
struct ipsets *ipsets = NULL, *nftsets = NULL;
|
||||||
int munged = 0, is_sign;
|
int is_sign;
|
||||||
unsigned int rcode = RCODE(header);
|
unsigned int rcode = RCODE(header);
|
||||||
size_t plen;
|
size_t plen;
|
||||||
|
|
||||||
(void)ad_reqd;
|
(void)ad_reqd;
|
||||||
(void)do_bit;
|
(void)do_bit;
|
||||||
(void)bogusanswer;
|
|
||||||
|
|
||||||
#ifdef HAVE_IPSET
|
#ifdef HAVE_IPSET
|
||||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||||
@@ -782,10 +781,38 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
server->flags |= SERV_WARNED_RECURSIVE;
|
server->flags |= SERV_WARNED_RECURSIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (header->hb3 & HB3_TC)
|
||||||
|
{
|
||||||
|
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
||||||
|
header->ancount = htons(0);
|
||||||
|
header->nscount = htons(0);
|
||||||
|
header->arcount = htons(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(header->hb3 & HB3_TC) && (!bogusanswer || (header->hb4 & HB4_CD)))
|
||||||
|
{
|
||||||
|
if (rcode == NXDOMAIN && extract_request(header, n, daemon->namebuff, NULL) &&
|
||||||
|
(check_for_local_domain(daemon->namebuff, now) || lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL)))
|
||||||
|
{
|
||||||
|
/* if we forwarded a query for a locally known name (because it was for
|
||||||
|
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||||
|
since we know that the domain exists, even if upstream doesn't */
|
||||||
|
header->hb3 |= HB3_AA;
|
||||||
|
SET_RCODE(header, NOERROR);
|
||||||
|
cache_secure = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon->doctors && do_doctor(header, n, daemon->namebuff))
|
||||||
|
cache_secure = 0;
|
||||||
|
|
||||||
|
/* check_for_bogus_wildcard() does it's own caching, so
|
||||||
|
don't call extract_addresses() if it triggers. */
|
||||||
if (daemon->bogus_addr && rcode != NXDOMAIN &&
|
if (daemon->bogus_addr && rcode != NXDOMAIN &&
|
||||||
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
|
check_for_bogus_wildcard(header, n, daemon->namebuff, now))
|
||||||
{
|
{
|
||||||
munged = 1;
|
header->ancount = htons(0);
|
||||||
|
header->nscount = htons(0);
|
||||||
|
header->arcount = htons(0);
|
||||||
SET_RCODE(header, NXDOMAIN);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
header->hb3 &= ~HB3_AA;
|
header->hb3 &= ~HB3_AA;
|
||||||
cache_secure = 0;
|
cache_secure = 0;
|
||||||
@@ -793,62 +820,50 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int doctored = 0;
|
int rc = extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure);
|
||||||
|
|
||||||
if (rcode == NXDOMAIN &&
|
if (rc != 0)
|
||||||
extract_request(header, n, daemon->namebuff, NULL))
|
|
||||||
{
|
{
|
||||||
if (check_for_local_domain(daemon->namebuff, now) ||
|
header->ancount = htons(0);
|
||||||
lookup_domain(daemon->namebuff, F_CONFIG, NULL, NULL))
|
header->nscount = htons(0);
|
||||||
{
|
header->arcount = htons(0);
|
||||||
/* if we forwarded a query for a locally known name (because it was for
|
|
||||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
|
||||||
since we know that the domain exists, even if upstream doesn't */
|
|
||||||
munged = 1;
|
|
||||||
header->hb3 |= HB3_AA;
|
|
||||||
SET_RCODE(header, NOERROR);
|
|
||||||
cache_secure = 0;
|
cache_secure = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
|
if (rc == 1)
|
||||||
{
|
{
|
||||||
case 1:
|
|
||||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||||
munged = 1;
|
|
||||||
cache_secure = 0;
|
|
||||||
ede = EDE_BLOCKED;
|
ede = EDE_BLOCKED;
|
||||||
break;
|
|
||||||
|
|
||||||
/* extract_addresses() found a malformed answer. */
|
|
||||||
case 2:
|
|
||||||
munged = 1;
|
|
||||||
SET_RCODE(header, SERVFAIL);
|
|
||||||
cache_secure = 0;
|
|
||||||
ede = EDE_OTHER;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rcode == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
|
if (rc == 2)
|
||||||
ede = EDE_FILTERED;
|
{
|
||||||
|
/* extract_addresses() found a malformed answer. */
|
||||||
|
SET_RCODE(header, SERVFAIL);
|
||||||
|
ede = EDE_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (doctored)
|
if (RCODE(header) == NOERROR && rrfilter(header, &n, RRFILTER_CONF) > 0)
|
||||||
cache_secure = 0;
|
ede = EDE_FILTERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (bogusanswer && !(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
|
{
|
||||||
|
if (bogusanswer)
|
||||||
|
{
|
||||||
|
if (!(header->hb4 & HB4_CD) && !option_bool(OPT_DNSSEC_DEBUG))
|
||||||
{
|
{
|
||||||
/* Bogus reply, turn into SERVFAIL */
|
/* Bogus reply, turn into SERVFAIL */
|
||||||
SET_RCODE(header, SERVFAIL);
|
SET_RCODE(header, SERVFAIL);
|
||||||
munged = 1;
|
header->ancount = htons(0);
|
||||||
|
header->nscount = htons(0);
|
||||||
|
header->arcount = htons(0);
|
||||||
|
ede = EDE_DNSSEC_BOGUS;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
||||||
{
|
|
||||||
header->hb4 &= ~HB4_AD;
|
|
||||||
|
|
||||||
if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
|
|
||||||
header->hb4 |= HB4_AD;
|
header->hb4 |= HB4_AD;
|
||||||
|
|
||||||
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
|
||||||
@@ -857,19 +872,8 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
/* the code above can elide sections of the packet. Find the new length here
|
||||||
nameserver info. */
|
and put back pseudoheader if it was removed. */
|
||||||
if (munged)
|
|
||||||
{
|
|
||||||
header->ancount = htons(0);
|
|
||||||
header->nscount = htons(0);
|
|
||||||
header->arcount = htons(0);
|
|
||||||
header->hb3 &= ~HB3_TC;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
|
|
||||||
sections of the packet. Find the new length here and put back pseudoheader
|
|
||||||
if it was removed. */
|
|
||||||
n = resize_packet(header, n, pheader, plen);
|
n = resize_packet(header, n, pheader, plen);
|
||||||
|
|
||||||
if (pheader && ede != EDE_UNSET)
|
if (pheader && ede != EDE_UNSET)
|
||||||
|
|||||||
+1
-1
@@ -94,7 +94,7 @@ void inotify_dnsmasq_init()
|
|||||||
if (daemon->inotifyfd == -1)
|
if (daemon->inotifyfd == -1)
|
||||||
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
die(_("failed to create inotify: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
if (option_bool(OPT_NO_RESOLV))
|
if (daemon->port == 0 || option_bool(OPT_NO_RESOLV))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (res = daemon->resolv_files; res; res = res->next)
|
for (res = daemon->resolv_files; res; res = res->next)
|
||||||
|
|||||||
@@ -5844,6 +5844,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
daemon = opt_malloc(sizeof(struct daemon));
|
daemon = opt_malloc(sizeof(struct daemon));
|
||||||
memset(daemon, 0, sizeof(struct daemon));
|
memset(daemon, 0, sizeof(struct daemon));
|
||||||
daemon->namebuff = buff;
|
daemon->namebuff = buff;
|
||||||
|
daemon->workspacename = safe_malloc((MAXDNAME * 2) + 1);
|
||||||
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||||
|
|
||||||
/* Set defaults - everything else is zero or NULL */
|
/* Set defaults - everything else is zero or NULL */
|
||||||
|
|||||||
+242
-120
@@ -384,14 +384,23 @@ static int private_net6(struct in6_addr *a, int ban_localhost)
|
|||||||
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
|
((u32 *)a)[0] == htonl(0x20010db8); /* RFC 6303 4.6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, int *doctored)
|
int do_doctor(struct dns_header *header, size_t qlen, char *namebuff)
|
||||||
{
|
{
|
||||||
|
unsigned char *p;
|
||||||
int i, qtype, qclass, rdlen;
|
int i, qtype, qclass, rdlen;
|
||||||
|
int done = 0;
|
||||||
|
|
||||||
for (i = count; i != 0; i--)
|
if (!(p = skip_questions(header, qlen)))
|
||||||
|
return done;
|
||||||
|
|
||||||
|
for (i = 0; i < ntohs(header->ancount) + ntohs(header->arcount); i++)
|
||||||
{
|
{
|
||||||
if (!(p = skip_name(p, header, qlen, 10)))
|
/* Skip over auth section */
|
||||||
return 0; /* bad packet */
|
if (i == ntohs(header->ancount) && !(p = skip_section(p, ntohs(header->nscount), header, qlen)))
|
||||||
|
return done;
|
||||||
|
|
||||||
|
if (!extract_name(header, qlen, &p, namebuff, 1, 10))
|
||||||
|
return done; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
@@ -401,57 +410,77 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
|
|||||||
if (qclass == C_IN && qtype == T_A)
|
if (qclass == C_IN && qtype == T_A)
|
||||||
{
|
{
|
||||||
struct doctor *doctor;
|
struct doctor *doctor;
|
||||||
struct in_addr addr;
|
union all_addr addr;
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
|
||||||
return 0;
|
return done;
|
||||||
|
|
||||||
/* alignment */
|
/* alignment */
|
||||||
memcpy(&addr, p, INADDRSZ);
|
memcpy(&addr.addr4, p, INADDRSZ);
|
||||||
|
|
||||||
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
|
for (doctor = daemon->doctors; doctor; doctor = doctor->next)
|
||||||
{
|
{
|
||||||
if (doctor->end.s_addr == 0)
|
if (doctor->end.s_addr == 0)
|
||||||
{
|
{
|
||||||
if (!is_same_net(doctor->in, addr, doctor->mask))
|
if (!is_same_net(doctor->in, addr.addr4, doctor->mask))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
|
else if (ntohl(doctor->in.s_addr) > ntohl(addr.addr4.s_addr) ||
|
||||||
ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
|
ntohl(doctor->end.s_addr) < ntohl(addr.addr4.s_addr))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
addr.s_addr &= ~doctor->mask.s_addr;
|
addr.addr4.s_addr &= ~doctor->mask.s_addr;
|
||||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
addr.addr4.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||||
header->hb3 &= ~HB3_AA;
|
header->hb3 &= ~HB3_AA;
|
||||||
*doctored = 1;
|
#ifdef HAVE_DNSSEC
|
||||||
memcpy(p, &addr, INADDRSZ);
|
/* remove validated flag from this RR, since we changed it! */
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && i < ntohs(header->ancount))
|
||||||
|
daemon->rr_status[i] = 0;
|
||||||
|
#endif
|
||||||
|
done = 1;
|
||||||
|
memcpy(p, &addr.addr4, INADDRSZ);
|
||||||
|
log_query(F_FORWARD | F_CONFIG | F_IPV4, namebuff, &addr, NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ADD_RDLEN(header, p, qlen, rdlen))
|
if (!ADD_RDLEN(header, p, qlen, rdlen))
|
||||||
return 0; /* bad packet */
|
return done; /* bad packet */
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_soa(struct dns_header *header, size_t qlen, int *doctored)
|
/* Find SOA RR in auth section to get TTL for negative caching of name.
|
||||||
|
Cache said SOA and return the difference in length between name and the name of the
|
||||||
|
SOA RR so we can look it up again.
|
||||||
|
*/
|
||||||
|
static int find_soa(struct dns_header *header, size_t qlen, char *name, int *substring, unsigned long *ttlp, int no_cache, time_t now)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p, *psave;
|
||||||
int qtype, qclass, rdlen;
|
int qtype, qclass, rdlen;
|
||||||
unsigned long ttl, minttl = ULONG_MAX;
|
unsigned long ttl, minttl;
|
||||||
int i, found_soa = 0;
|
int i, j;
|
||||||
|
size_t name_len, soa_len, len;
|
||||||
|
union all_addr addr;
|
||||||
|
|
||||||
/* first move to NS section and find TTL from any SOA section */
|
/* first move to NS section and find TTL from SOA RR */
|
||||||
if (!(p = skip_questions(header, qlen)) ||
|
if (!(p = skip_questions(header, qlen)) ||
|
||||||
!(p = do_doctor(p, ntohs(header->ancount), header, qlen, doctored)))
|
!(p = skip_section(p, ntohs(header->ancount), header, qlen)))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
|
|
||||||
for (i = ntohs(header->nscount); i != 0; i--)
|
name_len = strlen(name);
|
||||||
|
|
||||||
|
if (substring)
|
||||||
|
*substring = name_len;
|
||||||
|
|
||||||
|
if (ttlp)
|
||||||
|
*ttlp = daemon->neg_ttl;
|
||||||
|
|
||||||
|
for (i = 0; i < ntohs(header->nscount); i++)
|
||||||
{
|
{
|
||||||
if (!(p = skip_name(p, header, qlen, 10)))
|
if (!extract_name(header, qlen, &p, daemon->workspacename, 1, 0))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
@@ -459,40 +488,112 @@ static int find_soa(struct dns_header *header, size_t qlen, int *doctored)
|
|||||||
GETLONG(ttl, p);
|
GETLONG(ttl, p);
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
|
psave = p;
|
||||||
|
|
||||||
if ((qclass == C_IN) && (qtype == T_SOA))
|
if ((qclass == C_IN) && (qtype == T_SOA))
|
||||||
{
|
{
|
||||||
found_soa = 1;
|
soa_len = strlen(daemon->workspacename);
|
||||||
if (ttl < minttl)
|
|
||||||
minttl = ttl;
|
|
||||||
|
|
||||||
/* MNAME */
|
/* SOA must be for the name we're interested in. */
|
||||||
if (!(p = skip_name(p, header, qlen, 0)))
|
if (soa_len <= name_len && memcmp(daemon->workspacename, name + name_len - soa_len, soa_len) == 0)
|
||||||
|
{
|
||||||
|
int prefix = name_len - soa_len;
|
||||||
|
|
||||||
|
if (!no_cache)
|
||||||
|
{
|
||||||
|
if (!(addr.rrblock.rrdata = blockdata_alloc(NULL, 0)))
|
||||||
return 0;
|
return 0;
|
||||||
/* RNAME */
|
addr.rrblock.rrtype = T_SOA;
|
||||||
if (!(p = skip_name(p, header, qlen, 20)))
|
addr.rrblock.datalen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < 2; j++) /* MNAME, RNAME */
|
||||||
|
{
|
||||||
|
if (!extract_name(header, qlen, &p, daemon->workspacename, 1, 0))
|
||||||
|
{
|
||||||
|
if (!no_cache)
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!no_cache)
|
||||||
|
{
|
||||||
|
len = to_wire(daemon->workspacename);
|
||||||
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
|
||||||
|
{
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.rrblock.datalen += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CHECK_LEN(header, p, qlen, 20))
|
||||||
|
{
|
||||||
|
if (!no_cache)
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rest of RR */
|
||||||
|
if (!no_cache && !blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
|
||||||
|
{
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr.rrblock.datalen += 20;
|
||||||
|
|
||||||
|
if (!no_cache)
|
||||||
|
{
|
||||||
|
int secflag = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[i + ntohs(header->ancount)] != 0)
|
||||||
|
{
|
||||||
|
secflag = F_DNSSECOK;
|
||||||
|
|
||||||
|
/* limit TTL based on signature. */
|
||||||
|
if (daemon->rr_status[i + ntohs(header->ancount)] < ttl)
|
||||||
|
ttl = daemon->rr_status[i + ntohs(header->ancount)];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!cache_insert(name + prefix, &addr, C_IN, now, ttl, F_FORWARD | F_RR | F_KEYTAG | secflag))
|
||||||
|
{
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
|
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
|
||||||
|
|
||||||
GETLONG(ttl, p); /* minTTL */
|
GETLONG(minttl, p); /* minTTL */
|
||||||
if (ttl < minttl)
|
if (ttl < minttl)
|
||||||
minttl = ttl;
|
minttl = ttl;
|
||||||
|
|
||||||
|
if (substring)
|
||||||
|
*substring = prefix;
|
||||||
|
|
||||||
|
if (ttlp)
|
||||||
|
*ttlp = minttl;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
else if (!ADD_RDLEN(header, p, qlen, rdlen))
|
}
|
||||||
|
|
||||||
|
p = psave;
|
||||||
|
|
||||||
|
if (!ADD_RDLEN(header, p, qlen, rdlen))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* rewrite addresses in additional section too */
|
|
||||||
if (!do_doctor(p, ntohs(header->arcount), header, qlen, doctored))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!found_soa)
|
|
||||||
minttl = daemon->neg_ttl;
|
|
||||||
|
|
||||||
return minttl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print TXT reply to log */
|
/* Print TXT reply to log */
|
||||||
static int log_txt(char *name, unsigned char *p, const int ardlen, int secflag)
|
static int log_txt(char *name, unsigned char *p, const int ardlen, int flag)
|
||||||
{
|
{
|
||||||
unsigned char *p1 = p;
|
unsigned char *p1 = p;
|
||||||
|
|
||||||
@@ -514,7 +615,7 @@ static int log_txt(char *name, unsigned char *p, const int ardlen, int secflag)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*p3 = 0;
|
*p3 = 0;
|
||||||
log_query(secflag | F_FORWARD, name, NULL, (char*)p1, 0);
|
log_query(flag, name, NULL, (char*)p1, 0);
|
||||||
/* restore */
|
/* restore */
|
||||||
memmove(p1 + 1, p1, i);
|
memmove(p1 + 1, p1, i);
|
||||||
*p1 = len;
|
*p1 = len;
|
||||||
@@ -531,10 +632,10 @@ static int log_txt(char *name, unsigned char *p, const int ardlen, int secflag)
|
|||||||
*/
|
*/
|
||||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||||
struct ipsets *ipsets, struct ipsets *nftsets, int is_sign, int check_rebind,
|
struct ipsets *ipsets, struct ipsets *nftsets, int is_sign, int check_rebind,
|
||||||
int no_cache_dnssec, int secure, int *doctored)
|
int no_cache_dnssec, int secure)
|
||||||
{
|
{
|
||||||
unsigned char *p, *p1, *endrr, *namep;
|
unsigned char *p, *p1, *endrr, *namep;
|
||||||
int j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
int j, qtype, qclass, aqtype, aqclass, ardlen, res;
|
||||||
unsigned long ttl = 0;
|
unsigned long ttl = 0;
|
||||||
union all_addr addr;
|
union all_addr addr;
|
||||||
#ifdef HAVE_IPSET
|
#ifdef HAVE_IPSET
|
||||||
@@ -557,25 +658,6 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
cache_start_insert();
|
cache_start_insert();
|
||||||
|
|
||||||
/* find_soa is needed for dns_doctor side effects, so don't call it lazily if there are any. */
|
|
||||||
if (daemon->doctors || option_bool(OPT_DNSSEC_VALID))
|
|
||||||
{
|
|
||||||
searched_soa = 1;
|
|
||||||
ttl = find_soa(header, qlen, doctored);
|
|
||||||
|
|
||||||
if (*doctored)
|
|
||||||
{
|
|
||||||
if (secure)
|
|
||||||
return 0;
|
|
||||||
#ifdef HAVE_DNSSEC
|
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
|
||||||
for (j = 0; j < ntohs(header->ancount); j++)
|
|
||||||
if (daemon->rr_status[j] != 0)
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namep = p = (unsigned char *)(header+1);
|
namep = p = (unsigned char *)(header+1);
|
||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 || !extract_name(header, qlen, &p, name, 1, 4))
|
if (ntohs(header->qdcount) != 1 || !extract_name(header, qlen, &p, name, 1, 4))
|
||||||
@@ -624,7 +706,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
|
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && !no_cache_dnssec && daemon->rr_status[j] != 0)
|
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
|
||||||
{
|
{
|
||||||
/* validated RR anywhere in CNAME chain, don't cache. */
|
/* validated RR anywhere in CNAME chain, don't cache. */
|
||||||
if (cname_short || aqtype == T_CNAME)
|
if (cname_short || aqtype == T_CNAME)
|
||||||
@@ -673,17 +755,16 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
if (!found && !option_bool(OPT_NO_NEG))
|
if (!found && !option_bool(OPT_NO_NEG))
|
||||||
{
|
{
|
||||||
if (!searched_soa)
|
/* For reverse records, we use the name field to store the SOA name. */
|
||||||
{
|
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
||||||
searched_soa = 1;
|
|
||||||
ttl = find_soa(header, qlen, doctored);
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= F_NEG | (secure ? F_DNSSECOK : 0);
|
flags |= F_NEG | (secure ? F_DNSSECOK : 0);
|
||||||
if (name_encoding && ttl)
|
if (name_encoding && ttl)
|
||||||
{
|
{
|
||||||
flags |= F_REVERSE | name_encoding;
|
flags |= F_REVERSE | name_encoding;
|
||||||
cache_insert(NULL, &addr, C_IN, now, ttl, flags);
|
if (!have_soa)
|
||||||
|
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||||
|
cache_insert(name + substring, &addr, C_IN, now, ttl, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
log_query(flags | F_UPSTREAM, name, &addr, NULL, 0);
|
log_query(flags | F_UPSTREAM, name, &addr, NULL, 0);
|
||||||
@@ -705,7 +786,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
addrlen = IN6ADDRSZ;
|
addrlen = IN6ADDRSZ;
|
||||||
flags |= F_IPV6;
|
flags |= F_IPV6;
|
||||||
}
|
}
|
||||||
else if (qtype != T_CNAME && (qtype == T_SRV || rr_on_list(daemon->cache_rr, qtype)))
|
else if (qtype != T_CNAME &&
|
||||||
|
(qtype == T_SRV || rr_on_list(daemon->cache_rr, qtype) || rr_on_list(daemon->cache_rr, T_ANY)))
|
||||||
flags |= F_RR;
|
flags |= F_RR;
|
||||||
else
|
else
|
||||||
insert = 0; /* NOTE: do not cache data from CNAME queries. */
|
insert = 0; /* NOTE: do not cache data from CNAME queries. */
|
||||||
@@ -732,17 +814,18 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
GETSHORT(ardlen, p1);
|
GETSHORT(ardlen, p1);
|
||||||
endrr = p1+ardlen;
|
endrr = p1+ardlen;
|
||||||
|
|
||||||
|
if (!CHECK_LEN(header, endrr, qlen, 0))
|
||||||
|
return 2; /* bad packet */
|
||||||
|
|
||||||
/* Not what we're looking for? */
|
/* Not what we're looking for? */
|
||||||
if (aqclass != C_IN || res == 2)
|
if (aqclass != C_IN || res == 2)
|
||||||
{
|
{
|
||||||
p1 = endrr;
|
p1 = endrr;
|
||||||
if (!CHECK_LEN(header, p1, qlen, 0))
|
|
||||||
return 2; /* bad packet */
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID) && !no_cache_dnssec && daemon->rr_status[j] != 0)
|
if (option_bool(OPT_DNSSEC_VALID) && daemon->rr_status[j] != 0)
|
||||||
{
|
{
|
||||||
secflag = F_DNSSECOK;
|
secflag = F_DNSSECOK;
|
||||||
|
|
||||||
@@ -787,11 +870,12 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
else if (aqtype != qtype)
|
else if (qtype == T_ANY || aqtype != qtype)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (!option_bool(OPT_DNSSEC_VALID) || aqtype != T_RRSIG)
|
if (!option_bool(OPT_DNSSEC_VALID) || aqtype != T_RRSIG)
|
||||||
#endif
|
#endif
|
||||||
|
if (qtype != T_ANY)
|
||||||
log_query(secflag | F_FORWARD | F_UPSTREAM | F_RRNAME, name, NULL, NULL, aqtype);
|
log_query(secflag | F_FORWARD | F_UPSTREAM | F_RRNAME, name, NULL, NULL, aqtype);
|
||||||
}
|
}
|
||||||
else if (!(flags & F_NXDOMAIN))
|
else if (!(flags & F_NXDOMAIN))
|
||||||
@@ -838,7 +922,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
{
|
{
|
||||||
/* Copy the rest of the RR and end. */
|
/* Copy the rest of the RR and end. */
|
||||||
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1))
|
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1))
|
||||||
|
{
|
||||||
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
addr.rrblock.datalen += endrr - p1;
|
addr.rrblock.datalen += endrr - p1;
|
||||||
}
|
}
|
||||||
else if (desc == 0)
|
else if (desc == 0)
|
||||||
@@ -935,26 +1022,17 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
blockdata_free(addr.rrblock.rrdata);
|
blockdata_free(addr.rrblock.rrdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aqtype == T_TXT)
|
|
||||||
{
|
|
||||||
if (!CHECK_LEN(header, p1, qlen, ardlen))
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
log_txt(name, p1, ardlen, secflag | F_UPSTREAM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int negflag = F_UPSTREAM;
|
|
||||||
|
|
||||||
/* We're filtering this RRtype. It will be removed from the
|
/* We're filtering this RRtype. It will be removed from the
|
||||||
returned packet in process_reply() but gets cached here anyway
|
returned packet in process_reply() but gets cached here anyway
|
||||||
and will be filtered again on the way out of the cache. Here,
|
and will be filtered again on the way out of the cache. Here,
|
||||||
we just need to alter the logging. */
|
we just need to alter the logging. */
|
||||||
if (rr_on_list(daemon->filter_rr, qtype))
|
if (qtype != T_ANY && rr_on_list(daemon->filter_rr, qtype))
|
||||||
negflag = F_NEG | F_CONFIG;
|
secflag = F_NEG | F_CONFIG;
|
||||||
|
|
||||||
log_query(negflag | flags | F_FORWARD | secflag, name, &addr, NULL, aqtype);
|
if (aqtype == T_TXT)
|
||||||
}
|
log_txt(name, p1, ardlen, flags | F_FORWARD | F_UPSTREAM | secflag);
|
||||||
|
else
|
||||||
|
log_query(flags | F_FORWARD | F_UPSTREAM | secflag, name, &addr, NULL, aqtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
p1 = endrr;
|
p1 = endrr;
|
||||||
@@ -974,22 +1052,24 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
|
|
||||||
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL, 0);
|
log_query(F_UPSTREAM | F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0), name, NULL, NULL, 0);
|
||||||
|
|
||||||
if (!searched_soa)
|
if (insert && !option_bool(OPT_NO_NEG))
|
||||||
{
|
{
|
||||||
searched_soa = 1;
|
int substring, have_soa = find_soa(header, qlen, name, &substring, &ttl, no_cache_dnssec, now);
|
||||||
ttl = find_soa(header, qlen, doctored);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there's no SOA to get the TTL from, but there is a CNAME
|
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||||
pointing at this, inherit its TTL */
|
pointing at this, inherit its TTL */
|
||||||
if (insert && !option_bool(OPT_NO_NEG) && (ttl || cpp))
|
if (ttl || cpp)
|
||||||
{
|
{
|
||||||
if (ttl == 0)
|
if (!ttl)
|
||||||
ttl = cttl;
|
ttl = cttl;
|
||||||
|
|
||||||
if (flags & F_RR)
|
addr.rrdata.datalen = substring;
|
||||||
addr.rrdata.rrtype = qtype;
|
addr.rrdata.rrtype = qtype;
|
||||||
|
|
||||||
|
if (!have_soa)
|
||||||
|
flags |= F_NO_RR; /* Marks no SOA found. */
|
||||||
|
}
|
||||||
|
|
||||||
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
newc = cache_insert(name, &addr, C_IN, now, ttl, F_FORWARD | F_NEG | flags | (secure ? F_DNSSECOK : 0));
|
||||||
if (newc && cpp)
|
if (newc && cpp)
|
||||||
{
|
{
|
||||||
@@ -1001,15 +1081,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->hb3 & HB3_TC)
|
/* Don't cache replies from non-recursive nameservers, since we may get a
|
||||||
log_query(F_UPSTREAM, NULL, NULL, "truncated", 0);
|
|
||||||
|
|
||||||
/* Don't put stuff from a truncated packet into the cache.
|
|
||||||
Don't cache replies from non-recursive nameservers, since we may get a
|
|
||||||
reply containing a CNAME but not its target, even though the target
|
reply containing a CNAME but not its target, even though the target
|
||||||
does exist. */
|
does exist. */
|
||||||
if (!(header->hb3 & HB3_TC) &&
|
if (!(header->hb4 & HB4_CD) &&
|
||||||
!(header->hb4 & HB4_CD) &&
|
|
||||||
(header->hb4 & HB4_RA) &&
|
(header->hb4 & HB4_RA) &&
|
||||||
!no_cache_dnssec)
|
!no_cache_dnssec)
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
@@ -1242,8 +1317,7 @@ static int check_bad_address(struct dns_header *header, size_t qlen, struct bogu
|
|||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
GETLONG(ttl, p);
|
GETLONG(ttl, p);
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p)
|
||||||
|
|
||||||
if (ttlp)
|
if (ttlp)
|
||||||
*ttlp = ttl;
|
*ttlp = ttl;
|
||||||
|
|
||||||
@@ -1296,8 +1370,9 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
|||||||
/* Found a bogus address. Insert that info here, since there no SOA record
|
/* Found a bogus address. Insert that info here, since there no SOA record
|
||||||
to get the ttl from in the normal processing */
|
to get the ttl from in the normal processing */
|
||||||
cache_start_insert();
|
cache_start_insert();
|
||||||
cache_insert(name, NULL, C_IN, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN);
|
cache_insert(name, NULL, C_IN, now, ttl, F_FORWARD | F_NEG | F_NXDOMAIN);
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
|
log_query(F_CONFIG | F_FORWARD | F_NEG | F_NXDOMAIN, name, NULL, NULL, 0);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1500,12 +1575,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
union all_addr addr;
|
union all_addr addr;
|
||||||
int nameoffset;
|
int nameoffset;
|
||||||
unsigned short flag;
|
unsigned short flag;
|
||||||
int q, ans, anscount = 0, addncount = 0;
|
int ans, anscount = 0, nscount = 0, addncount = 0;
|
||||||
struct crec *crecp;
|
struct crec *crecp, *soa_lookup = NULL;
|
||||||
int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
|
int nxdomain = 0, notimp = 0, auth = 1, trunc = 0, sec_data = 1;
|
||||||
struct mx_srv_record *rec;
|
struct mx_srv_record *rec;
|
||||||
size_t len;
|
size_t len;
|
||||||
int rd_bit = (header->hb3 & HB3_RD);
|
int rd_bit = (header->hb3 & HB3_RD);
|
||||||
|
int count = 255; /* catch loops */
|
||||||
|
|
||||||
if (stale)
|
if (stale)
|
||||||
*stale = 0;
|
*stale = 0;
|
||||||
@@ -1514,7 +1590,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
*filtered = 0;
|
*filtered = 0;
|
||||||
|
|
||||||
/* never answer queries with RD unset, to avoid cache snooping. */
|
/* never answer queries with RD unset, to avoid cache snooping. */
|
||||||
if (ntohs(header->ancount) != 0 ||
|
if ( ntohs(header->qdcount) != 1 ||
|
||||||
|
ntohs(header->ancount) != 0 ||
|
||||||
ntohs(header->nscount) != 0 ||
|
ntohs(header->nscount) != 0 ||
|
||||||
ntohs(header->qdcount) == 0 ||
|
ntohs(header->qdcount) == 0 ||
|
||||||
OPCODE(header) != QUERY )
|
OPCODE(header) != QUERY )
|
||||||
@@ -1534,10 +1611,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
/* now process each question, answers go in RRs after the question */
|
/* now process each question, answers go in RRs after the question */
|
||||||
p = (unsigned char *)(header+1);
|
p = (unsigned char *)(header+1);
|
||||||
|
|
||||||
for (q = ntohs(header->qdcount); q != 0; q--)
|
|
||||||
{
|
|
||||||
int count = 255; /* catch loops */
|
|
||||||
|
|
||||||
/* save pointer to name for copying into answers */
|
/* save pointer to name for copying into answers */
|
||||||
nameoffset = p - (unsigned char *)header;
|
nameoffset = p - (unsigned char *)header;
|
||||||
|
|
||||||
@@ -1564,6 +1637,9 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
stale_flag = F_STALE;
|
stale_flag = F_STALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (crecp->flags & F_NEG)
|
||||||
|
soa_lookup = crecp;
|
||||||
|
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
{
|
{
|
||||||
if (qtype == T_CNAME)
|
if (qtype == T_CNAME)
|
||||||
@@ -1768,6 +1844,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (crecp->flags & F_NXDOMAIN)
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0);
|
log_query(stale_flag | (crecp->flags & ~F_FORWARD), name, &addr, NULL, 0);
|
||||||
|
soa_lookup = crecp;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1872,13 +1949,13 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_NXDOMAIN)))
|
if ((crecp = cache_find_by_name(NULL, name, now, flag)))
|
||||||
{
|
{
|
||||||
int localise = 0;
|
int localise = 0;
|
||||||
|
|
||||||
/* See if a putative address is on the network from which we received
|
/* See if a putative address is on the network from which we received
|
||||||
the query, is so we'll filter other answers. */
|
the query, is so we'll filter other answers. */
|
||||||
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
if (!(crecp->flags & F_NEG) && local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
||||||
{
|
{
|
||||||
struct crec *save = crecp;
|
struct crec *save = crecp;
|
||||||
do {
|
do {
|
||||||
@@ -1918,7 +1995,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
auth = 0;
|
auth = 0;
|
||||||
|
|
||||||
if (rr_on_list(daemon->filter_rr, qtype) &&
|
if (qtype != T_ANY && rr_on_list(daemon->filter_rr, qtype) &&
|
||||||
!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | F_NEG)))
|
!(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG | F_NEG)))
|
||||||
{
|
{
|
||||||
/* We have a cached answer but we're filtering it. */
|
/* We have a cached answer but we're filtering it. */
|
||||||
@@ -1931,14 +2008,18 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
*filtered = 1;
|
*filtered = 1;
|
||||||
}
|
}
|
||||||
else if (crecp->flags & F_NEG)
|
else if (crecp->flags & F_NEG)
|
||||||
|
{
|
||||||
|
if (qtype != T_ANY)
|
||||||
{
|
{
|
||||||
ans = 1;
|
ans = 1;
|
||||||
auth = 0;
|
auth = 0;
|
||||||
|
soa_lookup = crecp;
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
|
|
||||||
log_query(stale_flag | crecp->flags, name, NULL, NULL, 0);
|
log_query(stale_flag | crecp->flags, name, NULL, NULL, 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If we are returning local answers depending on network,
|
/* If we are returning local answers depending on network,
|
||||||
@@ -2102,12 +2183,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
if (flags & F_NXDOMAIN)
|
if (flags & F_NXDOMAIN)
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
else if (rr_on_list(daemon->filter_rr, qtype))
|
else if (qtype != T_ANY && rr_on_list(daemon->filter_rr, qtype))
|
||||||
flags |= F_NEG | F_CONFIG;
|
flags |= F_NEG | F_CONFIG;
|
||||||
|
|
||||||
auth = 0;
|
auth = 0;
|
||||||
ans = 1;
|
ans = 1;
|
||||||
|
|
||||||
|
if (flags & F_NEG)
|
||||||
|
soa_lookup = crecp;
|
||||||
|
|
||||||
if (!(flags & F_NEG))
|
if (!(flags & F_NEG))
|
||||||
{
|
{
|
||||||
if (flags & F_KEYTAG)
|
if (flags & F_KEYTAG)
|
||||||
@@ -2144,7 +2228,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!ans && rr_on_list(daemon->filter_rr, qtype))
|
if (qtype != T_ANY && !ans && rr_on_list(daemon->filter_rr, qtype))
|
||||||
{
|
{
|
||||||
/* We don't have a cached answer and when we get an answer from upstream we're going to
|
/* We don't have a cached answer and when we get an answer from upstream we're going to
|
||||||
filter it anyway. If we have a cached answer for the domain for another RRtype then
|
filter it anyway. If we have a cached answer for the domain for another RRtype then
|
||||||
@@ -2168,6 +2252,40 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
if (!ans)
|
if (!ans)
|
||||||
return 0; /* failed to answer a question */
|
return 0; /* failed to answer a question */
|
||||||
|
|
||||||
|
/* We found a negative record. See if we have an SOA record to
|
||||||
|
return in the AUTH section.
|
||||||
|
|
||||||
|
For FORWARD NEG records, the addr.rrdata.datalen field of the othewise
|
||||||
|
empty addr is used to held an offset in to the name which yields the SOA
|
||||||
|
name. For REVERSE NEG records, the otherwise empty name field holds the
|
||||||
|
SOA name. If soa_name has zero length, then no SOA is known. soa_lookup
|
||||||
|
MUST be a neg record here.
|
||||||
|
|
||||||
|
If the F_NO_RR flag is set, there was no SOA record supplied with the RR. */
|
||||||
|
if (soa_lookup && !(soa_lookup->flags & F_NO_RR))
|
||||||
|
{
|
||||||
|
char *soa_name = soa_lookup->flags & F_REVERSE ? cache_get_name(soa_lookup) : name + soa_lookup->addr.rrdata.datalen;
|
||||||
|
|
||||||
|
crecp = NULL;
|
||||||
|
while ((crecp = cache_find_by_name(crecp, soa_name, now, F_RR)))
|
||||||
|
if (crecp->addr.rrblock.rrtype == T_SOA)
|
||||||
|
{
|
||||||
|
char *rrdata;
|
||||||
|
|
||||||
|
if (!(crecp->flags & F_NEG) &&
|
||||||
|
(rrdata = blockdata_retrieve(crecp->addr.rrblock.rrdata, crecp->addr.rrblock.datalen, NULL)) &&
|
||||||
|
add_resource_record(header, limit, &trunc, 0, &ansp,
|
||||||
|
crec_ttl(crecp, now), NULL, T_SOA, C_IN, "t",
|
||||||
|
soa_name, crecp->addr.rrblock.datalen, rrdata))
|
||||||
|
{
|
||||||
|
nscount++;
|
||||||
|
|
||||||
|
if (!(crecp->flags & F_DNSSECOK))
|
||||||
|
sec_data = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create an additional data section, for stuff in SRV and MX record replies. */
|
/* create an additional data section, for stuff in SRV and MX record replies. */
|
||||||
@@ -2191,7 +2309,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
|
if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
|
||||||
crec_ttl(crecp, now), NULL, type, C_IN,
|
crec_ttl(crecp, now), NULL, type, C_IN,
|
||||||
crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
|
crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
|
||||||
|
{
|
||||||
addncount++;
|
addncount++;
|
||||||
|
if (!(crecp->flags & F_DNSSECOK))
|
||||||
|
sec_data = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2216,7 +2338,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
else
|
else
|
||||||
SET_RCODE(header, NOERROR); /* no error */
|
SET_RCODE(header, NOERROR); /* no error */
|
||||||
header->ancount = htons(anscount);
|
header->ancount = htons(anscount);
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(nscount);
|
||||||
header->arcount = htons(addncount);
|
header->arcount = htons(addncount);
|
||||||
|
|
||||||
len = ansp - (unsigned char *)header;
|
len = ansp - (unsigned char *)header;
|
||||||
|
|||||||
@@ -213,6 +213,14 @@ size_t rrfilter(struct dns_header *header, size_t *plen, int mode)
|
|||||||
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (qtype == T_ANY && rr_on_list(daemon->filter_rr, T_ANY))
|
||||||
|
{
|
||||||
|
/* Filter replies to ANY queries in the spirit of
|
||||||
|
RFC RFC 8482 para 4.3 */
|
||||||
|
if (class != C_IN ||
|
||||||
|
type == T_A || type == T_AAAA || type == T_MX || type == T_CNAME)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Only looking at answer section now. */
|
/* Only looking at answer section now. */
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ int rr_on_list(struct rrlist *list, unsigned short rr)
|
|||||||
{
|
{
|
||||||
while (list)
|
while (list)
|
||||||
{
|
{
|
||||||
if (list->rr == rr || list->rr == T_ANY)
|
if (list->rr == rr)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
list = list->next;
|
list = list->next;
|
||||||
|
|||||||
Reference in new issue
Block a user