Compare commits

...
5 Commits
Author SHA1 Message Date
Simon Kelley 09f3b2cd9c Fix case of DS queries to domains marked as not doing DNSSEC.
This was causing confusion: DNSSEC queries would be sent to
servers for domains that don't do DNSSEC, but because of that status
the answers would be treated as answers to ordinary queries,
sometimes resulting in a crash.
2017-05-09 01:34:02 +01:00
Simon Kelley 22827870fa Fix botch introduced by 561441320f 2017-05-08 21:39:04 +01:00
Vladislav Grishenko 4583dd9e42 Replace obsolete utime() usage with utimes().
This fixes build time warnings with POSIX.1-2008-aware c libraries.
2017-05-03 23:16:51 +01:00
Simon Kelley 561441320f Fix a couple of crashes on malformed config files.
Thanks to Stephan Zeisberg and
american fuzzy lop http://lcamtuf.coredump.cx/afl/
2017-05-03 22:54:09 +01:00
Simon Kelley b2a9c571eb Add "known-othernet" DHCP tag. 2017-04-30 18:21:31 +01:00
10 changed files with 97 additions and 71 deletions

No files matched your search

+5
View File
@@ -110,6 +110,11 @@ version 2.77
an address in configured locally. Thanks to Alin Năstac
for spotting the problem.
Add new DHCP tag "known-othernet" which is set when only a
dhcp-host exists for another subnet. Can be used to ensure
that privileged hosts are not given "guest" addresses by
accident. Thanks to Todd Sanket for the suggestion.
version 2.76
Include 0.0.0.0/8 in DNS rebind checks. This range
+2
View File
@@ -1021,6 +1021,8 @@ dhcp-host directive (or one implied by /etc/ethers) then the special
tag "known" is set. This allows dnsmasq to be configured to
ignore requests from unknown machines using
.B --dhcp-ignore=tag:!known
If the host matches only a dhcp-host directive which cannot
be used because it specifies an address on different subnet, the tag "known-othernet" is set.
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
+1 -1
View File
@@ -1375,7 +1375,7 @@ static void async_event(int pipe, time_t now)
/* update timestamp file on TERM if time is considered valid */
if (daemon->back_to_the_future)
{
if (utime(daemon->timestamp_file, NULL) == -1)
if (utimes(daemon->timestamp_file, NULL) == -1)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
}
#endif
-1
View File
@@ -117,7 +117,6 @@ typedef unsigned long long u64;
#include <sys/uio.h>
#include <syslog.h>
#include <dirent.h>
#include <utime.h>
#ifndef HAVE_LINUX_NETWORK
# include <net/if_dl.h>
#endif
+7 -5
View File
@@ -475,7 +475,7 @@ int setup_timestamp(void)
if (difftime(timestamp_time, time(0)) <= 0)
{
/* time already OK, update timestamp, and do key checking from the start. */
if (utime(daemon->timestamp_file, NULL) == -1)
if (utimes(daemon->timestamp_file, NULL) == -1)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
daemon->back_to_the_future = 1;
return 0;
@@ -489,12 +489,14 @@ int setup_timestamp(void)
int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
if (fd != -1)
{
struct utimbuf timbuf;
struct timeval tv[2];
close(fd);
timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
if (utime(daemon->timestamp_file, &timbuf) == 0)
timestamp_time = 1420070400; /* 1-1-2015 */
tv[0].tv_sec = tv[1].tv_sec = timestamp_time;
tv[0].tv_usec = tv[1].tv_usec = 0;
if (utimes(daemon->timestamp_file, tv) == 0)
goto check_and_exit;
}
}
@@ -519,7 +521,7 @@ static int check_date_range(u32 date_start, u32 date_end)
{
if (daemon->back_to_the_future == 0 && difftime(timestamp_time, curtime) <= 0)
{
if (utime(daemon->timestamp_file, NULL) != 0)
if (utimes(daemon->timestamp_file, NULL) != 0)
my_syslog(LOG_ERR, _("failed to update mtime on %s: %s"), daemon->timestamp_file, strerror(errno));
my_syslog(LOG_INFO, _("system time considered valid, now checking DNSSEC signature timestamps."));
+61 -61
View File
@@ -120,8 +120,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigne
unsigned int flags = 0;
for (serv = daemon->servers; serv; serv=serv->next)
if (qtype == F_DNSSECOK && !(serv->flags & SERV_DO_DNSSEC))
continue;
/* domain matches take priority over NODOTS matches */
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
else if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
{
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
*type = SERV_FOR_NODOTS;
@@ -877,10 +879,10 @@ void reply_query(int fd, int family, time_t now)
return;
/* Truncated answer can't be validated.
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
If this is an answer to a DNSSEC-generated query, we still
need to get the client to retry over TCP, so return
an answer with the TC bit set, even if the actual answer fits.
*/
if (header->hb3 & HB3_TC)
status = STAT_TRUNCATED;
@@ -933,37 +935,35 @@ void reply_query(int fd, int family, time_t now)
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (search_servers(now, NULL, F_QUERY, daemon->keyname, &type, &domain, NULL) == 0)
if (search_servers(now, NULL, F_DNSSECOK, daemon->keyname, &type, &domain, NULL) == 0)
{
struct server *start = server, *new_server = NULL;
type &= ~SERV_DO_DNSSEC;
while (1)
{
if (type == (start->flags & SERV_TYPE) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
new_server = start;
if (server == start)
{
new_server = NULL;
break;
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == server)
break;
}
if (new_server)
server = new_server;
while (1)
{
if (type == (start->flags & (SERV_TYPE | SERV_DO_DNSSEC)) &&
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)) &&
!(start->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
{
new_server = start;
if (server == start)
{
new_server = NULL;
break;
}
}
if (!(start = start->next))
start = daemon->servers;
if (start == server)
break;
}
if (new_server)
server = new_server;
}
new->sentto = server;
new->rfd4 = NULL;
#ifdef HAVE_IPV6
new->rfd6 = NULL;
@@ -1506,14 +1506,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
/* Find server to forward to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (search_servers(now, NULL, F_QUERY, keyname, &type, &domain, NULL) != 0)
if (search_servers(now, NULL, F_DNSSECOK, keyname, &type, &domain, NULL) != 0)
{
new_status = STAT_ABANDONED;
break;
}
type &= ~SERV_DO_DNSSEC;
while (1)
{
if (!firstsendto)
@@ -1530,34 +1528,34 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
}
}
if (type != (server->flags & SERV_TYPE) ||
if (type != (server->flags & (SERV_TYPE | SERV_DO_DNSSEC)) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, server->domain)) ||
(server->flags & (SERV_LITERAL_ADDRESS | SERV_LOOP)))
continue;
retry:
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
retry:
/* may need to make new connection. */
if (server->tcpfd == -1)
{
if ((server->tcpfd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue; /* No good, next server */
}
server->flags &= ~SERV_GOT_TCP;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (have_mark)
setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
#endif
if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) ||
connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1)
{
close(server->tcpfd);
server->tcpfd = -1;
continue; /* No good, next server */
}
server->flags &= ~SERV_GOT_TCP;
}
if (!read_write(server->tcpfd, packet, m + sizeof(u16), 0) ||
!read_write(server->tcpfd, &c1, 1, 1) ||
@@ -2080,6 +2078,8 @@ static void free_frec(struct frec *f)
#endif
}
/* if wait==NULL return a free or older than TIMEOUT record.
else return *wait zero if one available, or *wait is delay to
when the oldest in-use record will expire. Impose an absolute
@@ -2126,7 +2126,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
/* can't find empty one, use oldest if there is one
and it's older than timeout */
if (oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
if (!force && oldest && ((int)difftime(now, oldest->time)) >= TIMEOUT)
{
/* keep stuff for twice timeout if we can by allocating a new
record instead */
@@ -2166,7 +2166,7 @@ struct frec *get_new_frec(time_t now, int *wait, int force)
return f; /* OK if malloc fails and this is NULL */
}
/* crc is all-ones if not known. */
static struct frec *lookup_frec(unsigned short id, void *hash)
{
+4 -1
View File
@@ -3848,9 +3848,12 @@ err:
while (arg != last)
{
alias = canonicalise_opt(arg);
if (!alias || !target)
ret_err(_("bad CNAME"));
for (new = daemon->cnames; new; new = new->next)
if (hostname_isequal(new->alias, arg))
if (hostname_isequal(new->alias, alias))
ret_err(_("duplicate CNAME"));
new = opt_malloc(sizeof(struct cname));
new->next = daemon->cnames;
+7
View File
@@ -487,6 +487,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
known_id.next = netid;
netid = &known_id;
}
else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len,
mess->chaddr, mess->hlen, mess->htype, NULL))
{
known_id.net = "known-othernet";
known_id.next = netid;
netid = &known_id;
}
if (mess_type == 0 && !pxe)
{
+8 -1
View File
@@ -526,7 +526,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
if (have_config(config, CONFIG_DISABLE))
ignore = 1;
}
else if (state->clid &&
find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
{
known_id.net = "known-othernet";
known_id.next = state->tags;
state->tags = &known_id;
}
#ifdef OPTION6_PREFIX_CLASS
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
+2 -1
View File
@@ -503,7 +503,8 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
return -1;
out[i] = strtol(&in[j*2], NULL, 16);
mask = mask << 1;
i++;
if (++i == maxlen)
break;
if (j < bytes - 1)
in[(j+1)*2] = sav;
}