Compare commits

...
30 Commits
Author SHA1 Message Date
Wang Jian 49752b90d5 Log IPSET actions. 2014-03-28 20:52:47 +00:00
Simon Kelley e98bd52e25 Add --dnssec-no-timecheck 2014-03-28 20:41:23 +00:00
Simon Kelley 8a8bbad0cf Ensure ->sentto is valid for DNSSEC forwards. Otherwise retries SEGV. 2014-03-27 22:02:17 +00:00
Simon Kelley fec216df32 Cache stats availble in CHAOS .bind domain. 2014-03-27 20:54:34 +00:00
Simon Kelley 4e1fe44428 Terminate DS-search when reaching the root via cache entries. 2014-03-26 12:24:19 +00:00
Simon Kelley 51967f9807 SERVFAIL is an expected error return, don't try all servers. 2014-03-25 21:07:00 +00:00
Tomas Hozza b37f8b99ae Handle failure of hash_questions() 2014-03-25 20:52:28 +00:00
Tomas Hozza fc2833f172 Memory leak in error path. 2014-03-25 20:43:21 +00:00
Simon Kelley 490f90758d Reorder sanity checks on UDP packet reception, to cope with failed recvfrom() 2014-03-24 22:04:42 +00:00
Simon Kelley 56618c31f6 Add dnssec-check-unsigned to example config file. 2014-03-24 21:13:49 +00:00
Simon Kelley 604f7598c2 CHANGELOG update. 2014-03-22 19:33:43 +00:00
Simon Kelley 2a7a2b84ec Ignore DNS queries from port 0: http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html 2014-03-22 19:18:06 +00:00
Andy 3e21a1a6fa Tidy uid defines. 2014-03-22 19:10:07 +00:00
Simon Kelley 2b29191e7c Fix DNSSEC crash retrying to IPv6 server. 2014-03-21 11:13:55 +00:00
Simon Kelley 03431d6373 Initialise uid when creating CNAME cache record. 2014-03-20 16:25:43 +00:00
Simon Kelley cc1a29e250 Make --quiet-dhcp apply to DHCPDISCOVER when client ignored. 2014-03-20 15:47:18 +00:00
Moritz Warning e62e9b6187 Manpage typos. 2014-03-20 15:32:22 +00:00
Simon Kelley 19c51cfa49 Tidy and fix cache->uid handling.
Some CNAMES left the value of ->uid undefined.

Since there are now special values if this, for CNAMES
to interface names, that could cause a crash
if the undefined value hit the special value.

Also ensure that the special value can't arise
when the uid is encoding the source of an F_CONFIG
record, in case there's a CNAME to it.
2014-03-18 22:38:30 +00:00
Andy d5082158ee Ensure next_uid() can never return 0. 2014-03-17 19:50:29 +00:00
Simon Kelley 3f7483e816 Handle integer overflow in uid counter. Fixes rare crashes in cache code. 2014-03-16 22:56:58 +00:00
Simon Kelley 0c8584eabc Warn about non-local queries once only for UDP. 2014-03-12 20:12:56 +00:00
Simon Kelley f00690f93e Typo 2014-03-12 20:07:12 +00:00
Simon Kelley 89b12ed35b OPT_LOCAL_SERVICE needs up-to-date interface list too. 2014-03-06 13:27:57 +00:00
Simon Kelley 1a9a3489ec Set --local-service in Debian package startup. 2014-03-05 15:01:08 +00:00
Simon Kelley c8a80487cd --local-service. Default protection from DNS amplification attacks. 2014-03-05 14:29:54 +00:00
Simon Kelley 4ea8e80dd9 Add --static to pkg-config command when appropriate. 2014-03-05 11:01:23 +00:00
Simon Kelley c07d30dcb1 Compiler warning. 2014-03-03 14:19:19 +00:00
Simon Kelley d588ab54d4 Man page updates for DNSSEC. 2014-03-02 14:30:05 +00:00
Simon Kelley f8b422a7b6 KEYBLOCK LEN better as a multiple of 8. 2014-03-02 12:46:51 +00:00
Simon Kelley 29fe922b14 Can have local DS records (trust anchors). 2014-03-01 22:53:57 +00:00
16 changed files with 610 additions and 186 deletions

No files matched your search

+14 -1
View File
@@ -67,7 +67,20 @@ version 2.69
Add --servers-file. Allows dynamic update of upstream servers
full access to configuration.
Add --local-service. Accept DNS queries only from hosts
whose address is on a local subnet, ie a subnet for which
an interface exists on the server. This option
only has effect if there are no --interface --except-interface,
--listen-address or --auth-server options. It is intended
to be set as a default on installation, to allow
unconfigured installations to be useful but also safe from
being used for DNS amplification attacks.
Fix crashes in cache_get_cname_target() when dangling CNAMEs
encountered. Thanks to Andy and the rt-n56u project for
find this and helping to chase it down.
version 2.68
Use random addresses for DHCPv6 temporary address
allocations, instead of algorithmically determined stable
+4 -1
View File
@@ -14,8 +14,11 @@ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
if [ $op = "--copy" ]; then
pkg="$*"
elif grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
echo $in | grep ${search}_STATIC >/dev/null 2>&1; then
pkg=`$pkg --static $op $*`
else
pkg=`$pkg $op $*`
pkg=`$pkg $op $*`
fi
if grep "^\#[[:space:]]*define[[:space:]]*${search}_STATIC" config.h >/dev/null 2>&1 || \
+6
View File
@@ -1,6 +1,12 @@
dnsmasq (2.69-1) unstable; urgency=low
* New upstream.
* Set --local-service. (closes: #732610)
This tells dnsmasq to ignore DNS requests that don't come from a local network.
It's automatically ignored if --interface --except-interface, --listen-address
or --auth-server exist in the configuration, so for most installations, it will
have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
from being vulnerable to DNS-reflection attacks.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
Vendored
+8
View File
@@ -90,6 +90,14 @@ if [ ! "$DNSMASQ_USER" ]; then
DNSMASQ_USER="dnsmasq"
fi
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
# It's automatically ignored if --interface --except-interface, --listen-address
# or --auth-server exist in the configuration, so for most installations, it will
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
# from being vulnerable to DNS-reflection attacks.
DNSMASQ_OPTS="$DNSMASQ_OPTS --local-service"
start()
{
# Return
+8
View File
@@ -25,6 +25,14 @@
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
#dnssec
# Replies which are not DNSSEC signed may be legitimate, because the domain
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
# check that an unsigned reply is OK, by finding a secure proof that a DS
# record somewhere between the root and the domain does not exist.
# The cost of setting this is that even queries in unsigned domains will need
# one or more extra DNS queries to verify.
#dnssec-check-unsigned
# Uncomment this to filter useless windows-originated DNS requests
# which can trigger dial-on-demand links needlessly.
# Note that (amongst other things) this blocks all SRV requests,
+44 -6
View File
@@ -208,6 +208,14 @@ resolve in the global DNS to a A and/or AAAA record which points to
the address dnsmasq is listening on. When an interface is specified,
it may be qualified with "/4" or "/6" to specify only the IPv4 or IPv6
addresses associated with the interface.
.TP
.B --local-service
Accept DNS queries only from hosts whose address is on a local subnet,
ie a subnet for which an interface exists on the server. This option
only has effect is there are no --interface --except-interface,
--listen-address or --auth-server options. It is intended to be set as
a default on installation, to allow unconfigured installations to be
useful but also safe from being used for DNS amplification attacks.
.TP
.B \-2, --no-dhcp-interface=<interface name>
Do not provide DHCP or TFTP on the specified interface, but do provide DNS service.
@@ -599,7 +607,15 @@ clients unable to do validation, use of the AD bit set by dnsmasq is useful, pro
the dnsmasq server and the client is trusted. Dnsmasq must be compiled with HAVE_DNSSEC enabled, and DNSSEC
trust anchors provided, see
.B --trust-anchor.
Because the DNSSEC validation process uses the cache, it is not permitted to reduce the cache size below the default when DNSSEC is enabled.
Because the DNSSEC validation process uses the cache, it is not
permitted to reduce the cache size below the default when DNSSEC is
enabled. The nameservers upstream of dnsmasq must be DNSSEC-capable,
ie capable of returning DNSSEC records with data. If they are not,
then dnsmasq will not be able to determine the trusted status of
answers. In the default mode, this menas that all replies will be
marked as untrusted. If
.B --dnssec-check-unsigned
is set and the upstream servers don't support DNSSEC, then DNS service will be entirely broken.
.TP
.B --trust-anchor=[<class>],<domain>,<key-tag>,<algorithm>,<digest-type>,<digest>
Provide DS records to act a trust anchors for DNSSEC
@@ -615,7 +631,19 @@ legitimate: they are assumed to be valid and passed on (without the
attacker forging unsigned replies for signed DNS zones, but it is
fast. If this flag is set, dnsmasq will check the zones of unsigned
replies, to ensure that unsigned replies are allowed in those
zones. The cost of this is more upstream queries and slower performance.
zones. The cost of this is more upstream queries and slower
performance. See also the warning about upstream servers in the
section on
.B --dnssec
.TP
.B --dnssec-no-timecheck
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
interesting chicken-and-egg problem for machines which don't have a hardware real time clock. For these machines to determine the correct
time typically requires use of NTP and therefore DNS, but validating DNS requires that the correct time is already known. Setting this flag
removes the time-window checks (but not other DNSSEC validation.) only until the dnsmasq process receives SIGHUP. The intention is
that dnsmasq should be started with this flag when the platform determines that reliable time is not currently available. As soon as
reliable time is established, a SIGHUP should be sent to dnsmasq, which enables time checking, and purges the cache of DNS records
which have not been throughly checked.
.TP
.B --proxy-dnssec
Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
@@ -754,7 +782,7 @@ or from /etc/ethers will be served. A static-only subnet with address
all zeros may be used as a "catch-all" address to enable replies to all
Information-request packets on a subnet which is provided with
stateless DHCPv6, ie
.B --dhcp=range=::,static
.B --dhcp-range=::,static
For IPv4, the <mode> may be
.B proxy
@@ -1734,12 +1762,22 @@ When it receives a SIGUSR1,
writes statistics to the system log. It writes the cache size,
the number of names which have had to removed from the cache before
they expired in order to make room for new names and the total number
of names that have been inserted into the cache. For each upstream
of names that have been inserted into the cache. The number of cache hits and
misses and the number of authoritative queries answered are also given. For each upstream
server it gives the number of queries sent, and the number which
resulted in an error. In
.B --no-daemon
mode or when full logging is enabled (-q), a complete dump of the
contents of the cache is made.
contents of the cache is made.
The cache statistics are also available in the DNS as answers to
queries of class CHAOS and type TXT in domain bind. The domain names are cachesize.bind, insertions.bind, evictions.bind,
misses.bind, hits.bind, auth.bind and servers.bind. An example command to query this, using the
.B dig
utility would be
dig +short chaos txt cachesize.bind
.PP
When it receives SIGUSR2 and it is logging direct to a file (see
.B --log-facility
@@ -1843,7 +1881,7 @@ which has tags will be used in preference to an untagged
.B dhcp-option,
provided that _all_ the tags match somewhere in the
set collected as described above. The prefix '!' on a tag means 'not'
so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
so --dhcp-option=tag:!purple,3,1.2.3.4 sends the option when the
tag purple is not in the set of valid tags. (If using this in a
command line rather than a configuration file, be sure to escape !,
which is a shell metacharacter)
+133 -17
View File
@@ -24,7 +24,6 @@ static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error;
static union bigname *big_free = NULL;
static int bignames_left, hash_size;
static int uid = 1;
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
static const struct {
@@ -73,6 +72,19 @@ static void cache_link(struct crec *crecp);
static void rehash(int size);
static void cache_hash(struct crec *crecp);
static unsigned int next_uid(void)
{
static unsigned int uid = 0;
uid++;
/* uid == 0 used to indicate CNAME to interface name. */
if (uid == SRC_INTERFACE)
uid++;
return uid;
}
void cache_init(void)
{
struct crec *crecp;
@@ -88,7 +100,7 @@ void cache_init(void)
{
cache_link(crecp);
crecp->flags = 0;
crecp->uid = uid++;
crecp->uid = next_uid();
}
}
@@ -192,10 +204,7 @@ static void cache_free(struct crec *crecp)
{
crecp->flags &= ~F_FORWARD;
crecp->flags &= ~F_REVERSE;
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
if (uid == -1)
uid++;
crecp->uid = next_uid(); /* invalidate CNAMES pointing to this. */
if (cache_tail)
cache_tail->next = crecp;
@@ -256,7 +265,7 @@ char *cache_get_name(struct crec *crecp)
char *cache_get_cname_target(struct crec *crecp)
{
if (crecp->addr.cname.uid != -1)
if (crecp->addr.cname.uid != SRC_INTERFACE)
return cache_get_name(crecp->addr.cname.target.cache);
return crecp->addr.cname.target.int_name->name;
@@ -289,7 +298,7 @@ struct crec *cache_enumerate(int init)
static int is_outdated_cname_pointer(struct crec *crecp)
{
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == -1)
if (!(crecp->flags & F_CNAME) || crecp->addr.cname.uid == SRC_INTERFACE)
return 0;
/* NB. record may be reused as DS or DNSKEY, where uid is
@@ -774,13 +783,14 @@ static void add_hosts_cname(struct crec *target)
crec->name.namep = a->alias;
crec->addr.cname.target.cache = target;
crec->addr.cname.uid = target->uid;
crec->uid = next_uid();
cache_hash(crec);
add_hosts_cname(crec); /* handle chains */
}
}
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
int index, struct crec **rhash, int hashsz)
unsigned int index, struct crec **rhash, int hashsz)
{
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
int i, nameexists = 0;
@@ -884,7 +894,7 @@ static int gettok(FILE *f, char *token)
}
}
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
static int read_hostsfile(char *filename, unsigned int index, int cache_size, struct crec **rhash, int hashsz)
{
FILE *f = fopen(filename, "r");
char *token = daemon->namebuff, *domain_suffix = NULL;
@@ -1034,7 +1044,8 @@ void cache_reload(void)
cache->flags = F_FORWARD | F_NAMEP | F_CNAME | F_IMMORTAL | F_CONFIG;
cache->name.namep = a->alias;
cache->addr.cname.target.int_name = intr;
cache->addr.cname.uid = -1;
cache->addr.cname.uid = SRC_INTERFACE;
cache->uid = next_uid();
cache_hash(cache);
add_hosts_cname(cache); /* handle chains */
}
@@ -1070,7 +1081,7 @@ void cache_reload(void)
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
}
#ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
@@ -1078,7 +1089,7 @@ void cache_reload(void)
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, SRC_CONFIG, (struct crec **)daemon->packet, revhashsz);
}
#endif
}
@@ -1091,7 +1102,7 @@ void cache_reload(void)
}
if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
total_size = read_hostsfile(HOSTSFILE, SRC_HOSTS, total_size, (struct crec **)daemon->packet, revhashsz);
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
for (ah = daemon->addn_hosts; ah; ah = ah->next)
@@ -1155,6 +1166,7 @@ static void add_dhcp_cname(struct crec *target, time_t ttd)
aliasc->name.namep = a->alias;
aliasc->addr.cname.target.cache = target;
aliasc->addr.cname.uid = target->uid;
aliasc->uid = next_uid();
cache_hash(aliasc);
add_dhcp_cname(aliasc, ttd);
}
@@ -1242,7 +1254,7 @@ void cache_add_dhcp_entry(char *host_name, int prot,
crec->ttd = ttd;
crec->addr.addr = *host_address;
crec->name.namep = host_name;
crec->uid = uid++;
crec->uid = next_uid();
cache_hash(crec);
add_dhcp_cname(crec, ttd);
@@ -1250,6 +1262,101 @@ void cache_add_dhcp_entry(char *host_name, int prot,
}
#endif
int cache_make_stat(struct txt_record *t)
{
static char *buff = NULL;
static int bufflen = 60;
int len;
struct server *serv, *serv1;
char *p;
if (!buff && !(buff = whine_malloc(60)))
return 0;
p = buff;
switch (t->stat)
{
case TXT_STAT_CACHESIZE:
sprintf(buff+1, "%d", daemon->cachesize);
break;
case TXT_STAT_INSERTS:
sprintf(buff+1, "%d", cache_inserted);
break;
case TXT_STAT_EVICTIONS:
sprintf(buff+1, "%d", cache_live_freed);
break;
case TXT_STAT_MISSES:
sprintf(buff+1, "%u", daemon->queries_forwarded);
break;
case TXT_STAT_HITS:
sprintf(buff+1, "%u", daemon->local_answer);
break;
#ifdef HAVE_AUTH
case TXT_STAT_AUTH:
sprintf(buff+1, "%u", daemon->auth_answer);
break;
#endif
case TXT_STAT_SERVERS:
/* sum counts from different records for same server */
for (serv = daemon->servers; serv; serv = serv->next)
serv->flags &= ~SERV_COUNTED;
for (serv = daemon->servers; serv; serv = serv->next)
if (!(serv->flags &
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
{
char *new, *lenp;
int port, newlen, bytes_avail, bytes_needed;
unsigned int queries = 0, failed_queries = 0;
for (serv1 = serv; serv1; serv1 = serv1->next)
if (!(serv1->flags &
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
sockaddr_isequal(&serv->addr, &serv1->addr))
{
serv1->flags |= SERV_COUNTED;
queries += serv1->queries;
failed_queries += serv1->failed_queries;
}
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
lenp = p++; /* length */
bytes_avail = (p - buff) + bufflen;
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
if (bytes_needed >= bytes_avail)
{
/* expand buffer if necessary */
newlen = bytes_needed + 1 + bufflen - bytes_avail;
if (!(new = whine_malloc(newlen)))
return 0;
memcpy(new, buff, bufflen);
free(buff);
p = new + (p - buff);
lenp = p - 1;
buff = new;
bufflen = newlen;
bytes_avail = (p - buff) + bufflen;
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
}
*lenp = bytes_needed;
p += bytes_needed;
}
t->txt = (unsigned char *)buff;
t->len = p - buff;
return 1;
}
len = strlen(buff+1);
t->txt = (unsigned char *)buff;
t->len = len + 1;
*buff = len;
return 1;
}
void dump_cache(time_t now)
{
@@ -1368,11 +1475,13 @@ void dump_cache(time_t now)
}
}
char *record_source(int index)
char *record_source(unsigned int index)
{
struct hostsfile *ah;
if (index == 0)
if (index == SRC_CONFIG)
return "config";
else if (index == SRC_HOSTS)
return HOSTSFILE;
for (ah = daemon->addn_hosts; ah; ah = ah->next)
@@ -1500,6 +1609,13 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
source = arg;
verb = "to";
}
else if (flags & F_IPSET)
{
source = "ipset add";
dest = name;
name = arg;
verb = daemon->addrbuff;
}
else
source = "cached";
+1 -1
View File
@@ -18,7 +18,7 @@
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define KEYBLOCK_LEN 35 /* 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 TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
+20 -3
View File
@@ -397,7 +397,7 @@ int main (int argc, char **argv)
piperead = pipefd[0];
pipewrite = pipefd[1];
/* prime the pipe to load stuff first time. */
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
send_event(pipewrite, EVENT_INIT, 0, NULL);
err_pipe[1] = -1;
@@ -661,10 +661,17 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("DBus support enabled: bus connection pending"));
}
#endif
if (option_bool(OPT_LOCAL_SERVICE))
my_syslog(LOG_INFO, _("DNS service limited to local subnets"));
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
{
my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
if (option_bool(OPT_DNSSEC_TIME))
my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
}
#endif
if (log_err != 0)
@@ -1127,8 +1134,18 @@ static void async_event(int pipe, time_t now)
switch (ev.event)
{
case EVENT_RELOAD:
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && option_bool(OPT_DNSSEC_TIME))
{
my_syslog(LOG_INFO, _("now checking DNSSEC signature timestamps"));
reset_option_bool(OPT_DNSSEC_TIME);
}
#endif
/* fall through */
case EVENT_INIT:
clear_cache_and_reload(now);
if (daemon->port != 0)
{
if (daemon->resolv_files && option_bool(OPT_NO_POLL))
+26 -6
View File
@@ -164,6 +164,7 @@ struct event_desc {
#define EVENT_FORK_ERR 18
#define EVENT_LUA_ERR 19
#define EVENT_TFTP_ERR 20
#define EVENT_INIT 21
/* Exit codes. */
#define EC_GOOD 0
@@ -230,10 +231,11 @@ struct event_desc {
#define OPT_QUIET_DHCP6 43
#define OPT_QUIET_RA 44
#define OPT_DNSSEC_VALID 45
#define OPT_DNSSEC_PERMISS 46
#define OPT_DNSSEC_TIME 46
#define OPT_DNSSEC_DEBUG 47
#define OPT_DNSSEC_NO_SIGN 48
#define OPT_LAST 49
#define OPT_LOCAL_SERVICE 49
#define OPT_LAST 50
/* 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. */
@@ -279,10 +281,19 @@ struct naptr {
struct naptr *next;
};
#define TXT_STAT_CACHESIZE 1
#define TXT_STAT_INSERTS 2
#define TXT_STAT_EVICTIONS 3
#define TXT_STAT_MISSES 4
#define TXT_STAT_HITS 5
#define TXT_STAT_AUTH 6
#define TXT_STAT_SERVERS 7
struct txt_record {
char *name;
unsigned char *txt;
unsigned short class, len;
int stat;
struct txt_record *next;
};
@@ -366,7 +377,7 @@ struct crec {
struct crec *cache;
struct interface_name *int_name;
} target;
int uid; /* -1 if union is interface-name */
unsigned int uid; /* 0 if union is interface-name */
} cname;
struct {
struct blockdata *keydata;
@@ -387,7 +398,7 @@ struct crec {
} addr;
time_t ttd; /* time to die */
/* used as class if DNSKEY/DS/RRSIG, index to source for F_HOSTS */
int uid;
unsigned int uid;
unsigned short flags;
union {
char sname[SMALLDNAME];
@@ -425,6 +436,13 @@ struct crec {
#define F_KEYTAG (1u<<23)
#define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
/* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0
#define SRC_CONFIG 1
#define SRC_HOSTS 2
#define SRC_AH 3
/* struct sockaddr is not large enough to hold any address,
@@ -524,7 +542,7 @@ struct hostsfile {
struct hostsfile *next;
int flags;
char *fname;
int index; /* matches to cache entries for logging */
unsigned int index; /* matches to cache entries for logging */
};
@@ -966,6 +984,7 @@ extern struct daemon {
pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
struct addrlist *interface_addrs; /* list of all addresses/prefix lengths associated with all local interfaces */
/* DHCP state */
int dhcpfd, helperfd, pxefd;
@@ -1003,7 +1022,7 @@ extern struct daemon {
/* cache.c */
void cache_init(void);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(int index);
char *record_source(unsigned int index);
char *querystr(char *desc, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
@@ -1019,6 +1038,7 @@ void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_addre
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
int cache_make_stat(struct txt_record *t);
char *cache_get_name(struct crec *crecp);
char *cache_get_cname_target(struct crec *crecp);
struct crec *cache_enumerate(int init);
+11 -5
View File
@@ -390,7 +390,13 @@ static int serial_compare_32(unsigned long s1, unsigned long s2)
/* Check whether today/now is between date_start and date_end */
static int check_date_range(unsigned long date_start, unsigned long date_end)
{
unsigned long curtime = time(0);
unsigned long curtime;
/* Checking timestamps may be temporarily disabled */
if (option_bool(OPT_DNSSEC_TIME))
return 1;
curtime = time(0);
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
return serial_compare_32(curtime, date_start) == SERIAL_GT
@@ -827,7 +833,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
for (; crecp; crecp = cache_find_by_name(crecp, keyname, now, F_DNSKEY))
if (crecp->addr.key.algo == algo &&
crecp->addr.key.keytag == key_tag &&
crecp->uid == class &&
crecp->uid == (unsigned int)class &&
verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
}
@@ -932,7 +938,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
if (recp1->addr.ds.algo == algo &&
recp1->addr.ds.keytag == keytag &&
recp1->uid == class &&
recp1->uid == (unsigned int)class &&
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
hash_init(hash, &ctx, &digest))
@@ -1918,14 +1924,14 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname)
{
unsigned char *p = (unsigned char *)(header+1);
int type, class, qtype, qclass, rdlen, j, rc;
int type, class, qclass, rdlen, j, rc;
int cname_count = CNAME_CHAIN;
/* Get question */
if (!extract_name(header, plen, &p, name, 1, 4))
return STAT_BOGUS;
GETSHORT(qtype, p);
p +=2; /* type */
GETSHORT(qclass, p);
while (1)
+149 -47
View File
@@ -278,7 +278,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
if (forward->sentto->addr.sa.sa_family)
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");
#ifdef HAVE_IPV6
else
@@ -299,7 +299,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (sendto(fd, (char *)header, plen, 0,
&forward->sentto->addr.sa,
sa_len(&forward->sentto->addr)) == -1 && retry_send());
sa_len(&forward->sentto->addr)) == -1 && retry_send());
return 1;
}
@@ -698,14 +698,20 @@ void reply_query(int fd, int family, time_t now)
serveraddr.in6.sin6_flowinfo = 0;
#endif
header = (struct dns_header *)daemon->packet;
if (n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR))
return;
/* spoof check: answer must come from known server, */
for (server = daemon->servers; server; server = server->next)
if (!(server->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)) &&
sockaddr_isequal(&server->addr, &serveraddr))
break;
header = (struct dns_header *)daemon->packet;
if (!server)
return;
#ifdef HAVE_DNSSEC
hash = hash_questions(header, n, daemon->namebuff);
#else
@@ -713,11 +719,9 @@ void reply_query(int fd, int family, time_t now)
crc = questions_crc(header, n, daemon->namebuff);
#endif
if (!server ||
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
!(forward = lookup_frec(ntohs(header->id), hash)))
if (!(forward = lookup_frec(ntohs(header->id), hash)))
return;
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
!option_bool(OPT_ORDER) &&
forward->forwardall == 0)
@@ -747,7 +751,7 @@ void reply_query(int fd, int family, time_t now)
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
if (RCODE(header) == REFUSED)
server = NULL;
else
{
@@ -770,8 +774,7 @@ void reply_query(int fd, int family, time_t now)
we get a good reply from another server. Kill it when we've
had replies from all to avoid filling the forwarding table when
everything is broken */
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
{
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0;
@@ -784,7 +787,7 @@ void reply_query(int fd, int family, time_t now)
no_cache_dnssec = 1;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
if (server && option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
{
int status;
@@ -850,6 +853,7 @@ void reply_query(int fd, int family, time_t now)
*new = *forward; /* copy everything, then overwrite */
new->next = next;
new->blocking_query = NULL;
new->sentto = server;
new->rfd4 = NULL;
#ifdef HAVE_IPV6
new->rfd6 = NULL;
@@ -1076,11 +1080,60 @@ void receive_query(struct listener *listen, time_t now)
return;
source_addr.sa.sa_family = listen->family;
if (listen->family == AF_INET)
{
/* Source-port == 0 is an error, we can't send back to that.
http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
if (source_addr.in.sin_port == 0)
return;
}
#ifdef HAVE_IPV6
if (listen->family == AF_INET6)
source_addr.in6.sin6_flowinfo = 0;
else
{
/* Source-port == 0 is an error, we can't send back to that. */
if (source_addr.in6.sin6_port == 0)
return;
source_addr.in6.sin6_flowinfo = 0;
}
#endif
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
if (option_bool(OPT_LOCAL_SERVICE))
{
struct addrlist *addr;
#ifdef HAVE_IPV6
if (listen->family == AF_INET6)
{
for (addr = daemon->interface_addrs; addr; addr = addr->next)
if ((addr->flags & ADDRLIST_IPV6) &&
is_same_net6(&addr->addr.addr.addr6, &source_addr.in6.sin6_addr, addr->prefixlen))
break;
}
else
#endif
{
struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next)
{
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
break;
}
}
if (!addr)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
warned = 1;
}
return;
}
}
if (check_dst)
{
struct ifreq ifr;
@@ -1276,6 +1329,10 @@ static int send_check_sign(time_t now, struct dns_header *header, size_t plen, c
continue;
}
/* Reached the root */
if (!name_start)
return STAT_BOGUS;
strcpy(keyname, name_start);
return STAT_NEED_DS_NEG;
}
@@ -1341,8 +1398,11 @@ static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
struct crec *crecp = cache_find_by_name(NULL, name_start, now, F_DS);
if (--(*keycount) == 0)
return STAT_BOGUS;
{
free(packet);
return STAT_BOGUS;
}
if (crecp && (crecp->flags & F_DNSSECOK))
{
free(packet);
@@ -1357,46 +1417,55 @@ static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
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);
/* We rely on the question section coming back unchanged, ensure it is with the hash. */
if ((newhash = hash_questions(header, (unsigned int)m, name)))
memcpy(hash, newhash, HASH_SIZE);
*length = htons(m);
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))
{
m = (c1 << 8) | c2;
memcpy(hash, newhash, HASH_SIZE);
*length = htons(m);
newhash = hash_questions(header, (unsigned int)m, name);
if (newhash && memcmp(hash, newhash, HASH_SIZE) == 0)
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))
{
/* 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;
}
m = (c1 << 8) | c2;
/* No DS, not got to DNSSEC-land yet, go up. */
if (status == STAT_INSECURE)
newhash = hash_questions(header, (unsigned int)m, name);
if (newhash && memcmp(hash, newhash, HASH_SIZE) == 0)
{
p = (unsigned char *)(header+1);
/* Note this trashes all three name workspaces */
status = tcp_key_recurse(now, STAT_NEED_DS_NEG, header, m, class, name, keyname, server, keycount);
if (extract_name(header, plen, &p, name, 1, 4) &&
(name_start = strchr(name, '.')))
/* 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)
{
name_start++; /* chop a label off and try again */
continue;
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;
}
}
}
}
@@ -1544,6 +1613,37 @@ unsigned char *tcp_request(int confd, time_t now,
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
return packet;
/* We can be configured to only accept queries from at-most-one-hop-away addresses. */
if (option_bool(OPT_LOCAL_SERVICE))
{
struct addrlist *addr;
#ifdef HAVE_IPV6
if (peer_addr.sa.sa_family == AF_INET6)
{
for (addr = daemon->interface_addrs; addr; addr = addr->next)
if ((addr->flags & ADDRLIST_IPV6) &&
is_same_net6(&addr->addr.addr.addr6, &peer_addr.in6.sin6_addr, addr->prefixlen))
break;
}
else
#endif
{
struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next)
{
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
break;
}
}
if (!addr)
{
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
return packet;
}
}
while (1)
{
@@ -1644,6 +1744,8 @@ unsigned char *tcp_request(int confd, time_t now,
unsigned char *newhash, hash[HASH_SIZE];
if ((newhash = hash_questions(header, (unsigned int)size, daemon->keyname)))
memcpy(hash, newhash, HASH_SIZE);
else
memset(hash, 0, HASH_SIZE);
#else
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
#endif
+44 -1
View File
@@ -268,7 +268,40 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
if (!label)
label = ifr.ifr_name;
/* maintain a list of all addresses on all interfaces for --local-service option */
if (option_bool(OPT_LOCAL_SERVICE))
{
struct addrlist *al;
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
al->next = daemon->interface_addrs;
daemon->interface_addrs = al;
al->prefixlen = prefixlen;
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr.addr4 = addr->in.sin_addr;
al->flags = 0;
}
#ifdef HAVE_IPV6
else
{
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
}
#endif
}
}
#ifdef HAVE_IPV6
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
@@ -565,6 +598,15 @@ int enumerate_interfaces(int reset)
intname->addr = NULL;
}
/* Remove list of addresses of local interfaces */
for (addr = daemon->interface_addrs; addr; addr = tmp)
{
tmp = addr->next;
addr->next = spare;
spare = addr;
}
daemon->interface_addrs = NULL;
#ifdef HAVE_AUTH
/* remove addresses stored against auth_zone subnets, but not
ones configured as address literals */
@@ -1528,7 +1570,8 @@ void newaddress(time_t now)
{
(void)now;
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
enumerate_interfaces(0);
if (option_bool(OPT_CLEVERBIND))
+118 -91
View File
@@ -64,86 +64,88 @@ struct myoption {
#define OPTSTRING "951yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:4:6:7:8:0:3:"
/* options which don't have a one-char version */
#define LOPT_RELOAD 256
#define LOPT_NO_NAMES 257
#define LOPT_TFTP 258
#define LOPT_SECURE 259
#define LOPT_PREFIX 260
#define LOPT_PTR 261
#define LOPT_BRIDGE 262
#define LOPT_TFTP_MAX 263
#define LOPT_FORCE 264
#define LOPT_NOBLOCK 265
#define LOPT_LOG_OPTS 266
#define LOPT_MAX_LOGS 267
#define LOPT_CIRCUIT 268
#define LOPT_REMOTE 269
#define LOPT_SUBSCR 270
#define LOPT_INTNAME 271
#define LOPT_BANK 272
#define LOPT_DHCP_HOST 273
#define LOPT_APREF 274
#define LOPT_OVERRIDE 275
#define LOPT_TFTPPORTS 276
#define LOPT_REBIND 277
#define LOPT_NOLAST 278
#define LOPT_OPTS 279
#define LOPT_DHCP_OPTS 280
#define LOPT_MATCH 281
#define LOPT_BROADCAST 282
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#define LOPT_DHCP_FQDN 289
#define LOPT_CNAME 290
#define LOPT_PXE_PROMT 291
#define LOPT_PXE_SERV 292
#define LOPT_TEST 293
#define LOPT_TAG_IF 294
#define LOPT_PROXY 295
#define LOPT_GEN_NAMES 296
#define LOPT_MAXTTL 297
#define LOPT_NO_REBIND 298
#define LOPT_LOC_REBND 299
#define LOPT_ADD_MAC 300
#define LOPT_DNSSEC 301
#define LOPT_INCR_ADDR 302
#define LOPT_CONNTRACK 303
#define LOPT_FQDN 304
#define LOPT_LUASCRIPT 305
#define LOPT_RA 306
#define LOPT_DUID 307
#define LOPT_HOST_REC 308
#define LOPT_TFTP_LC 309
#define LOPT_RR 310
#define LOPT_CLVERBIND 311
#define LOPT_MAXCTTL 312
#define LOPT_AUTHZONE 313
#define LOPT_AUTHSERV 314
#define LOPT_AUTHTTL 315
#define LOPT_AUTHSOA 316
#define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318
#define LOPT_IPSET 319
#define LOPT_SYNTH 320
#define LOPT_RELOAD 256
#define LOPT_NO_NAMES 257
#define LOPT_TFTP 258
#define LOPT_SECURE 259
#define LOPT_PREFIX 260
#define LOPT_PTR 261
#define LOPT_BRIDGE 262
#define LOPT_TFTP_MAX 263
#define LOPT_FORCE 264
#define LOPT_NOBLOCK 265
#define LOPT_LOG_OPTS 266
#define LOPT_MAX_LOGS 267
#define LOPT_CIRCUIT 268
#define LOPT_REMOTE 269
#define LOPT_SUBSCR 270
#define LOPT_INTNAME 271
#define LOPT_BANK 272
#define LOPT_DHCP_HOST 273
#define LOPT_APREF 274
#define LOPT_OVERRIDE 275
#define LOPT_TFTPPORTS 276
#define LOPT_REBIND 277
#define LOPT_NOLAST 278
#define LOPT_OPTS 279
#define LOPT_DHCP_OPTS 280
#define LOPT_MATCH 281
#define LOPT_BROADCAST 282
#define LOPT_NEGTTL 283
#define LOPT_ALTPORT 284
#define LOPT_SCRIPTUSR 285
#define LOPT_LOCAL 286
#define LOPT_NAPTR 287
#define LOPT_MINPORT 288
#define LOPT_DHCP_FQDN 289
#define LOPT_CNAME 290
#define LOPT_PXE_PROMT 291
#define LOPT_PXE_SERV 292
#define LOPT_TEST 293
#define LOPT_TAG_IF 294
#define LOPT_PROXY 295
#define LOPT_GEN_NAMES 296
#define LOPT_MAXTTL 297
#define LOPT_NO_REBIND 298
#define LOPT_LOC_REBND 299
#define LOPT_ADD_MAC 300
#define LOPT_DNSSEC 301
#define LOPT_INCR_ADDR 302
#define LOPT_CONNTRACK 303
#define LOPT_FQDN 304
#define LOPT_LUASCRIPT 305
#define LOPT_RA 306
#define LOPT_DUID 307
#define LOPT_HOST_REC 308
#define LOPT_TFTP_LC 309
#define LOPT_RR 310
#define LOPT_CLVERBIND 311
#define LOPT_MAXCTTL 312
#define LOPT_AUTHZONE 313
#define LOPT_AUTHSERV 314
#define LOPT_AUTHTTL 315
#define LOPT_AUTHSOA 316
#define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318
#define LOPT_IPSET 319
#define LOPT_SYNTH 320
#ifdef OPTION6_PREFIX_CLASS
#define LOPT_PREF_CLSS 321
#define LOPT_PREF_CLSS 321
#endif
#define LOPT_RELAY 323
#define LOPT_RA_PARAM 324
#define LOPT_ADD_SBNET 325
#define LOPT_QUIET_DHCP 326
#define LOPT_QUIET_DHCP6 327
#define LOPT_QUIET_RA 328
#define LOPT_SEC_VALID 329
#define LOPT_TRUST_ANCHOR 330
#define LOPT_DNSSEC_DEBUG 331
#define LOPT_REV_SERV 332
#define LOPT_SERVERS_FILE 333
#define LOPT_DNSSEC_CHECK 334
#define LOPT_RELAY 323
#define LOPT_RA_PARAM 324
#define LOPT_ADD_SBNET 325
#define LOPT_QUIET_DHCP 326
#define LOPT_QUIET_DHCP6 327
#define LOPT_QUIET_RA 328
#define LOPT_SEC_VALID 329
#define LOPT_TRUST_ANCHOR 330
#define LOPT_DNSSEC_DEBUG 331
#define LOPT_REV_SERV 332
#define LOPT_SERVERS_FILE 333
#define LOPT_DNSSEC_CHECK 334
#define LOPT_LOCAL_SERVICE 335
#define LOPT_DNSSEC_TIME 336
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -175,6 +177,7 @@ static const struct myoption opts[] =
{ "domain-suffix", 1, 0, 's' },
{ "interface", 1, 0, 'i' },
{ "listen-address", 1, 0, 'a' },
{ "local-service", 0, 0, LOPT_LOCAL_SERVICE },
{ "bogus-priv", 0, 0, 'b' },
{ "bogus-nxdomain", 1, 0, 'B' },
{ "selfmx", 0, 0, 'e' },
@@ -285,6 +288,7 @@ static const struct myoption opts[] =
{ "trust-anchor", 1, 0, LOPT_TRUST_ANCHOR },
{ "dnssec-debug", 0, 0, LOPT_DNSSEC_DEBUG },
{ "dnssec-check-unsigned", 0, 0, LOPT_DNSSEC_CHECK },
{ "dnssec-no-timecheck", 0, 0, LOPT_DNSSEC_TIME },
#ifdef OPTION6_PREFIX_CLASS
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
#endif
@@ -441,6 +445,7 @@ static struct {
{ LOPT_TRUST_ANCHOR, ARG_DUP, "<domain>,[<class>],...", gettext_noop("Specify trust anchor key digest."), NULL },
{ LOPT_DNSSEC_DEBUG, OPT_DNSSEC_DEBUG, NULL, gettext_noop("Disable upstream checking for DNSSEC debugging."), NULL },
{ LOPT_DNSSEC_CHECK, OPT_DNSSEC_NO_SIGN, NULL, gettext_noop("Ensure answers without DNSSEC are in unsigned zones."), NULL },
{ LOPT_DNSSEC_TIME, OPT_DNSSEC_TIME, NULL, gettext_noop("Don't check DNSSEC signature timestamps until first cache-reload"), NULL },
#ifdef OPTION6_PREFIX_CLASS
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
#endif
@@ -448,6 +453,7 @@ static struct {
{ LOPT_QUIET_DHCP, OPT_QUIET_DHCP, NULL, gettext_noop("Do not log routine DHCP."), NULL },
{ LOPT_QUIET_DHCP6, OPT_QUIET_DHCP6, NULL, gettext_noop("Do not log routine DHCPv6."), 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 },
{ 0, 0, NULL, NULL, NULL }
};
@@ -612,19 +618,24 @@ static int atoi_check8(char *a, int *res)
}
#endif
static void add_txt(char *name, char *txt)
static void add_txt(char *name, char *txt, int stat)
{
size_t len = strlen(txt);
struct txt_record *r = opt_malloc(sizeof(struct txt_record));
if (txt)
{
size_t len = strlen(txt);
r->txt = opt_malloc(len+1);
r->len = len+1;
*(r->txt) = len;
memcpy((r->txt)+1, txt, len);
}
r->stat = stat;
r->name = opt_string_alloc(name);
r->next = daemon->txt;
daemon->txt = r;
r->class = C_CHAOS;
r->txt = opt_malloc(len+1);
r->len = len+1;
*(r->txt) = len;
memcpy((r->txt)+1, txt, len);
}
static void do_usage(void)
@@ -1661,7 +1672,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'H': /* --addn-hosts */
{
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
static int hosts_index = 1;
static unsigned int hosts_index = SRC_AH;
new->fname = opt_string_alloc(arg);
new->index = hosts_index++;
new->flags = 0;
@@ -3606,7 +3617,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->txt;
daemon->txt = new;
new->class = C_IN;
new->stat = 0;
if (!(new->name = canonicalise_opt(arg)))
ret_err(_("bad TXT record"));
@@ -4017,10 +4029,11 @@ static int one_file(char *file, int hard_opt)
/* expand any name which is a directory */
struct hostsfile *expand_filelist(struct hostsfile *list)
{
int i;
unsigned int i;
struct hostsfile *ah;
for (i = 0, ah = list; ah; ah = ah->next)
/* find largest used index */
for (i = SRC_AH, ah = list; ah; ah = ah->next)
{
if (i <= ah->index)
i = ah->index + 1;
@@ -4254,9 +4267,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->soa_refresh = SOA_REFRESH;
daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY;
add_txt("version.bind", "dnsmasq-" VERSION );
add_txt("authors.bind", "Simon Kelley");
add_txt("copyright.bind", COPYRIGHT);
add_txt("version.bind", "dnsmasq-" VERSION, 0 );
add_txt("authors.bind", "Simon Kelley", 0);
add_txt("copyright.bind", COPYRIGHT, 0);
add_txt("cachesize.bind", NULL, TXT_STAT_CACHESIZE);
add_txt("insertions.bind", NULL, TXT_STAT_INSERTS);
add_txt("evictions.bind", NULL, TXT_STAT_EVICTIONS);
add_txt("misses.bind", NULL, TXT_STAT_MISSES);
add_txt("hits.bind", NULL, TXT_STAT_HITS);
#ifdef HAVE_AUTH
add_txt("auth.bind", NULL, TXT_STAT_AUTH);
#endif
add_txt("servers.bind", NULL, TXT_STAT_SERVERS);
while (1)
{
@@ -4457,6 +4479,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
else if (option_bool(OPT_DHCP_FQDN))
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
/* If there's access-control config, then ignore --local-service, it's intended
as a system default to keep otherwise unconfigured installations safe. */
if (daemon->if_names || daemon->if_except || daemon->if_addrs || daemon->authserver)
reset_option_bool(OPT_LOCAL_SERVICE);
if (testmode)
{
fprintf(stderr, "dnsmasq: %s.\n", _("syntax check OK"));
+22 -7
View File
@@ -1065,6 +1065,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
if (newc)
{
newc->addr.cname.target.cache = NULL;
/* anything other than zero, to avoid being mistaken for CNAME to interface-name */
newc->addr.cname.uid = 1;
if (cpp)
{
cpp->addr.cname.target.cache = newc;
@@ -1100,7 +1102,10 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{
ipsets_cur = ipsets;
while (*ipsets_cur)
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
{
log_query(F_IPSET, name, &addr, *ipsets_cur);
add_to_ipset(*ipsets_cur++, &addr, flags, 0);
}
}
#endif
@@ -1241,7 +1246,7 @@ int check_for_local_domain(char *name, time_t now)
struct ptr_record *ptr;
struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_NO_RR)) &&
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
@@ -1456,7 +1461,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
{
char *name = daemon->namebuff;
unsigned char *p, *ansp, *pheader;
int qtype, qclass;
unsigned int qtype, qclass;
struct all_addr addr;
int nameoffset;
unsigned short flag;
@@ -1545,10 +1550,20 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
ans = 1;
if (!dryrun)
{
unsigned long ttl = daemon->local_ttl;
int ok = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_TXT, t->class, "t", t->len, t->txt))
/* Dynamically generate stat record */
if (t->stat != 0)
{
ttl = 0;
if (!cache_make_stat(t))
ok = 0;
}
if (ok && add_resource_record(header, limit, &trunc, nameoffset, &ansp,
ttl, NULL,
T_TXT, t->class, "t", t->len, t->txt))
anscount++;
}
@@ -2016,7 +2031,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
strcpy(name, cname_target);
/* check if target interface_name */
if (crecp->addr.cname.uid == -1)
if (crecp->addr.cname.uid == SRC_INTERFACE)
goto intname_restart;
else
goto cname_restart;
+2
View File
@@ -962,6 +962,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
case DHCPDISCOVER:
if (ignore || have_config(config, CONFIG_DISABLE))
{
if (option_bool(OPT_QUIET_DHCP))
return 0;
message = _("ignored");
opt = NULL;
}