mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8f16556d3 | ||
|
|
cbe379ad6b | ||
|
|
338b340be9 | ||
|
|
a006eb7e14 | ||
|
|
554b580e97 | ||
|
|
0df29f5e23 | ||
|
|
b4c0f092d8 | ||
|
|
78c6184752 | ||
|
|
38440b204d | ||
|
|
ad4a8ff7d9 | ||
|
|
04b0ac0537 | ||
|
|
982faf4024 | ||
|
|
fe3992f9fa | ||
|
|
7aa970e2c7 | ||
|
|
30d0879ed5 |
No files matched your search
@@ -68,10 +68,42 @@ version 2.73
|
|||||||
Fix broken DNSSEC validation of ECDSA signatures.
|
Fix broken DNSSEC validation of ECDSA signatures.
|
||||||
|
|
||||||
Add --dnssec-timestamp option, which provides an automatic
|
Add --dnssec-timestamp option, which provides an automatic
|
||||||
way to detect when the system time becomes valid after boot
|
way to detect when the system time becomes valid after
|
||||||
on systems without an RTC, whilst allowing DNS queries before the
|
boot on systems without an RTC, whilst allowing DNS
|
||||||
clock is valid so that NTP can run. Thanks to
|
queries before the clock is valid so that NTP can run.
|
||||||
Kevin Darbyshire-Bryant for developing this idea.
|
Thanks to Kevin Darbyshire-Bryant for developing this idea.
|
||||||
|
|
||||||
|
Add --tftp-no-fail option. Thanks to Stefan Tomanek for
|
||||||
|
the patch.
|
||||||
|
|
||||||
|
Fix crash caused by looking up servers.bind, CHAOS text
|
||||||
|
record, when more than about five --servers= lines are
|
||||||
|
in the dnsmasq config. This causes memory corruption
|
||||||
|
which causes a crash later. Thanks to Matt Coddington for
|
||||||
|
sterling work chasing this down.
|
||||||
|
|
||||||
|
Fix crash on receipt of certain malformed DNS requests.
|
||||||
|
Thanks to Nick Sampanis for spotting the problem.
|
||||||
|
Note that this is could allow the dnsmasq process's
|
||||||
|
memory to be read by an attacker under certain
|
||||||
|
circumstances, so it has a CVE, CVE-2015-3294
|
||||||
|
|
||||||
|
Fix crash in authoritative DNS code, if a .arpa zone
|
||||||
|
is declared as authoritative, and then a PTR query which
|
||||||
|
is not to be treated as authoritative arrived. Normally,
|
||||||
|
directly declaring .arpa zone as authoritative is not
|
||||||
|
done, so this crash wouldn't be seen. Instead the
|
||||||
|
relevant .arpa zone should be specified as a subnet
|
||||||
|
in the auth-zone declaration. Thanks to Johnny S. Lee
|
||||||
|
for the bugreport and initial patch.
|
||||||
|
|
||||||
|
Fix authoritative DNS code to correctly reply to NS
|
||||||
|
and SOA queries for .arpa zones for which we are
|
||||||
|
declared authoritative by means of a subnet in auth-zone.
|
||||||
|
Previously we provided correct answers to PTR queries
|
||||||
|
in such zones (including NS and SOA) but not direct
|
||||||
|
NS and SOA queries. Thanks to Johnny S. Lee for
|
||||||
|
pointing out the problem.
|
||||||
|
|
||||||
|
|
||||||
version 2.72
|
version 2.72
|
||||||
|
|||||||
@@ -277,6 +277,11 @@ int main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inet_addr(argv[2]) == INADDR_NONE)
|
||||||
|
{
|
||||||
|
perror("invalid ip address");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
lease.s_addr = inet_addr(argv[2]);
|
lease.s_addr = inet_addr(argv[2]);
|
||||||
server = find_interface(lease, nl, if_nametoindex(argv[1]));
|
server = find_interface(lease, nl, if_nametoindex(argv[1]));
|
||||||
|
|||||||
@@ -486,6 +486,9 @@
|
|||||||
# Set the root directory for files available via FTP.
|
# Set the root directory for files available via FTP.
|
||||||
#tftp-root=/var/ftpd
|
#tftp-root=/var/ftpd
|
||||||
|
|
||||||
|
# Do not abort if the tftp-root is unavailable
|
||||||
|
#tftp-no-fail
|
||||||
|
|
||||||
# Make the TFTP server more secure: with this set, only files owned by
|
# Make the TFTP server more secure: with this set, only files owned by
|
||||||
# the user dnsmasq is running as will be send over the net.
|
# the user dnsmasq is running as will be send over the net.
|
||||||
#tftp-secure
|
#tftp-secure
|
||||||
|
|||||||
@@ -1711,6 +1711,9 @@ Absolute paths (starting with /) are allowed, but they must be within
|
|||||||
the tftp-root. If the optional interface argument is given, the
|
the tftp-root. If the optional interface argument is given, the
|
||||||
directory is only used for TFTP requests via that interface.
|
directory is only used for TFTP requests via that interface.
|
||||||
.TP
|
.TP
|
||||||
|
.B --tftp-no-fail
|
||||||
|
Do not abort startup if specified tftp root directories are inaccessible.
|
||||||
|
.TP
|
||||||
.B --tftp-unique-root
|
.B --tftp-unique-root
|
||||||
Add the IP address of the TFTP client as a path component on the end
|
Add the IP address of the TFTP client as a path component on the end
|
||||||
of the TFTP-root (in standard dotted-quad format). Only valid if a
|
of the TFTP-root (in standard dotted-quad format). Only valid if a
|
||||||
|
|||||||
+36
-24
@@ -131,24 +131,27 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qtype == T_PTR)
|
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
|
||||||
|
(flag = in_arpa_name_2_addr(name, &addr)) &&
|
||||||
|
!local_query)
|
||||||
{
|
{
|
||||||
if (!(flag = in_arpa_name_2_addr(name, &addr)))
|
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||||
continue;
|
if ((subnet = find_subnet(zone, flag, &addr)))
|
||||||
|
break;
|
||||||
|
|
||||||
if (!local_query)
|
if (!zone)
|
||||||
{
|
{
|
||||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
auth = 0;
|
||||||
if ((subnet = find_subnet(zone, flag, &addr)))
|
continue;
|
||||||
break;
|
|
||||||
|
|
||||||
if (!zone)
|
|
||||||
{
|
|
||||||
auth = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (qtype == T_SOA)
|
||||||
|
soa = 1, found = 1;
|
||||||
|
else if (qtype == T_NS)
|
||||||
|
ns = 1, found = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qtype == T_PTR && flag)
|
||||||
|
{
|
||||||
intr = NULL;
|
intr = NULL;
|
||||||
|
|
||||||
if (flag == F_IPV4)
|
if (flag == F_IPV4)
|
||||||
@@ -186,7 +189,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
|
|
||||||
if (intr)
|
if (intr)
|
||||||
{
|
{
|
||||||
if (in_zone(zone, intr->name, NULL))
|
if (local_query || in_zone(zone, intr->name, NULL))
|
||||||
{
|
{
|
||||||
found = 1;
|
found = 1;
|
||||||
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||||
@@ -208,8 +211,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
*p = 0; /* must be bare name */
|
*p = 0; /* must be bare name */
|
||||||
|
|
||||||
/* add external domain */
|
/* add external domain */
|
||||||
strcat(name, ".");
|
if (zone)
|
||||||
strcat(name, zone->domain);
|
{
|
||||||
|
strcat(name, ".");
|
||||||
|
strcat(name, zone->domain);
|
||||||
|
}
|
||||||
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
|
||||||
found = 1;
|
found = 1;
|
||||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||||
@@ -217,7 +223,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
T_PTR, C_IN, "d", name))
|
T_PTR, C_IN, "d", name))
|
||||||
anscount++;
|
anscount++;
|
||||||
}
|
}
|
||||||
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
|
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
|
||||||
{
|
{
|
||||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
|
||||||
found = 1;
|
found = 1;
|
||||||
@@ -240,14 +246,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
|||||||
}
|
}
|
||||||
|
|
||||||
cname_restart:
|
cname_restart:
|
||||||
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
if (found)
|
||||||
if (in_zone(zone, name, &cut))
|
/* NS and SOA .arpa requests have set found above. */
|
||||||
break;
|
cut = NULL;
|
||||||
|
else
|
||||||
if (!zone)
|
|
||||||
{
|
{
|
||||||
auth = 0;
|
for (zone = daemon->auth_zones; zone; zone = zone->next)
|
||||||
continue;
|
if (in_zone(zone, name, &cut))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!zone)
|
||||||
|
{
|
||||||
|
auth = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||||
|
|||||||
+2
-2
@@ -1367,7 +1367,7 @@ int cache_make_stat(struct txt_record *t)
|
|||||||
}
|
}
|
||||||
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||||
lenp = p++; /* length */
|
lenp = p++; /* length */
|
||||||
bytes_avail = (p - buff) + bufflen;
|
bytes_avail = bufflen - (p - buff );
|
||||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||||
if (bytes_needed >= bytes_avail)
|
if (bytes_needed >= bytes_avail)
|
||||||
{
|
{
|
||||||
@@ -1381,7 +1381,7 @@ int cache_make_stat(struct txt_record *t)
|
|||||||
lenp = p - 1;
|
lenp = p - 1;
|
||||||
buff = new;
|
buff = new;
|
||||||
bufflen = newlen;
|
bufflen = newlen;
|
||||||
bytes_avail = (p - buff) + bufflen;
|
bytes_avail = bufflen - (p - buff );
|
||||||
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
bytes_needed = snprintf(p, bytes_avail, "%s#%d %u %u", daemon->addrbuff, port, queries, failed_queries);
|
||||||
}
|
}
|
||||||
*lenp = bytes_needed;
|
*lenp = bytes_needed;
|
||||||
|
|||||||
@@ -142,3 +142,11 @@ struct dns_header {
|
|||||||
|
|
||||||
#define ADD_RDLEN(header, pp, plen, len) \
|
#define ADD_RDLEN(header, pp, plen, len) \
|
||||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
|
||||||
|
|
||||||
|
/* Escape character in our presentation format for names.
|
||||||
|
Cannot be '.' or /000 and must be !isprint().
|
||||||
|
Note that escaped chars are stored as
|
||||||
|
<NAME_ESCAPE> <orig-char+1>
|
||||||
|
to ensure that the escaped form of /000 doesn't include /000
|
||||||
|
*/
|
||||||
|
#define NAME_ESCAPE 1
|
||||||
+44
-11
@@ -58,6 +58,9 @@ int main (int argc, char **argv)
|
|||||||
struct dhcp_context *context;
|
struct dhcp_context *context;
|
||||||
struct dhcp_relay *relay;
|
struct dhcp_relay *relay;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_TFTP
|
||||||
|
int tftp_prefix_missing = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef LOCALEDIR
|
#ifdef LOCALEDIR
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
@@ -99,8 +102,19 @@ int main (int argc, char **argv)
|
|||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (option_bool(OPT_DNSSEC_VALID))
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
{
|
{
|
||||||
daemon->keyname = safe_malloc(MAXDNAME);
|
/* Note that both /000 and '.' are allowed within labels. These get
|
||||||
daemon->workspacename = safe_malloc(MAXDNAME);
|
represented in presentation format using NAME_ESCAPE as an escape
|
||||||
|
character when in DNSSEC mode.
|
||||||
|
In theory, if all the characters in a name were /000 or
|
||||||
|
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
||||||
|
presentation format would be twice as long as the spec.
|
||||||
|
|
||||||
|
daemon->namebuff was previously allocated by the option-reading
|
||||||
|
code before we knew if we're in DNSSEC mode, so reallocate here. */
|
||||||
|
free(daemon->namebuff);
|
||||||
|
daemon->namebuff = safe_malloc(MAXDNAME * 2);
|
||||||
|
daemon->keyname = safe_malloc(MAXDNAME * 2);
|
||||||
|
daemon->workspacename = safe_malloc(MAXDNAME * 2);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -636,7 +650,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))
|
||||||
{
|
{
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct tftp_prefix *p;
|
struct tftp_prefix *p;
|
||||||
@@ -645,20 +659,31 @@ int main (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (!((dir = opendir(daemon->tftp_prefix))))
|
if (!((dir = opendir(daemon->tftp_prefix))))
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
|
tftp_prefix_missing = 1;
|
||||||
_exit(0);
|
if (!option_bool(OPT_TFTP_NO_FAIL))
|
||||||
|
{
|
||||||
|
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
else
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (p = daemon->if_prefix; p; p = p->next)
|
for (p = daemon->if_prefix; p; p = p->next)
|
||||||
{
|
{
|
||||||
|
p->missing = 0;
|
||||||
if (!((dir = opendir(p->prefix))))
|
if (!((dir = opendir(p->prefix))))
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
|
p->missing = 1;
|
||||||
_exit(0);
|
if (!option_bool(OPT_TFTP_NO_FAIL))
|
||||||
}
|
{
|
||||||
closedir(dir);
|
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -773,6 +798,7 @@ int main (int argc, char **argv)
|
|||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
if (option_bool(OPT_TFTP))
|
if (option_bool(OPT_TFTP))
|
||||||
{
|
{
|
||||||
|
struct tftp_prefix *p;
|
||||||
#ifdef FD_SETSIZE
|
#ifdef FD_SETSIZE
|
||||||
if (FD_SETSIZE < (unsigned)max_fd)
|
if (FD_SETSIZE < (unsigned)max_fd)
|
||||||
max_fd = FD_SETSIZE;
|
max_fd = FD_SETSIZE;
|
||||||
@@ -783,6 +809,13 @@ int main (int argc, char **argv)
|
|||||||
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
||||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
||||||
|
|
||||||
|
if (tftp_prefix_missing)
|
||||||
|
my_syslog(MS_TFTP | LOG_WARNING, _("warning: %s inaccessible"), daemon->tftp_prefix);
|
||||||
|
|
||||||
|
for (p = daemon->if_prefix; p; p = p->next)
|
||||||
|
if (p->missing)
|
||||||
|
my_syslog(MS_TFTP | LOG_WARNING, _("warning: TFTP directory %s inaccessible"), p->prefix);
|
||||||
|
|
||||||
/* This is a guess, it assumes that for small limits,
|
/* This is a guess, it assumes that for small limits,
|
||||||
disjoint files might be served, but for large limits,
|
disjoint files might be served, but for large limits,
|
||||||
a single file will be sent to may clients (the file only needs
|
a single file will be sent to may clients (the file only needs
|
||||||
|
|||||||
+4
-1
@@ -240,7 +240,8 @@ struct event_desc {
|
|||||||
#define OPT_LOCAL_SERVICE 49
|
#define OPT_LOCAL_SERVICE 49
|
||||||
#define OPT_LOOP_DETECT 50
|
#define OPT_LOOP_DETECT 50
|
||||||
#define OPT_EXTRALOG 51
|
#define OPT_EXTRALOG 51
|
||||||
#define OPT_LAST 52
|
#define OPT_TFTP_NO_FAIL 52
|
||||||
|
#define OPT_LAST 53
|
||||||
|
|
||||||
/* 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. */
|
||||||
@@ -582,6 +583,7 @@ struct hostsfile {
|
|||||||
#define STAT_NO_NS 10
|
#define STAT_NO_NS 10
|
||||||
#define STAT_NEED_DS_NEG 11
|
#define STAT_NEED_DS_NEG 11
|
||||||
#define STAT_CHASE_CNAME 12
|
#define STAT_CHASE_CNAME 12
|
||||||
|
#define STAT_INSECURE_DS 13
|
||||||
|
|
||||||
#define FREC_NOREBIND 1
|
#define FREC_NOREBIND 1
|
||||||
#define FREC_CHECKING_DISABLED 2
|
#define FREC_CHECKING_DISABLED 2
|
||||||
@@ -901,6 +903,7 @@ struct addr_list {
|
|||||||
struct tftp_prefix {
|
struct tftp_prefix {
|
||||||
char *interface;
|
char *interface;
|
||||||
char *prefix;
|
char *prefix;
|
||||||
|
int missing;
|
||||||
struct tftp_prefix *next;
|
struct tftp_prefix *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+34
-9
@@ -321,10 +321,18 @@ static int verify(struct blockdata *key_data, unsigned int key_len, unsigned cha
|
|||||||
thus generating names in canonical form.
|
thus generating names in canonical form.
|
||||||
Calling to_wire followed by from_wire is almost an identity,
|
Calling to_wire followed by from_wire is almost an identity,
|
||||||
except that the UC remains mapped to LC.
|
except that the UC remains mapped to LC.
|
||||||
|
|
||||||
|
Note that both /000 and '.' are allowed within labels. These get
|
||||||
|
represented in presentation format using NAME_ESCAPE as an escape
|
||||||
|
character. In theory, if all the characters in a name were /000 or
|
||||||
|
'.' or NAME_ESCAPE then all would have to be escaped, so the
|
||||||
|
presentation format would be twice as long as the spec (1024).
|
||||||
|
The buffers are all delcared as 2049 (allowing for the trailing zero)
|
||||||
|
for this reason.
|
||||||
*/
|
*/
|
||||||
static int to_wire(char *name)
|
static int to_wire(char *name)
|
||||||
{
|
{
|
||||||
unsigned char *l, *p, term;
|
unsigned char *l, *p, *q, term;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
for (l = (unsigned char*)name; *l != 0; l = p)
|
for (l = (unsigned char*)name; *l != 0; l = p)
|
||||||
@@ -332,7 +340,12 @@ static int to_wire(char *name)
|
|||||||
for (p = l; *p != '.' && *p != 0; p++)
|
for (p = l; *p != '.' && *p != 0; p++)
|
||||||
if (*p >= 'A' && *p <= 'Z')
|
if (*p >= 'A' && *p <= 'Z')
|
||||||
*p = *p - 'A' + 'a';
|
*p = *p - 'A' + 'a';
|
||||||
|
else if (*p == NAME_ESCAPE)
|
||||||
|
{
|
||||||
|
for (q = p; *q; q++)
|
||||||
|
*q = *(q+1);
|
||||||
|
(*p)--;
|
||||||
|
}
|
||||||
term = *p;
|
term = *p;
|
||||||
|
|
||||||
if ((len = p - l) != 0)
|
if ((len = p - l) != 0)
|
||||||
@@ -351,13 +364,24 @@ static int to_wire(char *name)
|
|||||||
/* Note: no compression allowed in input. */
|
/* Note: no compression allowed in input. */
|
||||||
static void from_wire(char *name)
|
static void from_wire(char *name)
|
||||||
{
|
{
|
||||||
unsigned char *l;
|
unsigned char *l, *p, *last;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
for (last = (unsigned char *)name; *last != 0; last += *last+1);
|
||||||
|
|
||||||
for (l = (unsigned char *)name; *l != 0; l += len+1)
|
for (l = (unsigned char *)name; *l != 0; l += len+1)
|
||||||
{
|
{
|
||||||
len = *l;
|
len = *l;
|
||||||
memmove(l, l+1, len);
|
memmove(l, l+1, len);
|
||||||
|
for (p = l; p < l + len; p++)
|
||||||
|
if (*p == '.' || *p == 0 || *p == NAME_ESCAPE)
|
||||||
|
{
|
||||||
|
memmove(p+1, p, 1 + last - p);
|
||||||
|
len++;
|
||||||
|
*p++ = NAME_ESCAPE;
|
||||||
|
(*p)++;
|
||||||
|
}
|
||||||
|
|
||||||
l[len] = '.';
|
l[len] = '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,7 +669,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
|||||||
if (left1 != 0)
|
if (left1 != 0)
|
||||||
memmove(buff1, buff1 + len1 - left1, left1);
|
memmove(buff1, buff1 + len1 - left1, left1);
|
||||||
|
|
||||||
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
|
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||||
{
|
{
|
||||||
quit = 1;
|
quit = 1;
|
||||||
len1 = end1 - p1;
|
len1 = end1 - p1;
|
||||||
@@ -656,7 +680,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
|
|||||||
if (left2 != 0)
|
if (left2 != 0)
|
||||||
memmove(buff2, buff2 + len2 - left2, left2);
|
memmove(buff2, buff2 + len2 - left2, left2);
|
||||||
|
|
||||||
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
|
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||||
{
|
{
|
||||||
quit = 1;
|
quit = 1;
|
||||||
len2 = end2 - p2;
|
len2 = end2 - p2;
|
||||||
@@ -902,10 +926,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
|
|
||||||
end = p + rdlen;
|
end = p + rdlen;
|
||||||
|
|
||||||
/* canonicalise rdata and calculate length of same, use name buffer as workspace */
|
/* canonicalise rdata and calculate length of same, use name buffer as workspace.
|
||||||
|
Note that name buffer is twice MAXDNAME long in DNSSEC mode. */
|
||||||
cp = p;
|
cp = p;
|
||||||
dp = rr_desc;
|
dp = rr_desc;
|
||||||
for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
|
for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)) != 0; len += seg);
|
||||||
len += end - cp;
|
len += end - cp;
|
||||||
len = htons(len);
|
len = htons(len);
|
||||||
hash->update(ctx, 2, (unsigned char *)&len);
|
hash->update(ctx, 2, (unsigned char *)&len);
|
||||||
@@ -913,7 +938,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
|||||||
/* Now canonicalise again and digest. */
|
/* Now canonicalise again and digest. */
|
||||||
cp = p;
|
cp = p;
|
||||||
dp = rr_desc;
|
dp = rr_desc;
|
||||||
while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
|
while ((seg = get_rdata(header, plen, end, name, MAXDNAME * 2, &cp, &dp)))
|
||||||
hash->update(ctx, seg, (unsigned char *)name);
|
hash->update(ctx, seg, (unsigned char *)name);
|
||||||
if (cp != end)
|
if (cp != end)
|
||||||
hash->update(ctx, end - cp, cp);
|
hash->update(ctx, end - cp, cp);
|
||||||
@@ -981,7 +1006,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
|||||||
|
|
||||||
/* If we've cached that DS provably doesn't exist, result must be INSECURE */
|
/* If we've cached that DS provably doesn't exist, result must be INSECURE */
|
||||||
if (crecp->flags & F_NEG)
|
if (crecp->flags & F_NEG)
|
||||||
return STAT_INSECURE;
|
return STAT_INSECURE_DS;
|
||||||
|
|
||||||
/* NOTE, we need to find ONE DNSKEY which matches the DS */
|
/* NOTE, we need to find ONE DNSKEY which matches the DS */
|
||||||
for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
|
for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
|
||||||
|
|||||||
+75
-22
@@ -521,7 +521,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
||||||
int no_cache, int cache_secure, int ad_reqd, int do_bit, int added_pheader, int check_subnet, union mysockaddr *query_source)
|
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
|
||||||
|
int check_subnet, union mysockaddr *query_source)
|
||||||
{
|
{
|
||||||
unsigned char *pheader, *sizep;
|
unsigned char *pheader, *sizep;
|
||||||
char **sets = 0;
|
char **sets = 0;
|
||||||
@@ -529,7 +530,8 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
size_t plen;
|
size_t plen;
|
||||||
|
|
||||||
(void)ad_reqd;
|
(void)ad_reqd;
|
||||||
(void) do_bit;
|
(void)do_bit;
|
||||||
|
(void)bogusanswer;
|
||||||
|
|
||||||
#ifdef HAVE_IPSET
|
#ifdef HAVE_IPSET
|
||||||
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
|
||||||
@@ -634,7 +636,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
if (no_cache && !(header->hb4 & HB4_CD))
|
if (bogusanswer && !(header->hb4 & HB4_CD))
|
||||||
{
|
{
|
||||||
if (!option_bool(OPT_DNSSEC_DEBUG))
|
if (!option_bool(OPT_DNSSEC_DEBUG))
|
||||||
{
|
{
|
||||||
@@ -786,7 +788,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
everything is broken */
|
everything is broken */
|
||||||
if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
|
if (forward->forwardall == 0 || --forward->forwardall == 1 || RCODE(header) != SERVFAIL)
|
||||||
{
|
{
|
||||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0;
|
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
|
|
||||||
if (option_bool(OPT_NO_REBIND))
|
if (option_bool(OPT_NO_REBIND))
|
||||||
check_rebind = !(forward->flags & FREC_NOREBIND);
|
check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||||
@@ -819,7 +821,13 @@ 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 || status == STAT_NO_NS)
|
/* Provably no DS, everything below is insecure, even if signatures are offered */
|
||||||
|
if (status == STAT_NO_DS)
|
||||||
|
/* We only cache sigs when we've validated a reply.
|
||||||
|
Avoid caching a reply with sigs if there's a vaildated break in the
|
||||||
|
DS chain, so we don't return replies from cache missing sigs. */
|
||||||
|
status = STAT_INSECURE_DS;
|
||||||
|
else if (status == STAT_NO_NS)
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
}
|
}
|
||||||
else if (forward->flags & FREC_CHECK_NOSIGN)
|
else if (forward->flags & FREC_CHECK_NOSIGN)
|
||||||
@@ -959,7 +967,13 @@ 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 || status == STAT_NO_NS)
|
/* Provably no DS, everything below is insecure, even if signatures are offered */
|
||||||
|
if (status == STAT_NO_DS)
|
||||||
|
/* We only cache sigs when we've validated a reply.
|
||||||
|
Avoid caching a reply with sigs if there's a vaildated break in the
|
||||||
|
DS chain, so we don't return replies from cache missing sigs. */
|
||||||
|
status = STAT_INSECURE_DS;
|
||||||
|
else if (status == STAT_NO_NS)
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
}
|
}
|
||||||
else if (forward->flags & FREC_CHECK_NOSIGN)
|
else if (forward->flags & FREC_CHECK_NOSIGN)
|
||||||
@@ -985,11 +999,22 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_cache_dnssec = 0;
|
||||||
|
|
||||||
|
if (status == STAT_INSECURE_DS)
|
||||||
|
{
|
||||||
|
/* We only cache sigs when we've validated a reply.
|
||||||
|
Avoid caching a reply with sigs if there's a vaildated break in the
|
||||||
|
DS chain, so we don't return replies from cache missing sigs. */
|
||||||
|
status = STAT_INSECURE;
|
||||||
|
no_cache_dnssec = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == STAT_TRUNCATED)
|
if (status == STAT_TRUNCATED)
|
||||||
header->hb3 |= HB3_TC;
|
header->hb3 |= HB3_TC;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *result;
|
char *result, *domain = "result";
|
||||||
|
|
||||||
if (forward->work_counter == 0)
|
if (forward->work_counter == 0)
|
||||||
{
|
{
|
||||||
@@ -999,15 +1024,19 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
else
|
else
|
||||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||||
|
|
||||||
log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
|
if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
|
||||||
}
|
domain = daemon->namebuff;
|
||||||
|
|
||||||
no_cache_dnssec = 0;
|
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
|
||||||
|
}
|
||||||
|
|
||||||
if (status == STAT_SECURE)
|
if (status == STAT_SECURE)
|
||||||
cache_secure = 1;
|
cache_secure = 1;
|
||||||
else if (status == STAT_BOGUS)
|
else if (status == STAT_BOGUS)
|
||||||
no_cache_dnssec = 1;
|
{
|
||||||
|
no_cache_dnssec = 1;
|
||||||
|
bogusanswer = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1017,7 +1046,7 @@ void reply_query(int fd, int family, time_t now)
|
|||||||
else
|
else
|
||||||
header->hb4 &= ~HB4_CD;
|
header->hb4 &= ~HB4_CD;
|
||||||
|
|
||||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure,
|
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||||
{
|
{
|
||||||
@@ -1420,7 +1449,7 @@ static int do_check_sign(struct frec *forward, int status, time_t now, char *nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move toward the root, until we find a signed non-existance of a DS, in which case
|
/* Move down from the root, until we find a signed non-existance of a DS, in which case
|
||||||
an unsigned answer is OK, or we find a signed DS, in which case there should be
|
an unsigned answer is OK, or we find a signed DS, in which case there should be
|
||||||
a signature, and the answer is BOGUS */
|
a signature, and the answer is BOGUS */
|
||||||
static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name,
|
static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, size_t plen, int class, char *name,
|
||||||
@@ -1570,8 +1599,13 @@ 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 || new_status == STAT_NO_NS))
|
if (status == STAT_NEED_DS)
|
||||||
new_status = STAT_BOGUS;
|
{
|
||||||
|
if (new_status == STAT_NO_DS)
|
||||||
|
new_status = STAT_INSECURE_DS;
|
||||||
|
else if (new_status == STAT_NO_NS)
|
||||||
|
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);
|
||||||
@@ -1630,8 +1664,13 @@ 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 || new_status == STAT_NO_NS))
|
if (status == STAT_NEED_DS)
|
||||||
new_status = STAT_BOGUS; /* Validated no DS */
|
{
|
||||||
|
if (new_status == STAT_NO_DS)
|
||||||
|
new_status = STAT_INSECURE_DS;
|
||||||
|
else if (new_status == STAT_NO_NS)
|
||||||
|
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);
|
||||||
@@ -1673,7 +1712,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
int local_auth = 0;
|
int local_auth = 0;
|
||||||
#endif
|
#endif
|
||||||
int checking_disabled, ad_question, do_bit, added_pheader = 0;
|
int checking_disabled, ad_question, do_bit, added_pheader = 0;
|
||||||
int check_subnet, no_cache_dnssec = 0, cache_secure = 0;
|
int check_subnet, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
size_t m;
|
size_t m;
|
||||||
unsigned short qtype;
|
unsigned short qtype;
|
||||||
unsigned int gotname;
|
unsigned int gotname;
|
||||||
@@ -1939,7 +1978,16 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
{
|
{
|
||||||
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
|
||||||
int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
|
int status = tcp_key_recurse(now, STAT_TRUNCATED, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
|
||||||
char *result;
|
char *result, *domain = "result";
|
||||||
|
|
||||||
|
if (status == STAT_INSECURE_DS)
|
||||||
|
{
|
||||||
|
/* We only cache sigs when we've validated a reply.
|
||||||
|
Avoid caching a reply with sigs if there's a vaildated break in the
|
||||||
|
DS chain, so we don't return replies from cache missing sigs. */
|
||||||
|
status = STAT_INSECURE;
|
||||||
|
no_cache_dnssec = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (keycount == 0)
|
if (keycount == 0)
|
||||||
{
|
{
|
||||||
@@ -1948,11 +1996,16 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||||
|
if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
|
||||||
|
domain = daemon->namebuff;
|
||||||
|
|
||||||
log_query(F_KEYTAG | F_SECSTAT, "result", NULL, result);
|
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
|
||||||
|
|
||||||
if (status == STAT_BOGUS)
|
if (status == STAT_BOGUS)
|
||||||
no_cache_dnssec = 1;
|
{
|
||||||
|
no_cache_dnssec = 1;
|
||||||
|
bogusanswer = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (status == STAT_SECURE)
|
if (status == STAT_SECURE)
|
||||||
cache_secure = 1;
|
cache_secure = 1;
|
||||||
@@ -1987,7 +2040,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec,
|
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, bogusanswer,
|
||||||
cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
|
cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ struct myoption {
|
|||||||
#define LOPT_DHOPT_INOTIFY 341
|
#define LOPT_DHOPT_INOTIFY 341
|
||||||
#define LOPT_HOST_INOTIFY 342
|
#define LOPT_HOST_INOTIFY 342
|
||||||
#define LOPT_DNSSEC_STAMP 343
|
#define LOPT_DNSSEC_STAMP 343
|
||||||
|
#define LOPT_TFTP_NO_FAIL 344
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -235,6 +236,7 @@ static const struct myoption opts[] =
|
|||||||
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
|
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
|
||||||
{ "enable-tftp", 2, 0, LOPT_TFTP },
|
{ "enable-tftp", 2, 0, LOPT_TFTP },
|
||||||
{ "tftp-secure", 0, 0, LOPT_SECURE },
|
{ "tftp-secure", 0, 0, LOPT_SECURE },
|
||||||
|
{ "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
|
||||||
{ "tftp-unique-root", 0, 0, LOPT_APREF },
|
{ "tftp-unique-root", 0, 0, LOPT_APREF },
|
||||||
{ "tftp-root", 1, 0, LOPT_PREFIX },
|
{ "tftp-root", 1, 0, LOPT_PREFIX },
|
||||||
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
|
{ "tftp-max", 1, 0, LOPT_TFTP_MAX },
|
||||||
@@ -419,6 +421,7 @@ static struct {
|
|||||||
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
||||||
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
||||||
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
||||||
|
{ LOPT_TFTP_NO_FAIL, OPT_TFTP_NO_FAIL, NULL, gettext_noop("Do not terminate the service if TFTP directories are inaccessible."), NULL },
|
||||||
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
||||||
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
||||||
{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
|
{ LOPT_TFTP_LC, OPT_TFTP_LC, NULL, gettext_noop("Convert TFTP filenames to lowercase"), NULL },
|
||||||
|
|||||||
+35
-7
@@ -20,7 +20,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
|||||||
char *name, int isExtract, int extrabytes)
|
char *name, int isExtract, int extrabytes)
|
||||||
{
|
{
|
||||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||||
unsigned int j, l, hops = 0;
|
unsigned int j, l, namelen = 0, hops = 0;
|
||||||
int retvalue = 1;
|
int retvalue = 1;
|
||||||
|
|
||||||
if (isExtract)
|
if (isExtract)
|
||||||
@@ -94,9 +94,15 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
|||||||
count = 256;
|
count = 256;
|
||||||
digs = ((count-1)>>2)+1;
|
digs = ((count-1)>>2)+1;
|
||||||
|
|
||||||
/* output is \[x<hex>/siz]. which is digs+9 chars */
|
/* output is \[x<hex>/siz]. which is digs+6/7/8 chars */
|
||||||
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
|
namelen += digs+6;
|
||||||
|
if (count > 9)
|
||||||
|
namelen++;
|
||||||
|
if (count > 99)
|
||||||
|
namelen++;
|
||||||
|
if (namelen+1 >= MAXDNAME)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!CHECK_LEN(header, p, plen, (count-1)>>3))
|
if (!CHECK_LEN(header, p, plen, (count-1)>>3))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -119,7 +125,8 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ /* label_type = 0 -> label. */
|
{ /* label_type = 0 -> label. */
|
||||||
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
|
namelen += l;
|
||||||
|
if (namelen+1 >= MAXDNAME)
|
||||||
return 0;
|
return 0;
|
||||||
if (!CHECK_LEN(header, p, plen, l))
|
if (!CHECK_LEN(header, p, plen, l))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -128,6 +135,19 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
|||||||
if (isExtract)
|
if (isExtract)
|
||||||
{
|
{
|
||||||
unsigned char c = *p;
|
unsigned char c = *p;
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID))
|
||||||
|
{
|
||||||
|
if (c == 0 || c == '.' || c == NAME_ESCAPE)
|
||||||
|
{
|
||||||
|
*cp++ = NAME_ESCAPE;
|
||||||
|
*cp++ = c+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*cp++ = c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
if (c != 0 && c != '.')
|
if (c != 0 && c != '.')
|
||||||
*cp++ = c;
|
*cp++ = c;
|
||||||
else
|
else
|
||||||
@@ -144,6 +164,11 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
|||||||
cp++;
|
cp++;
|
||||||
if (c1 >= 'A' && c1 <= 'Z')
|
if (c1 >= 'A' && c1 <= 'Z')
|
||||||
c1 += 'a' - 'A';
|
c1 += 'a' - 'A';
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
|
||||||
|
c1 = (*cp++)-1;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (c2 >= 'A' && c2 <= 'Z')
|
if (c2 >= 'A' && c2 <= 'Z')
|
||||||
c2 += 'a' - 'A';
|
c2 += 'a' - 'A';
|
||||||
|
|
||||||
@@ -1198,7 +1223,10 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||||
{
|
{
|
||||||
unsigned char *p = skip_questions(header, qlen);
|
unsigned char *p;
|
||||||
|
|
||||||
|
if (!(p = skip_questions(header, qlen)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* clear authoritative and truncated flags, set QR flag */
|
/* clear authoritative and truncated flags, set QR flag */
|
||||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||||
@@ -1214,7 +1242,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
SET_RCODE(header, NOERROR); /* empty domain */
|
SET_RCODE(header, NOERROR); /* empty domain */
|
||||||
else if (flags == F_NXDOMAIN)
|
else if (flags == F_NXDOMAIN)
|
||||||
SET_RCODE(header, NXDOMAIN);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
else if (p && flags == F_IPV4)
|
else if (flags == F_IPV4)
|
||||||
{ /* we know the address */
|
{ /* we know the address */
|
||||||
SET_RCODE(header, NOERROR);
|
SET_RCODE(header, NOERROR);
|
||||||
header->ancount = htons(1);
|
header->ancount = htons(1);
|
||||||
@@ -1222,7 +1250,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
|
|||||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (p && flags == F_IPV6)
|
else if (flags == F_IPV6)
|
||||||
{
|
{
|
||||||
SET_RCODE(header, NOERROR);
|
SET_RCODE(header, NOERROR);
|
||||||
header->ancount = htons(1);
|
header->ancount = htons(1);
|
||||||
|
|||||||
+10
-14
@@ -824,25 +824,21 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Windows 8 always requests an address even if the Managed bit
|
|
||||||
in RA is 0 and it keeps retrying if it receives a reply
|
|
||||||
stating that no addresses are available. We solve this
|
|
||||||
by not replying at all if we're not configured to give any
|
|
||||||
addresses by DHCPv6. RFC 3315 17.2.1. appears to allow this. */
|
|
||||||
|
|
||||||
for (c = state->context; c; c = c->current)
|
|
||||||
if (!(c->flags & CONTEXT_RA_STATELESS))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!c)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* no address, return error */
|
/* no address, return error */
|
||||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||||
put_opt6_short(DHCP6NOADDRS);
|
put_opt6_short(DHCP6NOADDRS);
|
||||||
put_opt6_string(_("no addresses available"));
|
put_opt6_string(_("no addresses available"));
|
||||||
end_opt6(o1);
|
end_opt6(o1);
|
||||||
log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
|
|
||||||
|
/* Some clients will ask repeatedly when we're not giving
|
||||||
|
out addresses because we're in stateless mode. Avoid spamming
|
||||||
|
the log in that case. */
|
||||||
|
for (c = state->context; c; c = c->current)
|
||||||
|
if (!(c->flags & CONTEXT_RA_STATELESS))
|
||||||
|
{
|
||||||
|
log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
+8
-1
@@ -226,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
|
|||||||
{
|
{
|
||||||
unsigned char *cp = p++;
|
unsigned char *cp = p++;
|
||||||
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
for (j = 0; *sval && (*sval != '.'); sval++, j++)
|
||||||
*p++ = *sval;
|
{
|
||||||
|
#ifdef HAVE_DNSSEC
|
||||||
|
if (option_bool(OPT_DNSSEC_VALID) && *sval == NAME_ESCAPE)
|
||||||
|
*p++ = (*(++sval))-1;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
*p++ = *sval;
|
||||||
|
}
|
||||||
*cp = j;
|
*cp = j;
|
||||||
if (*sval)
|
if (*sval)
|
||||||
sval++;
|
sval++;
|
||||||
|
|||||||
Reference in new issue
Block a user