Compare commits

...
16 Commits
Author SHA1 Message Date
Simon Kelley 5f4dc5c6ca Add --dhcp-hostsdir config option. 2015-01-20 20:51:02 +00:00
Simon Kelley 2ae195f5a7 Don't treat SERVFAIL as a recoverable error..... 2015-01-18 22:20:48 +00:00
Simon Kelley 393415597c Cope with multiple interfaces with the same LL address. 2015-01-18 22:11:10 +00:00
Simon Kelley ae4624bf46 Logs for DS records consistent. 2015-01-12 23:22:08 +00:00
Simon Kelley 5e321739db Don't answer from cache RRsets from wildcards, as we don't have NSECs. 2015-01-12 23:16:56 +00:00
Simon Kelley 9f79ee4ae3 Log port of requestor when doing extra logging. 2015-01-12 20:18:18 +00:00
RinSatsuki 28de38768e Add --min-cache-ttl option. 2015-01-10 15:22:21 +00:00
Simon Kelley 25cf5e373e Add --log-queries=extra option for more complete logging. 2015-01-09 15:53:03 +00:00
Simon Kelley 424c4a8a53 Merge branch 'unsigned' 2015-01-07 22:01:14 +00:00
Simon Kelley 97e618a0e3 DNSSEC: do top-down search for limit of secure delegation. 2015-01-07 21:55:43 +00:00
Yousong Zhou d8dbd903d0 Fix race condition issue in makefile. 2015-01-05 17:03:35 +00:00
Yousong Zhou 81c538efce Implement makefile dependencies on COPTS variable. 2015-01-03 16:36:14 +00:00
Matthias Andree d310ab7ecb Fix build failure in new inotify code on BSD. 2014-12-27 15:36:38 +00:00
Simon Kelley 0b1008d367 Bad packet protection. 2014-12-27 15:33:32 +00:00
Glen Huang 32fc6dbe03 Add --ignore-address option. 2014-12-27 15:28:12 +00:00
Simon Kelley 83d2ed09fc Initialise return value. 2014-12-23 18:42:38 +00:00
15 changed files with 628 additions and 219 deletions

No files matched your search

+1 -1
View File
@@ -3,7 +3,7 @@ src/*.mo
src/dnsmasq.pot src/dnsmasq.pot
src/dnsmasq src/dnsmasq
src/dnsmasq_baseline src/dnsmasq_baseline
src/.configured src/.copts_*
contrib/wrt/dhcp_lease_time contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release contrib/wrt/dhcp_release
debian/base/ debian/base/
+36
View File
@@ -23,6 +23,42 @@ version 2.73
Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
for the bug report. for the bug report.
Add --ignore-address option. Ignore replies to A-record
queries which include the specified address. No error is
generated, dnsmasq simply continues to listen for another
reply. This is useful to defeat blocking strategies which
rely on quickly supplying a forged answer to a DNS
request for certain domains, before the correct answer can
arrive. Thanks to Glen Huang for the patch.
Revisit the part of DNSSEC validation which determines if an
unsigned answer is legit, or is in some part of the DNS
tree which should be signed. Dnsmasq now works from the
DNS root downward looking for the limit of signed
delegations, rather than working bottom up. This is
both more correct, and less likely to trip over broken
nameservers in the unsigned parts of the DNS tree
which don't respond well to DNSSEC queries.
Add --log-queries=extra option, which makes logs easier
to search automatically.
Add --min-cache-ttl option. I've resisted this for a long
time, on the grounds that disbelieving TTLs is never a
good idea, but I've been persuaded that there are
sometimes reasons to do it. (Step forward, GFW).
To avoid misuse, there's a hard limit on the TTL
floor of one hour. Thansk to RinSatsuki for the patch.
Cope with multiple interfaces with the same link-local
address. (IPv6 addresses are scoped, so this is allowed.)
Thanks to Cory Benfield for help with this.
Add --dhcp-hostsdir. This allows addition of new host
configurations to a running dnsmasq instance much more
cheaply than having dnsmasq re-read all its existing
configuration each time.
version 2.72 version 2.72
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support. Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
+8 -4
View File
@@ -64,6 +64,8 @@ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp` gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi` sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"' version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
copts_conf = .copts_$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | \
( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
objs = cache.o rfc1035.o util.o option.o forward.o network.o \ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
@@ -83,7 +85,7 @@ all : $(BUILDDIR)
mostly_clean : mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
clean : mostly_clean clean : mostly_clean
rm -f $(BUILDDIR)/dnsmasq_baseline rm -f $(BUILDDIR)/dnsmasq_baseline
@@ -139,17 +141,19 @@ bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
# rules below are targets in recusive makes with cwd=$(BUILDDIR) # rules below are targets in recusive makes with cwd=$(BUILDDIR)
.configured: $(hdrs) $(copts_conf): $(hdrs)
@rm -f *.o @rm -f *.o .copts_*
@touch $@ @touch $@
$(objs:.o=.c) $(hdrs): $(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ . ln -s $(top)/$(SRC)/$@ .
$(objs): $(copts_conf) $(hdrs)
.c.o: .c.o:
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $< $(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : .configured $(hdrs) $(objs) dnsmasq : $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS) $(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
dnsmasq.pot : $(objs:.o=.c) $(hdrs) dnsmasq.pot : $(objs:.o=.c) $(hdrs)
+25 -1
View File
@@ -81,6 +81,12 @@ the upstream DNS servers.
.B --max-cache-ttl=<time> .B --max-cache-ttl=<time>
Set a maximum TTL value for entries in the cache. Set a maximum TTL value for entries in the cache.
.TP .TP
.B --min-cache-ttl=<time>
Extend short TTL values to the time given when caching them. Note that
artificially extending TTL values is in general a bad idea, do not do it
unless you have a good reason, and understand what you are doing.
Dnsmasq limits the value of this option to one hour, unless recompiled.
.TP
.B --auth-ttl=<time> .B --auth-ttl=<time>
Set the TTL value returned in answers from the authoritative server. Set the TTL value returned in answers from the authoritative server.
.TP .TP
@@ -98,7 +104,10 @@ only, to stop dnsmasq daemonising in production, use
.B -k. .B -k.
.TP .TP
.B \-q, --log-queries .B \-q, --log-queries
Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on receipt of SIGUSR1. If the argument "extra" is supplied, ie
.B --log-queries=extra
then the log has extra information at the start of each line.
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor.
.TP .TP
.B \-8, --log-facility=<facility> .B \-8, --log-facility=<facility>
Set the facility to which dnsmasq will send syslog entries, this Set the facility to which dnsmasq will send syslog entries, this
@@ -294,6 +303,12 @@ instead of the correct NXDOMAIN response. This option tells dnsmasq to
fake the correct response when it sees this behaviour. As at Sept 2003 fake the correct response when it sees this behaviour. As at Sept 2003
the IP address being returned by Verisign is 64.94.110.11 the IP address being returned by Verisign is 64.94.110.11
.TP .TP
.B \-B, --ignore-address=<ipaddr>
Ignore replies to A-record queries which include the specified address.
No error is generated, dnsmasq simply continues to listen for another reply.
This is useful to defeat blocking strategies which rely on quickly supplying a
forged answer to a DNS request for certain domain, before the correct answer can arrive.
.TP
.B \-f, --filterwin2k .B \-f, --filterwin2k
Later versions of windows make periodic DNS requests which don't get sensible answers from Later versions of windows make periodic DNS requests which don't get sensible answers from
the public DNS and can cause problems by triggering dial-on-demand links. This flag turns on an option the public DNS and can cause problems by triggering dial-on-demand links. This flag turns on an option
@@ -962,6 +977,15 @@ is given, then read all the files contained in that directory. The advantage of
using this option is the same as for --dhcp-hostsfile: the using this option is the same as for --dhcp-hostsfile: the
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a it is possible to encode the information in a
.TP
.B --dhcp-hostsdir=<path>
This is exactly equivalent to dhcp-hostfile, except for the following. The path MUST be a
directory, and not an individual file. Changed or new files within
the directory are read automatically, without the need to send SIGHUP.
If a file is deleted for changed after it has been read by dnsmasq, then the
host record it contained will remain until dnsmasq recieves a SIGHUP, or
is restarted; ie host records are only added dynamically.
.TP
.B --dhcp-boot .B --dhcp-boot
flag as DHCP options, using the options names bootfile-name, flag as DHCP options, using the options names bootfile-name,
server-ip-address and tftp-server. This allows these to be included server-ip-address and tftp-server. This allows these to be included
+4 -1
View File
@@ -413,7 +413,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
peer_addr->in.sin_port = 0; peer_addr->in.sin_port = 0;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
peer_addr->in6.sin6_port = 0; {
peer_addr->in6.sin6_port = 0;
peer_addr->in6.sin6_scope_id = 0;
}
#endif #endif
for (peers = daemon->auth_peers; peers; peers = peers->next) for (peers = daemon->auth_peers; peers; peers = peers->next)
+13 -2
View File
@@ -461,9 +461,11 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
if (flags & (F_IPV4 | F_IPV6 | F_CNAME)) if (flags & (F_IPV4 | F_IPV6 | F_CNAME))
{ {
log_query(flags | F_UPSTREAM, name, addr, NULL); log_query(flags | F_UPSTREAM, name, addr, NULL);
/* Don;t mess with TTL for DNSSEC records. */ /* Don't mess with TTL for DNSSEC records. */
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl) if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl; ttl = daemon->max_cache_ttl;
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
ttl = daemon->min_cache_ttl;
} }
/* if previous insertion failed give up now. */ /* if previous insertion failed give up now. */
@@ -1638,7 +1640,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
if (strlen(name) == 0) if (strlen(name) == 0)
name = "."; name = ".";
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest); if (option_bool(OPT_EXTRALOG))
{
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
if (flags & F_NOEXTRA)
my_syslog(LOG_INFO, "* %s/%u %s %s %s %s", daemon->addrbuff2, port, source, name, verb, dest);
else
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
}
else
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
} }
+2
View File
@@ -17,6 +17,7 @@
#define FTABSIZ 150 /* max number of outstanding requests (default) */ #define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */ #define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */ #define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */ #define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */ #define KEYBLOCK_LEN 40 /* choose to mininise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */ #define DNSSEC_WORK 50 /* Max number of queries to validate one question */
@@ -26,6 +27,7 @@
#define RANDOM_SOCKS 64 /* max simultaneous random ports */ #define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */ #define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */ #define CACHESIZ 150 /* default cache size */
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
#define MAXLEASES 1000 /* maximum number of DHCP leases */ #define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */ #define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */ #define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
+24 -7
View File
@@ -93,6 +93,8 @@ int main (int argc, char **argv)
daemon->packet = safe_malloc(daemon->packet_buff_sz); daemon->packet = safe_malloc(daemon->packet_buff_sz);
daemon->addrbuff = safe_malloc(ADDRSTRLEN); daemon->addrbuff = safe_malloc(ADDRSTRLEN);
if (option_bool(OPT_EXTRALOG))
daemon->addrbuff2 = safe_malloc(ADDRSTRLEN);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
@@ -140,6 +142,9 @@ int main (int argc, char **argv)
set_option_bool(OPT_NOWILD); set_option_bool(OPT_NOWILD);
reset_option_bool(OPT_CLEVERBIND); reset_option_bool(OPT_CLEVERBIND);
} }
if (daemon->inotify_hosts)
die(_("dhcp-hostsdir not supported on this platform"), NULL, EC_BADCONF);
#endif #endif
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID))
@@ -314,12 +319,15 @@ int main (int argc, char **argv)
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
blockdata_init(); blockdata_init();
#endif #endif
}
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
if (!option_bool(OPT_NO_POLL)) if ((!option_bool(OPT_NO_POLL) && daemon->port != 0) ||
inotify_dnsmasq_init(); daemon->dhcp || daemon->doing_dhcp6)
inotify_dnsmasq_init();
else
daemon->inotifyfd = -1;
#endif #endif
}
if (option_bool(OPT_DBUS)) if (option_bool(OPT_DBUS))
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
@@ -743,7 +751,7 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (option_bool(OPT_TFTP)) if (option_bool(OPT_TFTP))
{ {
#ifdef FD_SETSIZE #ifdef FD_SETSIZE
if (FD_SETSIZE < (unsigned)max_fd) if (FD_SETSIZE < (unsigned)max_fd)
@@ -868,7 +876,7 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
FD_SET(daemon->netlinkfd, &rset); FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd); bump_maxfd(daemon->netlinkfd, &maxfd);
if (daemon->port != 0 && !option_bool(OPT_NO_POLL)) if (daemon->inotifyfd != -1)
{ {
FD_SET(daemon->inotifyfd, &rset); FD_SET(daemon->inotifyfd, &rset);
bump_maxfd(daemon->inotifyfd, &maxfd); bump_maxfd(daemon->inotifyfd, &maxfd);
@@ -941,8 +949,11 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check()) if (daemon->inotifyfd != -1 && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check(now))
poll_resolv(1, 1, now); {
if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
poll_resolv(1, 1, now);
}
#else #else
/* Check for changes to resolv files once per second max. */ /* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */ /* Don't go silent for long periods if the clock goes backwards. */
@@ -1383,6 +1394,9 @@ void clear_cache_and_reload(time_t now)
if (option_bool(OPT_ETHERS)) if (option_bool(OPT_ETHERS))
dhcp_read_ethers(); dhcp_read_ethers();
reread_dhcp(); reread_dhcp();
#ifdef HAVE_LINUX_NETWORK
set_dhcp_inotify();
#endif
dhcp_update_configs(daemon->dhcp_conf); dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs(); lease_update_from_configs();
lease_update_file(now); lease_update_file(now);
@@ -1587,6 +1601,9 @@ static void check_dns_listeners(fd_set *set, time_t now)
} }
} }
close(confd); close(confd);
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
daemon->log_id += TCP_MAX_QUERIES;
} }
#endif #endif
else else
+28 -12
View File
@@ -238,7 +238,8 @@ struct event_desc {
#define OPT_DNSSEC_NO_SIGN 48 #define OPT_DNSSEC_NO_SIGN 48
#define OPT_LOCAL_SERVICE 49 #define OPT_LOCAL_SERVICE 49
#define OPT_LOOP_DETECT 50 #define OPT_LOOP_DETECT 50
#define OPT_LAST 51 #define OPT_EXTRALOG 51
#define OPT_LAST 52
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -442,6 +443,7 @@ struct crec {
#define F_NO_RR (1u<<25) #define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26) #define F_IPSET (1u<<26)
#define F_NSIGMATCH (1u<<27) #define F_NSIGMATCH (1u<<27)
#define F_NOEXTRA (1u<<28)
/* Values of uid in crecs with F_CONFIG bit set. */ /* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0 #define SRC_INTERFACE 0
@@ -548,13 +550,17 @@ struct resolvc {
#endif #endif
}; };
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */ /* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile and dhcp-hostsdir*/
#define AH_DIR 1 #define AH_DIR 1
#define AH_INACTIVE 2 #define AH_INACTIVE 2
#define AH_WD_DONE 4
struct hostsfile { struct hostsfile {
struct hostsfile *next; struct hostsfile *next;
int flags; int flags;
char *fname; char *fname;
#ifdef HAVE_LINUX_NETWORK
int wd; /* inotify watch descriptor */
#endif
unsigned int index; /* matches to cache entries for logging */ unsigned int index; /* matches to cache entries for logging */
}; };
@@ -569,8 +575,9 @@ struct hostsfile {
#define STAT_SECURE_WILDCARD 7 #define STAT_SECURE_WILDCARD 7
#define STAT_NO_SIG 8 #define STAT_NO_SIG 8
#define STAT_NO_DS 9 #define STAT_NO_DS 9
#define STAT_NEED_DS_NEG 10 #define STAT_NO_NS 10
#define STAT_CHASE_CNAME 11 #define STAT_NEED_DS_NEG 11
#define STAT_CHASE_CNAME 12
#define FREC_NOREBIND 1 #define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2 #define FREC_CHECKING_DISABLED 2
@@ -598,13 +605,15 @@ struct frec {
#endif #endif
unsigned int iface; unsigned int iface;
unsigned short orig_id, new_id; unsigned short orig_id, new_id;
int fd, forwardall, flags; int log_id, fd, forwardall, flags;
time_t time; time_t time;
unsigned char *hash[HASH_SIZE]; unsigned char *hash[HASH_SIZE];
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
int class, work_counter; int class, work_counter;
struct blockdata *stash; /* Saved reply, whilst we validate */ struct blockdata *stash; /* Saved reply, whilst we validate */
size_t stash_len; struct blockdata *orig_domain; /* domain of original query, whilst
we're seeing is if in unsigned domain */
size_t stash_len, name_start, name_len;
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */ struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
struct frec *blocking_query; /* Query which is blocking us. */ struct frec *blocking_query; /* Query which is blocking us. */
#endif #endif
@@ -930,7 +939,7 @@ extern struct daemon {
char *runfile; char *runfile;
char *lease_change_command; char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces; struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr; struct bogus_addr *bogus_addr, *ignore_addr;
struct server *servers; struct server *servers;
struct ipsets *ipsets; struct ipsets *ipsets;
int log_fac; /* log facility */ int log_fac; /* log facility */
@@ -938,7 +947,7 @@ extern struct daemon {
int max_logs; /* queue limit */ int max_logs; /* queue limit */
int cachesize, ftabsize; int cachesize, ftabsize;
int port, query_port, min_port; int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl; unsigned long local_ttl, neg_ttl, max_ttl, min_cache_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts; struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6; struct dhcp_context *dhcp, *dhcp6;
struct ra_interface *ra_interfaces; struct ra_interface *ra_interfaces;
@@ -956,7 +965,7 @@ extern struct daemon {
int doing_ra, doing_dhcp6; int doing_ra, doing_dhcp6;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names; struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
struct dhcp_netid_list *force_broadcast, *bootp_dynamic; struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file; struct hostsfile *dhcp_hosts_file, *dhcp_opts_file, *inotify_hosts;
int dhcp_max, tftp_max; int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port; int dhcp_server_port, dhcp_client_port;
int start_tftp_port, end_tftp_port; int start_tftp_port, end_tftp_port;
@@ -999,6 +1008,8 @@ extern struct daemon {
struct randfd randomsocks[RANDOM_SOCKS]; struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo; int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */ struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
int log_id, log_display_id; /* ids of transactions for logging */
union mysockaddr *log_source_addr;
/* DHCP state */ /* DHCP state */
int dhcpfd, helperfd, pxefd; int dhcpfd, helperfd, pxefd;
@@ -1030,6 +1041,7 @@ extern struct daemon {
/* utility string buffer, hold max sized IP address as string */ /* utility string buffer, hold max sized IP address as string */
char *addrbuff; char *addrbuff;
char *addrbuff2; /* only allocated when OPT_EXTRALOG */
} *daemon; } *daemon;
@@ -1093,6 +1105,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
time_t now, int *ad_reqd, int *do_bit); time_t now, int *ad_reqd, int *do_bit);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now); struct bogus_addr *addr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign); size_t *len, unsigned char **p, int *is_sign);
int check_for_local_domain(char *name, time_t now); int check_for_local_domain(char *name, time_t now);
@@ -1125,7 +1138,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr); size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class); int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class); int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer); int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer, int *nons);
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname); int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname);
int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen); int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
size_t filter_rrsigs(struct dns_header *header, size_t plen); size_t filter_rrsigs(struct dns_header *header, size_t plen);
@@ -1188,7 +1201,7 @@ void reset_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list); struct hostsfile *expand_filelist(struct hostsfile *list);
char *parse_server(char *arg, union mysockaddr *addr, char *parse_server(char *arg, union mysockaddr *addr,
union mysockaddr *source_addr, char *interface, int *flags); union mysockaddr *source_addr, char *interface, int *flags);
int option_read_hostsfile(char *file);
/* forward.c */ /* forward.c */
void reply_query(int fd, int family, time_t now); void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now); void receive_query(struct listener *listen, time_t now);
@@ -1477,5 +1490,8 @@ int detect_loop(char *query, int type);
/* inotify.c */ /* inotify.c */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void inotify_dnsmasq_init(); void inotify_dnsmasq_init();
int inotify_check(void); int inotify_check(time_t now);
# ifdef HAVE_DHCP
void set_dhcp_inotify(void);
# endif
#endif #endif
+69 -38
View File
@@ -638,6 +638,9 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag; int type_covered, algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag;
u16 *rr_desc = get_desc(type); u16 *rr_desc = get_desc(type);
if (wildcard_out)
*wildcard_out = NULL;
if (!(p = skip_questions(header, plen))) if (!(p = skip_questions(header, plen)))
return STAT_BOGUS; return STAT_BOGUS;
@@ -802,7 +805,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
{ {
while (*name_start != '.' && *name_start != 0) while (*name_start != '.' && *name_start != 0)
name_start++; name_start++;
if (k != 1) if (k != 1 && *name_start == '.')
name_start++; name_start++;
} }
@@ -872,8 +875,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
/* The DNS packet is expected to contain the answer to a DNSKEY query. /* The DNS packet is expected to contain the answer to a DNSKEY query.
Put all DNSKEYs in the answer which are valid into the cache. Put all DNSKEYs in the answer which are valid into the cache.
return codes: return codes:
STAT_INSECURE No DNSKEYs in reply. STAT_SECURE At least one valid DNSKEY found and in cache.
STAT_SECURE At least one valid DNSKEY found and in cache.
STAT_BOGUS No DNSKEYs found, which can be validated with DS, STAT_BOGUS No DNSKEYs found, which can be validated with DS,
or self-sign for DNSKEY RRset is not valid, bad packet. or self-sign for DNSKEY RRset is not valid, bad packet.
STAT_NEED_DS DS records to validate a key not found, name in keyname STAT_NEED_DS DS records to validate a key not found, name in keyname
@@ -893,12 +895,9 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
GETSHORT(qtype, p); GETSHORT(qtype, p);
GETSHORT(qclass, p); GETSHORT(qclass, p);
if (qtype != T_DNSKEY || qclass != class) if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
return STAT_BOGUS; return STAT_BOGUS;
if (ntohs(header->ancount) == 0)
return STAT_INSECURE;
/* See if we have cached a DS record which validates this key */ /* See if we have cached a DS record which validates this key */
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS))) if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
{ {
@@ -1039,7 +1038,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
else else
{ {
a.addr.keytag = keytag; a.addr.keytag = keytag;
log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DNSKEY keytag %u");
recp1->addr.key.keylen = rdlen - 4; recp1->addr.key.keylen = rdlen - 4;
recp1->addr.key.keydata = key; recp1->addr.key.keydata = key;
@@ -1093,24 +1092,24 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
return STAT_SECURE; return STAT_SECURE;
} }
log_query(F_UPSTREAM, name, NULL, "BOGUS DNSKEY"); log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
return STAT_BOGUS; return STAT_BOGUS;
} }
/* The DNS packet is expected to contain the answer to a DS query /* The DNS packet is expected to contain the answer to a DS query
Put all DSs in the answer which are valid into the cache. Put all DSs in the answer which are valid into the cache.
return codes: return codes:
STAT_INSECURE no DS in reply or not signed.
STAT_SECURE At least one valid DS found and in cache. STAT_SECURE At least one valid DS found and in cache.
STAT_NO_DS It's proved there's no DS here. STAT_NO_DS It's proved there's no DS here.
STAT_BOGUS At least one DS found, which fails validation, bad packet. STAT_NO_NS It's proved there's no DS _or_ NS here.
STAT_BOGUS no DS in reply or not signed, fails validation, bad packet.
STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname STAT_NEED_DNSKEY DNSKEY records to validate a DS not found, name in keyname
*/ */
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class) int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class)
{ {
unsigned char *p = (unsigned char *)(header+1); unsigned char *p = (unsigned char *)(header+1);
int qtype, qclass, val, i, neganswer; int qtype, qclass, val, i, neganswer, nons;
if (ntohs(header->qdcount) != 1 || if (ntohs(header->qdcount) != 1 ||
!(p = skip_name(p, header, plen, 4))) !(p = skip_name(p, header, plen, 4)))
@@ -1122,32 +1121,39 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
if (qtype != T_DS || qclass != class) if (qtype != T_DS || qclass != class)
val = STAT_BOGUS; val = STAT_BOGUS;
else else
val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer); val = dnssec_validate_reply(now, header, plen, name, keyname, NULL, &neganswer, &nons);
/* Note dnssec_validate_reply() will have cached positive answers */
if (val == STAT_NO_SIG) if (val == STAT_NO_SIG || val == STAT_INSECURE)
val = STAT_INSECURE; val = STAT_BOGUS;
p = (unsigned char *)(header+1); p = (unsigned char *)(header+1);
extract_name(header, plen, &p, name, 1, 4); extract_name(header, plen, &p, name, 1, 4);
p += 4; /* qtype, qclass */ p += 4; /* qtype, qclass */
if (!(p = skip_section(p, ntohs(header->ancount), header, plen))) if (!(p = skip_section(p, ntohs(header->ancount), header, plen)))
return STAT_BOGUS; val = STAT_BOGUS;
if (val == STAT_BOGUS) if (val == STAT_BOGUS)
log_query(F_UPSTREAM, name, NULL, "BOGUS DS");
if ((val == STAT_SECURE || val == STAT_INSECURE) && neganswer)
{ {
int rdlen, flags = F_FORWARD | F_DS | F_NEG; log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
return STAT_BOGUS;
}
/* By here, the answer is proved secure, and a positive answer has been cached. */
if (val == STAT_SECURE && neganswer)
{
int rdlen, flags = F_FORWARD | F_DS | F_NEG | F_DNSSECOK;
unsigned long ttl, minttl = ULONG_MAX; unsigned long ttl, minttl = ULONG_MAX;
struct all_addr a; struct all_addr a;
if (RCODE(header) == NXDOMAIN) if (RCODE(header) == NXDOMAIN)
flags |= F_NXDOMAIN; flags |= F_NXDOMAIN;
if (val == STAT_SECURE) /* We only cache validated DS records, DNSSECOK flag hijacked
flags |= F_DNSSECOK; to store presence/absence of NS. */
if (nons)
flags &= ~F_DNSSECOK;
for (i = ntohs(header->nscount); i != 0; i--) for (i = ntohs(header->nscount); i != 0; i--)
{ {
@@ -1194,9 +1200,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
cache_insert(name, &a, now, ttl, flags); cache_insert(name, &a, now, ttl, flags);
cache_end_insert(); cache_end_insert();
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, nons ? "no delegation" : "no DS");
} }
return (val == STAT_SECURE) ? STAT_NO_DS : STAT_INSECURE; return nons ? STAT_NO_NS : STAT_NO_DS;
} }
return val; return val;
@@ -1320,13 +1328,16 @@ static int find_nsec_records(struct dns_header *header, size_t plen, unsigned ch
} }
static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count, static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
char *workspace1, char *workspace2, char *name, int type) char *workspace1, char *workspace2, char *name, int type, int *nons)
{ {
int i, rc, rdlen; int i, rc, rdlen;
unsigned char *p, *psave; unsigned char *p, *psave;
int offset = (type & 0xff) >> 3; int offset = (type & 0xff) >> 3;
int mask = 0x80 >> (type & 0x07); int mask = 0x80 >> (type & 0x07);
if (nons)
*nons = 0;
/* Find NSEC record that proves name doesn't exist */ /* Find NSEC record that proves name doesn't exist */
for (i = 0; i < nsec_count; i++) for (i = 0; i < nsec_count; i++)
{ {
@@ -1352,6 +1363,10 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
rdlen -= p - psave; rdlen -= p - psave;
/* rdlen is now length of type map, and p points to it */ /* rdlen is now length of type map, and p points to it */
/* If we can prove that there's no NS record, return that information. */
if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
*nons = 1;
while (rdlen >= 2) while (rdlen >= 2)
{ {
if (!CHECK_LEN(header, p, plen, rdlen)) if (!CHECK_LEN(header, p, plen, rdlen))
@@ -1453,7 +1468,7 @@ static int base32_decode(char *in, unsigned char *out)
} }
static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type, static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count) char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count, int *nons)
{ {
int i, hash_len, salt_len, base32_len, rdlen; int i, hash_len, salt_len, base32_len, rdlen;
unsigned char *p, *psave; unsigned char *p, *psave;
@@ -1494,6 +1509,10 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
if (!CHECK_LEN(header, p, plen, rdlen)) if (!CHECK_LEN(header, p, plen, rdlen))
return 0; return 0;
/* If we can prove that there's no NS record, return that information. */
if (nons && rdlen >= 2 && p[0] == 0 && (p[2] & (0x80 >> T_NS)) == 0)
*nons = 1;
while (rdlen >= 2) while (rdlen >= 2)
{ {
if (p[0] == type >> 8) if (p[0] == type >> 8)
@@ -1530,13 +1549,16 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
} }
static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count, static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
char *workspace1, char *workspace2, char *name, int type, char *wildname) char *workspace1, char *workspace2, char *name, int type, char *wildname, int *nons)
{ {
unsigned char *salt, *p, *digest; unsigned char *salt, *p, *digest;
int digest_len, i, iterations, salt_len, base32_len, algo = 0; int digest_len, i, iterations, salt_len, base32_len, algo = 0;
struct nettle_hash const *hash; struct nettle_hash const *hash;
char *closest_encloser, *next_closest, *wildcard; char *closest_encloser, *next_closest, *wildcard;
if (nons)
*nons = 0;
/* Look though the NSEC3 records to find the first one with /* Look though the NSEC3 records to find the first one with
an algorithm we support (currently only algo == 1). an algorithm we support (currently only algo == 1).
@@ -1609,7 +1631,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0) if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS; return STAT_BOGUS;
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count)) if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, nons))
return STAT_SECURE; return STAT_SECURE;
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3" /* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
@@ -1654,7 +1676,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0) if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS; return STAT_BOGUS;
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count)) if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
return STAT_BOGUS; return STAT_BOGUS;
/* Finally, check that there's no seat of wildcard synthesis */ /* Finally, check that there's no seat of wildcard synthesis */
@@ -1669,7 +1691,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0) if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS; return STAT_BOGUS;
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count)) if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count, NULL))
return STAT_BOGUS; return STAT_BOGUS;
} }
@@ -1678,7 +1700,8 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */ /* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
/* Returns are the same as validate_rrset, plus the class if the missing key is in *class */ /* Returns are the same as validate_rrset, plus the class if the missing key is in *class */
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer) int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
int *class, int *neganswer, int *nons)
{ {
unsigned char *ans_start, *qname, *p1, *p2, **nsecs; unsigned char *ans_start, *qname, *p1, *p2, **nsecs;
int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype; int type1, class1, rdlen1, type2, class2, rdlen2, qclass, qtype;
@@ -1795,11 +1818,14 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
struct blockdata *key; struct blockdata *key;
struct crec *crecp; struct crec *crecp;
char *wildname; char *wildname;
int have_wildcard = 0;
rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0); rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
if (rc == STAT_SECURE_WILDCARD) if (rc == STAT_SECURE_WILDCARD)
{ {
have_wildcard = 1;
/* An attacker replay a wildcard answer with a different /* An attacker replay a wildcard answer with a different
answer and overlay a genuine RR. To prove this answer and overlay a genuine RR. To prove this
hasn't happened, the answer must prove that hasn't happened, the answer must prove that
@@ -1808,9 +1834,10 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
return STAT_BOGUS; /* No NSECs or bad packet */ return STAT_BOGUS; /* No NSECs or bad packet */
if (nsec_type == T_NSEC) if (nsec_type == T_NSEC)
rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1); rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, NULL);
else else
rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, wildname); rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename,
keyname, name, type1, wildname, NULL);
if (rc != STAT_SECURE) if (rc != STAT_SECURE)
return rc; return rc;
@@ -1861,7 +1888,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
else else
{ {
a.addr.keytag = keytag; a.addr.keytag = keytag;
log_query(F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u"); log_query(F_NOEXTRA | F_KEYTAG | F_UPSTREAM, name, &a, "DS keytag %u");
crecp->addr.ds.digest = digest; crecp->addr.ds.digest = digest;
crecp->addr.ds.keydata = key; crecp->addr.ds.keydata = key;
crecp->addr.ds.algo = algo; crecp->addr.ds.algo = algo;
@@ -1889,7 +1916,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
p2 += 13; /* labels, orig_ttl, expiration, inception */ p2 += 13; /* labels, orig_ttl, expiration, inception */
GETSHORT(keytag, p2); GETSHORT(keytag, p2);
if ((key = blockdata_alloc((char*)psave, rdlen2))) /* We don't cache sigs for wildcard answers, because to reproduce the
answer from the cache will require one or more NSEC/NSEC3 records
which we don't cache. The lack of the RRSIG ensures that a query for
this RRset asking for a secure answer will always be forwarded. */
if (!have_wildcard && (key = blockdata_alloc((char*)psave, rdlen2)))
{ {
if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS))) if (!(crecp = cache_insert(name, &a, now, ttl, F_FORWARD | F_DNSKEY | F_DS)))
blockdata_free(key); blockdata_free(key);
@@ -1934,9 +1965,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
return STAT_BOGUS; return STAT_BOGUS;
if (nsec_type == T_NSEC) if (nsec_type == T_NSEC)
return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype); return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, nons);
else else
return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL); return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL, nons);
} }
/* Chase the CNAME chain in the packet until the first record which _doesn't validate. /* Chase the CNAME chain in the packet until the first record which _doesn't validate.
@@ -2034,10 +2065,10 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
char *types = querystr("dnssec-query", type); char *types = querystr("dnssec-query", type);
if (addr->sa.sa_family == AF_INET) if (addr->sa.sa_family == AF_INET)
log_query(F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types); log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types); log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, name, (struct all_addr *)&addr->in6.sin6_addr, types);
#endif #endif
header->qdcount = htons(1); header->qdcount = htons(1);
+214 -140
View File
@@ -26,8 +26,9 @@ static void free_frec(struct frec *f);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n, static int tcp_key_recurse(time_t now, int status, struct dns_header *header, size_t n,
int class, char *name, char *keyname, struct server *server, int *keycount); int class, char *name, char *keyname, struct server *server, int *keycount);
static int do_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class); static int do_check_sign(struct frec *forward, int status, time_t now, char *name, char *keyname);
static int send_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname); static int send_check_sign(struct frec *forward, time_t now, struct dns_header *header, size_t plen,
char *name, char *keyname);
#endif #endif
@@ -278,10 +279,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
plen = forward->stash_len; plen = forward->stash_len;
if (forward->sentto->addr.sa.sa_family == AF_INET) if (forward->sentto->addr.sa.sa_family == AF_INET)
log_query(F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec"); log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else else
log_query(F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec"); log_query(F_NOEXTRA | F_DNSSEC | F_IPV6, "retry", (struct all_addr *)&forward->sentto->addr.in6.sin6_addr, "dnssec");
#endif #endif
if (forward->sentto->sfd) if (forward->sentto->sfd)
@@ -388,6 +389,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct server *firstsentto = start; struct server *firstsentto = start;
int forwarded = 0; int forwarded = 0;
/* If a query is retried, use the log_id for the retry when logging the answer. */
forward->log_id = daemon->log_id;
if (option_bool(OPT_ADD_MAC)) if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source); plen = add_mac(header, plen, ((char *) header) + daemon->packet_buff_sz, &forward->source);
@@ -724,7 +728,16 @@ void reply_query(int fd, int family, time_t now)
if (!(forward = lookup_frec(ntohs(header->id), hash))) if (!(forward = lookup_frec(ntohs(header->id), hash)))
return; return;
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) && /* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = forward->log_id;
daemon->log_source_addr = &forward->source;
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
check_for_ignored_address(header, n, daemon->ignore_addr))
return;
if (RCODE(header) == REFUSED &&
!option_bool(OPT_ORDER) && !option_bool(OPT_ORDER) &&
forward->forwardall == 0) forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */ /* for broken servers, attempt to send to another one. */
@@ -811,18 +824,22 @@ void reply_query(int fd, int family, time_t now)
else if (forward->flags & FREC_DS_QUERY) else if (forward->flags & FREC_DS_QUERY)
{ {
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
if (status == STAT_NO_DS) if (status == STAT_NO_DS || status == STAT_NO_NS)
status = STAT_INSECURE; status = STAT_BOGUS;
} }
else if (forward->flags & FREC_CHECK_NOSIGN) else if (forward->flags & FREC_CHECK_NOSIGN)
status = do_check_sign(now, header, n, daemon->namebuff, daemon->keyname, forward->class); {
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
if (status != STAT_NEED_KEY)
status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
}
else else
{ {
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL); status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);
if (status == STAT_NO_SIG) if (status == STAT_NO_SIG)
{ {
if (option_bool(OPT_DNSSEC_NO_SIGN)) if (option_bool(OPT_DNSSEC_NO_SIGN))
status = send_check_sign(now, header, n, daemon->namebuff, daemon->keyname); status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
else else
status = STAT_INSECURE; status = STAT_INSECURE;
} }
@@ -857,6 +874,7 @@ void reply_query(int fd, int family, time_t now)
new->blocking_query = NULL; new->blocking_query = NULL;
new->sentto = server; new->sentto = server;
new->rfd4 = NULL; new->rfd4 = NULL;
new->orig_domain = NULL;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
new->rfd6 = NULL; new->rfd6 = NULL;
#endif #endif
@@ -885,7 +903,9 @@ void reply_query(int fd, int family, time_t now)
new->new_id = get_id(); new->new_id = get_id();
header->id = htons(new->new_id); header->id = htons(new->new_id);
/* Save query for retransmission */ /* Save query for retransmission */
new->stash = blockdata_alloc((char *)header, nn); if (!(new->stash = blockdata_alloc((char *)header, nn)))
return;
new->stash_len = nn; new->stash_len = nn;
/* Don't resend this. */ /* Don't resend this. */
@@ -942,18 +962,22 @@ void reply_query(int fd, int family, time_t now)
else if (forward->flags & FREC_DS_QUERY) else if (forward->flags & FREC_DS_QUERY)
{ {
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class); status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
if (status == STAT_NO_DS) if (status == STAT_NO_DS || status == STAT_NO_NS)
status = STAT_INSECURE; status = STAT_BOGUS;
} }
else if (forward->flags & FREC_CHECK_NOSIGN) else if (forward->flags & FREC_CHECK_NOSIGN)
status = do_check_sign(now, header, n, daemon->namebuff, daemon->keyname, forward->class); {
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
if (status != STAT_NEED_KEY)
status = do_check_sign(forward, status, now, daemon->namebuff, daemon->keyname);
}
else else
{ {
status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL); status = dnssec_validate_reply(now, header, n, daemon->namebuff, daemon->keyname, &forward->class, NULL, NULL);
if (status == STAT_NO_SIG) if (status == STAT_NO_SIG)
{ {
if (option_bool(OPT_DNSSEC_NO_SIGN)) if (option_bool(OPT_DNSSEC_NO_SIGN))
status = send_check_sign(now, header, n, daemon->namebuff, daemon->keyname); status = send_check_sign(forward, now, header, n, daemon->namebuff, daemon->keyname);
else else
status = STAT_INSECURE; status = STAT_INSECURE;
} }
@@ -1243,6 +1267,11 @@ void receive_query(struct listener *listen, time_t now)
} }
} }
/* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &source_addr;
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
{ {
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
@@ -1315,70 +1344,80 @@ void receive_query(struct listener *listen, time_t now)
/* UDP: we've got an unsigned answer, return STAT_INSECURE if we can prove there's no DS /* UDP: we've got an unsigned answer, return STAT_INSECURE if we can prove there's no DS
and therefore the answer shouldn't be signed, or STAT_BOGUS if it should be, or and therefore the answer shouldn't be signed, or STAT_BOGUS if it should be, or
STAT_NEED_DS_NEG and keyname if we need to do the query. */ STAT_NEED_DS_NEG and keyname if we need to do the query. */
static int send_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname) static int send_check_sign(struct frec *forward, time_t now, struct dns_header *header, size_t plen,
char *name, char *keyname)
{ {
struct crec *crecp;
char *name_start = name;
int status = dnssec_chase_cname(now, header, plen, name, keyname); int status = dnssec_chase_cname(now, header, plen, name, keyname);
if (status != STAT_INSECURE) if (status != STAT_INSECURE)
return status; return status;
while (1) /* Store the domain we're trying to check. */
{ forward->name_start = strlen(name);
crecp = cache_find_by_name(NULL, name_start, now, F_DS); forward->name_len = forward->name_start + 1;
if (!(forward->orig_domain = blockdata_alloc(name, forward->name_len)))
return STAT_BOGUS;
if (crecp && (crecp->flags & F_DNSSECOK)) return do_check_sign(forward, 0, now, name, keyname);
return (crecp->flags & F_NEG) ? STAT_INSECURE : STAT_BOGUS;
if (crecp && (crecp->flags & F_NEG) && (name_start = strchr(name_start, '.')))
{
name_start++; /* chop a label off and try again */
continue;
}
/* Reached the root */
if (!name_start)
return STAT_BOGUS;
strcpy(keyname, name_start);
return STAT_NEED_DS_NEG;
}
} }
/* Got answer to DS query from send_check_sign, check for proven non-existence, or make the next DS query to try. */ /* We either have a a reply (header non-NULL, or we need to start by looking in the cache */
static int do_check_sign(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class) static int do_check_sign(struct frec *forward, int status, time_t now, char *name, char *keyname)
{ {
char *name_start; /* get domain we're checking back from blockdata store, it's stored on the original query. */
unsigned char *p; while (forward->dependent)
int status; forward = forward->dependent;
/* In this case only, a SERVFAIL reply allows us to continue up the tree, looking for a blockdata_retrieve(forward->orig_domain, forward->name_len, name);
suitable NSEC reply to DS queries. */
if (RCODE(header) != SERVFAIL) while (1)
{ {
status = dnssec_validate_ds(now, header, plen, name, keyname, class); char *p;
if (status != STAT_INSECURE) if (status == 0)
{ {
if (status == STAT_NO_DS) struct crec *crecp;
status = STAT_INSECURE;
return status; /* Haven't received answer, see if in cache */
if (!(crecp = cache_find_by_name(NULL, &name[forward->name_start], now, F_DS)))
{
/* put name of DS record we're missing into keyname */
strcpy(keyname, &name[forward->name_start]);
/* and wait for reply to arrive */
return STAT_NEED_DS_NEG;
}
/* F_DNSSECOK misused in DS cache records to non-existance of NS record */
if (!(crecp->flags & F_NEG))
status = STAT_SECURE;
else if (crecp->flags & F_DNSSECOK)
status = STAT_NO_DS;
else
status = STAT_NO_NS;
} }
/* Have entered non-signed part of DNS tree. */
if (status == STAT_NO_DS)
return STAT_INSECURE;
if (status == STAT_BOGUS)
return STAT_BOGUS;
/* There's a proven DS record, or we're within a zone, where there doesn't need
to be a DS record. Add a name and try again.
If we've already tried the whole name, then fail */
if (forward->name_start == 0)
return STAT_BOGUS;
for (p = &name[forward->name_start-2]; (*p != '.') && (p != name); p--);
if (p != name)
p++;
forward->name_start = p - name;
status = 0; /* force to cache when we iterate. */
} }
p = (unsigned char *)(header+1);
if (extract_name(header, plen, &p, name, 1, 4) &&
(name_start = strchr(name, '.')))
{
name_start++; /* chop a label off and try again */
strcpy(keyname, name_start);
return STAT_NEED_DS_NEG;
}
return STAT_BOGUS;
} }
/* Move toward the root, until we find a signed non-existance of a DS, in which case /* Move toward the root, until we find a signed non-existance of a DS, in which case
@@ -1390,9 +1429,10 @@ static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
size_t m; size_t m;
unsigned char *packet, *payload; unsigned char *packet, *payload;
u16 *length; u16 *length;
unsigned char *p = (unsigned char *)(header+1); int status, name_len;
int status; struct blockdata *block;
char *name_start = name;
char *name_start;
/* Get first insecure entry in CNAME chain */ /* Get first insecure entry in CNAME chain */
status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, name, keyname, server, keycount); status = tcp_key_recurse(now, STAT_CHASE_CNAME, header, plen, class, name, keyname, server, keycount);
@@ -1406,94 +1446,112 @@ static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
header = (struct dns_header *)payload; header = (struct dns_header *)payload;
length = (u16 *)packet; length = (u16 *)packet;
/* Stash the name away, since the buffer will be trashed when we recurse */
name_len = strlen(name) + 1;
name_start = name + name_len - 1;
if (!(block = blockdata_alloc(name, name_len)))
{
free(packet);
return STAT_BOGUS;
}
while (1) while (1)
{ {
unsigned char *newhash, hash[HASH_SIZE];
unsigned char c1, c2; unsigned char c1, c2;
struct crec *crecp = cache_find_by_name(NULL, name_start, now, F_DS); struct crec *crecp;
if (--(*keycount) == 0) if (--(*keycount) == 0)
{ {
free(packet); free(packet);
blockdata_free(block);
return STAT_BOGUS; return STAT_BOGUS;
} }
if (crecp && (crecp->flags & F_DNSSECOK)) while ((crecp = cache_find_by_name(NULL, name_start, now, F_DS)))
{ {
free(packet); if ((crecp->flags & F_NEG) && (crecp->flags & F_DNSSECOK))
return (crecp->flags & F_NEG) ? STAT_INSECURE : STAT_BOGUS; {
/* Found a secure denial of DS - delegation is indeed insecure */
free(packet);
blockdata_free(block);
return STAT_INSECURE;
}
/* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
Add another label and continue. */
if (name_start == name)
{
free(packet);
blockdata_free(block);
return STAT_BOGUS; /* run out of labels */
}
name_start -= 2;
while (*name_start != '.' && name_start != name)
name_start--;
if (name_start != name)
name_start++;
} }
/* If we have cached insecurely that a DS doesn't exist, /* Can't find it in the cache, have to send a query */
ise that is a hit for where to start looking for the secure one */
if (crecp && (crecp->flags & F_NEG) && (name_start = strchr(name_start, '.')))
{
name_start++; /* chop a label off and try again */
continue;
}
/* reached the root */
if (!name_start)
{
free(packet);
return STAT_BOGUS;
}
m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr); m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr);
/* We rely on the question section coming back unchanged, ensure it is with the hash. */ *length = htons(m);
if ((newhash = hash_questions(header, (unsigned int)m, name)))
if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) &&
read_write(server->tcpfd, &c1, 1, 1) &&
read_write(server->tcpfd, &c2, 1, 1) &&
read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
{ {
memcpy(hash, newhash, HASH_SIZE); m = (c1 << 8) | c2;
*length = htons(m); /* Note this trashes all three name workspaces */
status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
if (read_write(server->tcpfd, packet, m + sizeof(u16), 0) && if (status == STAT_NO_DS)
read_write(server->tcpfd, &c1, 1, 1) &&
read_write(server->tcpfd, &c2, 1, 1) &&
read_write(server->tcpfd, payload, (c1 << 8) | c2, 1))
{ {
m = (c1 << 8) | c2; /* Found a secure denial of DS - delegation is indeed insecure */
free(packet);
newhash = hash_questions(header, (unsigned int)m, name); blockdata_free(block);
if (newhash && memcmp(hash, newhash, HASH_SIZE) == 0) return STAT_INSECURE;
{
/* In this case only, a SERVFAIL reply allows us to continue up the tree, looking for a
suitable NSEC reply to DS queries. */
if (RCODE(header) == SERVFAIL)
status = STAT_INSECURE;
else
/* Note this trashes all three name workspaces */
status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
/* We've found a DS which proves the bit of the DNS where the
original query is, is unsigned, so the answer is OK,
if unvalidated. */
if (status == STAT_NO_DS)
{
free(packet);
return STAT_INSECURE;
}
/* No DS, not got to DNSSEC-land yet, go up. */
if (status == STAT_INSECURE)
{
p = (unsigned char *)(header+1);
if (extract_name(header, plen, &p, name, 1, 4) &&
(name_start = strchr(name, '.')))
{
name_start++; /* chop a label off and try again */
continue;
}
}
}
} }
if (status == STAT_BOGUS)
{
free(packet);
blockdata_free(block);
return STAT_BOGUS;
}
/* Here, either there's a secure DS, or no NS and no DS, and therefore no delegation.
Add another label and continue. */
/* Get name we're checking back. */
blockdata_retrieve(block, name_len, name);
if (name_start == name)
{
free(packet);
blockdata_free(block);
return STAT_BOGUS; /* run out of labels */
}
name_start -= 2;
while (*name_start != '.' && name_start != name)
name_start--;
if (name_start != name)
name_start++;
}
else
{
/* IO failure */
free(packet);
blockdata_free(block);
return STAT_BOGUS; /* run out of labels */
} }
free(packet);
return STAT_BOGUS;
} }
} }
@@ -1512,14 +1570,14 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG) else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
{ {
new_status = dnssec_validate_ds(now, header, n, name, keyname, class); new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
if (status == STAT_NEED_DS && new_status == STAT_NO_DS) if (status == STAT_NEED_DS && (new_status == STAT_NO_DS || new_status == STAT_NO_NS))
new_status = STAT_INSECURE; new_status = STAT_BOGUS;
} }
else if (status == STAT_CHASE_CNAME) else if (status == STAT_CHASE_CNAME)
new_status = dnssec_chase_cname(now, header, n, name, keyname); new_status = dnssec_chase_cname(now, header, n, name, keyname);
else else
{ {
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL); new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
if (new_status == STAT_NO_SIG) if (new_status == STAT_NO_SIG)
{ {
@@ -1572,14 +1630,14 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG) else if (status == STAT_NEED_DS || status == STAT_NEED_DS_NEG)
{ {
new_status = dnssec_validate_ds(now, header, n, name, keyname, class); new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
if (status == STAT_NEED_DS && new_status == STAT_NO_DS) if (status == STAT_NEED_DS && (new_status == STAT_NO_DS || new_status == STAT_NO_NS))
new_status = STAT_INSECURE; /* Validated no DS */ new_status = STAT_BOGUS; /* Validated no DS */
} }
else if (status == STAT_CHASE_CNAME) else if (status == STAT_CHASE_CNAME)
new_status = dnssec_chase_cname(now, header, n, name, keyname); new_status = dnssec_chase_cname(now, header, n, name, keyname);
else else
{ {
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL); new_status = dnssec_validate_reply(now, header, n, name, keyname, &class, NULL, NULL);
if (new_status == STAT_NO_SIG) if (new_status == STAT_NO_SIG)
{ {
@@ -1630,6 +1688,7 @@ unsigned char *tcp_request(int confd, time_t now,
struct in_addr dst_addr_4; struct in_addr dst_addr_4;
union mysockaddr peer_addr; union mysockaddr peer_addr;
socklen_t peer_len = sizeof(union mysockaddr); socklen_t peer_len = sizeof(union mysockaddr);
int query_count = 0;
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1) if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet; return packet;
@@ -1667,7 +1726,8 @@ unsigned char *tcp_request(int confd, time_t now,
while (1) while (1)
{ {
if (!packet || if (query_count == TCP_MAX_QUERIES ||
!packet ||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) || !read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
!(size = c1 << 8 | c2) || !(size = c1 << 8 | c2) ||
!read_write(confd, payload, size, 1)) !read_write(confd, payload, size, 1))
@@ -1676,6 +1736,13 @@ unsigned char *tcp_request(int confd, time_t now,
if (size < (int)sizeof(struct dns_header)) if (size < (int)sizeof(struct dns_header))
continue; continue;
query_count++;
/* log_query gets called indirectly all over the place, so
pass these in global variables - sorry. */
daemon->log_display_id = ++daemon->log_id;
daemon->log_source_addr = &peer_addr;
check_subnet = 0; check_subnet = 0;
/* save state of "cd" flag in query */ /* save state of "cd" flag in query */
@@ -1957,6 +2024,7 @@ static struct frec *allocate_frec(time_t now)
f->dependent = NULL; f->dependent = NULL;
f->blocking_query = NULL; f->blocking_query = NULL;
f->stash = NULL; f->stash = NULL;
f->orig_domain = NULL;
#endif #endif
daemon->frec_list = f; daemon->frec_list = f;
} }
@@ -2025,6 +2093,12 @@ static void free_frec(struct frec *f)
f->stash = NULL; f->stash = NULL;
} }
if (f->orig_domain)
{
blockdata_free(f->orig_domain);
f->orig_domain = NULL;
}
/* Anything we're waiting on is pointless now, too */ /* Anything we're waiting on is pointless now, too */
if (f->blocking_query) if (f->blocking_query)
free_frec(f->blocking_query); free_frec(f->blocking_query);
+113 -6
View File
@@ -15,9 +15,14 @@
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_LINUX_NETWORK
#include <sys/inotify.h> #include <sys/inotify.h>
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_DHCP
static void check_for_dhcp_inotify(struct inotify_event *in, time_t now);
#endif
/* the strategy is to set a inotify on the directories containing /* the strategy is to set a inotify on the directories containing
resolv files, for any files in the directory which are close-write resolv files, for any files in the directory which are close-write
@@ -40,8 +45,6 @@ void inotify_dnsmasq_init()
struct resolvc *res; struct resolvc *res;
inotify_buffer = safe_malloc(INOTIFY_SZ); inotify_buffer = safe_malloc(INOTIFY_SZ);
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (daemon->inotifyfd == -1) if (daemon->inotifyfd == -1)
@@ -66,6 +69,7 @@ void inotify_dnsmasq_init()
{ {
*d = 0; /* make path just directory */ *d = 0; /* make path just directory */
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO); res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
res->file = d+1; /* pointer to filename */ res->file = d+1; /* pointer to filename */
*d = '/'; *d = '/';
@@ -78,7 +82,7 @@ void inotify_dnsmasq_init()
} }
} }
int inotify_check(void) int inotify_check(time_t now)
{ {
int hit = 0; int hit = 0;
@@ -101,13 +105,116 @@ int inotify_check(void)
for (res = daemon->resolv_files; res; res = res->next) for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0) if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
hit = 1; hit = 1;
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->doing_dhcp6)
check_for_dhcp_inotify(in, now);
#endif
} }
} }
return hit; return hit;
} }
#endif #ifdef HAVE_DHCP
/* initialisation for dhcp-hostdir. Set inotify watch for each directory, and read pre-existing files */
void set_dhcp_inotify(void)
{
struct hostsfile *ah;
for (ah = daemon->inotify_hosts; ah; ah = ah->next)
{
DIR *dir_stream = NULL;
struct dirent *ent;
struct stat buf;
if (stat(ah->fname, &buf) == -1 || !(S_ISDIR(buf.st_mode)))
{
my_syslog(LOG_ERR, _("bad directory in dhcp-hostsdir %s"), ah->fname);
continue;
}
if (!(ah->flags & AH_WD_DONE))
{
ah->wd = inotify_add_watch(daemon->inotifyfd, ah->fname, IN_CLOSE_WRITE | IN_MOVED_TO);
ah->flags |= AH_WD_DONE;
}
/* Read contents of dir _after_ calling add_watch, in the ho[e of avoiding
a race which misses files being added as we start */
if (ah->wd == -1 || !(dir_stream = opendir(ah->fname)))
{
my_syslog(LOG_ERR, _("failed to create inotify for %s"), ah->fname);
continue;
}
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
if ((path = whine_malloc(lendir + lenfile + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, ent->d_name);
/* ignore non-regular files */
if (stat(path, &buf) != -1 && S_ISREG(buf.st_mode))
option_read_hostsfile(path);
free(path);
}
}
}
}
static void check_for_dhcp_inotify(struct inotify_event *in, time_t now)
{
struct hostsfile *ah;
/* ignore emacs backups and dotfiles */
if (in->len == 0 ||
in->name[in->len - 1] == '~' ||
(in->name[0] == '#' && in->name[in->len - 1] == '#') ||
in->name[0] == '.')
return;
for (ah = daemon->inotify_hosts; ah; ah = ah->next)
if (ah->wd == in->wd)
{
size_t lendir = strlen(ah->fname);
char *path;
if ((path = whine_malloc(lendir + in->len + 2)))
{
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, in->name);
if (option_read_hostsfile(path))
{
/* Propogate the consequences of loading a new dhcp-host */
dhcp_update_configs(daemon->dhcp_conf);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns(1);
}
free(path);
}
return;
}
}
#endif /* DHCP */
#endif /* LINUX_NETWORK */
+52 -6
View File
@@ -147,6 +147,9 @@ struct myoption {
#define LOPT_LOCAL_SERVICE 335 #define LOPT_LOCAL_SERVICE 335
#define LOPT_DNSSEC_TIME 336 #define LOPT_DNSSEC_TIME 336
#define LOPT_LOOP_DETECT 337 #define LOPT_LOOP_DETECT 337
#define LOPT_IGNORE_ADDR 338
#define LOPT_MINCTTL 339
#define LOPT_DHCP_INOTIFY 340
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -159,7 +162,7 @@ static const struct myoption opts[] =
{ "no-poll", 0, 0, 'n' }, { "no-poll", 0, 0, 'n' },
{ "help", 0, 0, 'w' }, { "help", 0, 0, 'w' },
{ "no-daemon", 0, 0, 'd' }, { "no-daemon", 0, 0, 'd' },
{ "log-queries", 0, 0, 'q' }, { "log-queries", 2, 0, 'q' },
{ "user", 2, 0, 'u' }, { "user", 2, 0, 'u' },
{ "group", 2, 0, 'g' }, { "group", 2, 0, 'g' },
{ "resolv-file", 2, 0, 'r' }, { "resolv-file", 2, 0, 'r' },
@@ -181,6 +184,7 @@ static const struct myoption opts[] =
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE }, { "local-service", 0, 0, LOPT_LOCAL_SERVICE },
{ "bogus-priv", 0, 0, 'b' }, { "bogus-priv", 0, 0, 'b' },
{ "bogus-nxdomain", 1, 0, 'B' }, { "bogus-nxdomain", 1, 0, 'B' },
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
{ "selfmx", 0, 0, 'e' }, { "selfmx", 0, 0, 'e' },
{ "filterwin2k", 0, 0, 'f' }, { "filterwin2k", 0, 0, 'f' },
{ "pid-file", 2, 0, 'x' }, { "pid-file", 2, 0, 'x' },
@@ -244,6 +248,7 @@ static const struct myoption opts[] =
{ "interface-name", 1, 0, LOPT_INTNAME }, { "interface-name", 1, 0, LOPT_INTNAME },
{ "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST }, { "dhcp-hostsfile", 1, 0, LOPT_DHCP_HOST },
{ "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS }, { "dhcp-optsfile", 1, 0, LOPT_DHCP_OPTS },
{ "dhcp-hostsdir", 1, 0, LOPT_DHCP_INOTIFY },
{ "dhcp-no-override", 0, 0, LOPT_OVERRIDE }, { "dhcp-no-override", 0, 0, LOPT_OVERRIDE },
{ "tftp-port-range", 1, 0, LOPT_TFTPPORTS }, { "tftp-port-range", 1, 0, LOPT_TFTPPORTS },
{ "stop-dns-rebind", 0, 0, LOPT_REBIND }, { "stop-dns-rebind", 0, 0, LOPT_REBIND },
@@ -253,6 +258,7 @@ static const struct myoption opts[] =
{ "dhcp-broadcast", 2, 0, LOPT_BROADCAST }, { "dhcp-broadcast", 2, 0, LOPT_BROADCAST },
{ "neg-ttl", 1, 0, LOPT_NEGTTL }, { "neg-ttl", 1, 0, LOPT_NEGTTL },
{ "max-ttl", 1, 0, LOPT_MAXTTL }, { "max-ttl", 1, 0, LOPT_MAXTTL },
{ "min-cache-ttl", 1, 0, LOPT_MINCTTL },
{ "max-cache-ttl", 1, 0, LOPT_MAXCTTL }, { "max-cache-ttl", 1, 0, LOPT_MAXCTTL },
{ "dhcp-alternate-port", 2, 0, LOPT_ALTPORT }, { "dhcp-alternate-port", 2, 0, LOPT_ALTPORT },
{ "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR }, { "dhcp-scriptuser", 1, 0, LOPT_SCRIPTUSR },
@@ -331,6 +337,7 @@ static struct {
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL }, { 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
{ LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL }, { LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
{ LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL }, { LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
{ LOPT_DHCP_INOTIFY, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from a directory."), NULL },
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL }, { LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE }, { 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE }, { 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
@@ -355,7 +362,7 @@ static struct {
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL}, { LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
{ 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL }, { 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" }, { 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL }, { 'q', ARG_DUP, NULL, gettext_noop("Log DNS queries."), NULL },
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL }, { 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL }, { 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE }, { 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
@@ -368,6 +375,8 @@ static struct {
{ 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL }, { 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
{ LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL }, { LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL }, { LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
{ LOPT_MAXCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live ceiling for cache."), NULL },
{ LOPT_MINCTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live floor for cache."), NULL },
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER }, { 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL }, { 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL }, { 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
@@ -457,6 +466,7 @@ static struct {
{ LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL }, { LOPT_QUIET_RA, OPT_QUIET_RA, NULL, gettext_noop("Do not log RA."), NULL },
{ LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL }, { LOPT_LOCAL_SERVICE, OPT_LOCAL_SERVICE, NULL, gettext_noop("Accept queries only from directly-connected networks"), NULL },
{ LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL }, { LOPT_LOOP_DETECT, OPT_LOOP_DETECT, NULL, gettext_noop("Detect and remove DNS forwarding loops"), NULL },
{ LOPT_IGNORE_ADDR, ARG_DUP, "<ipaddr>", gettext_noop("Ignore DNS responses containing ipaddr."), NULL },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
@@ -1702,8 +1712,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
#endif /* HAVE_DHCP */ #endif /* HAVE_DHCP */
case LOPT_DHCP_HOST: /* --dhcp-hostfile */ case LOPT_DHCP_HOST: /* --dhcp-hostsfile */
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */ case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
case LOPT_DHCP_INOTIFY: /* dhcp-hostsdir */
case 'H': /* --addn-hosts */ case 'H': /* --addn-hosts */
{ {
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile)); struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
@@ -1726,6 +1737,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->dhcp_opts_file; new->next = daemon->dhcp_opts_file;
daemon->dhcp_opts_file = new; daemon->dhcp_opts_file = new;
} }
else if (option == LOPT_DHCP_INOTIFY)
{
new->next = daemon->inotify_hosts;
daemon->inotify_hosts = new;
}
break; break;
} }
@@ -2119,14 +2136,23 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
case 'B': /* --bogus-nxdomain */ case 'B': /* --bogus-nxdomain */
{ case LOPT_IGNORE_ADDR: /* --ignore-address */
{
struct in_addr addr; struct in_addr addr;
unhide_metas(arg); unhide_metas(arg);
if (arg && (inet_pton(AF_INET, arg, &addr) > 0)) if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
{ {
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr)); struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
baddr->next = daemon->bogus_addr; if (option == 'B')
daemon->bogus_addr = baddr; {
baddr->next = daemon->bogus_addr;
daemon->bogus_addr = baddr;
}
else
{
baddr->next = daemon->ignore_addr;
daemon->ignore_addr = baddr;
}
baddr->addr = addr; baddr->addr = addr;
} }
else else
@@ -2409,6 +2435,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err); ret_err(gen_err);
break; break;
case 'q': /* --log-queries */
set_option_bool(OPT_LOG);
if (arg && strcmp(arg, "extra") == 0)
set_option_bool(OPT_EXTRALOG);
break;
case LOPT_MAX_LOGS: /* --log-async */ case LOPT_MAX_LOGS: /* --log-async */
daemon->max_logs = LOG_MAX; /* default */ daemon->max_logs = LOG_MAX; /* default */
if (arg && !atoi_check(arg, &daemon->max_logs)) if (arg && !atoi_check(arg, &daemon->max_logs))
@@ -2438,6 +2470,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'T': /* --local-ttl */ case 'T': /* --local-ttl */
case LOPT_NEGTTL: /* --neg-ttl */ case LOPT_NEGTTL: /* --neg-ttl */
case LOPT_MAXTTL: /* --max-ttl */ case LOPT_MAXTTL: /* --max-ttl */
case LOPT_MINCTTL: /* --min-cache-ttl */
case LOPT_MAXCTTL: /* --max-cache-ttl */ case LOPT_MAXCTTL: /* --max-cache-ttl */
case LOPT_AUTHTTL: /* --auth-ttl */ case LOPT_AUTHTTL: /* --auth-ttl */
{ {
@@ -2448,6 +2481,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->neg_ttl = (unsigned long)ttl; daemon->neg_ttl = (unsigned long)ttl;
else if (option == LOPT_MAXTTL) else if (option == LOPT_MAXTTL)
daemon->max_ttl = (unsigned long)ttl; daemon->max_ttl = (unsigned long)ttl;
else if (option == LOPT_MINCTTL)
{
if (ttl > TTL_FLOOR_LIMIT)
ttl = TTL_FLOOR_LIMIT;
daemon->min_cache_ttl = (unsigned long)ttl;
}
else if (option == LOPT_MAXCTTL) else if (option == LOPT_MAXCTTL)
daemon->max_cache_ttl = (unsigned long)ttl; daemon->max_cache_ttl = (unsigned long)ttl;
else if (option == LOPT_AUTHTTL) else if (option == LOPT_AUTHTTL)
@@ -4012,6 +4051,13 @@ static void read_file(char *file, FILE *f, int hard_opt)
fclose(f); fclose(f);
} }
#ifdef HAVE_DHCP
int option_read_hostsfile(char *file)
{
return one_file(file, LOPT_BANK);
}
#endif
static int one_file(char *file, int hard_opt) static int one_file(char *file, int hard_opt)
{ {
FILE *f; FILE *f;
+38 -1
View File
@@ -1328,6 +1328,43 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
return 0; return 0;
} }
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr)
{
unsigned char *p;
int i, qtype, qclass, rdlen;
struct bogus_addr *baddrp;
/* skip over questions */
if (!(p = skip_questions(header, qlen)))
return 0; /* bad packet */
for (i = ntohs(header->ancount); i != 0; i--)
{
if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
p += 4; /* TTL */
GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A)
{
if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
return 1;
}
if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
}
return 0;
}
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp, int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...) unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
{ {
@@ -1606,7 +1643,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(F_UPSTREAM, name, NULL, "secure no DS"); log_query(F_UPSTREAM, name, NULL, "no DS");
} }
else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL))) else if ((keydata = blockdata_retrieve(crecp->addr.ds.keydata, crecp->addr.ds.keylen, NULL)))
{ {
+1
View File
@@ -274,6 +274,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (s1->sa.sa_family == AF_INET6 && if (s1->sa.sa_family == AF_INET6 &&
s1->in6.sin6_port == s2->in6.sin6_port && s1->in6.sin6_port == s2->in6.sin6_port &&
s1->in6.sin6_scope_id == s2->in6.sin6_scope_id &&
IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr)) IN6_ARE_ADDR_EQUAL(&s1->in6.sin6_addr, &s2->in6.sin6_addr))
return 1; return 1;
#endif #endif