Compare commits

...
40 Commits
Author SHA1 Message Date
Simon Kelley 4d25cf89d5 Handle corner cases in NSEC coverage checks. 2015-06-06 23:13:57 +01:00
Simon Kelley 24e9207e13 More reproducibility fixes for Debian package. 2015-06-04 22:32:43 +01:00
Simon Kelley 89130d91d6 DHCPv6: DHCPCONFIRM should be OK for any address on link, not just dynamic addresses. 2015-06-03 22:34:14 +01:00
Simon Kelley d644b2a17d Close Debian bug for bug fixed upstream. 2015-06-01 21:00:16 +01:00
swigger bd7bfa21c4 Correctly sanitise DNS header bits in answer when recreating query for retry. 2015-06-01 20:54:59 +01:00
Simon Kelley 403de05925 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq 2015-05-26 22:12:01 +01:00
John Hanks 46c89f2bd0 Add infiniband to example config file. 2015-05-26 22:07:57 +01:00
Christian Demsar 23facf0d77 Man page typo. 2015-05-20 20:26:23 +01:00
Simon Kelley 549b1a478c Tweak immediately previous patch. 2015-05-20 20:20:24 +01:00
Simon Kelley 7f8565b94c Select correct DHCP context when in PXE bootserver mode. 2015-05-19 23:01:27 +01:00
Simon Kelley 06568c6636 Remove support for DNS Extended Label Types.
The support was only partial, and the whole concept is
now deprecated in the standards.
2015-05-15 20:43:48 +01:00
Simon Kelley 5d07d77e75 Fix buffer overflow introduced in 2.73rc6.
Fix off-by-one in code which checks for over-long domain names
in received DNS packets. This enables buffer overflow attacks
which can certainly crash dnsmasq and may allow for arbitrary
code execution. The problem was introduced in commit b8f16556d,
release 2.73rc6, so has not escaped into any stable release.
Note that the off-by-one was in the label length determination,
so the buffer can be overflowed by as many bytes as there are
labels in the name - ie, many.

Thanks to Ron Bowes, who used lcmatuf's afl-fuzz tool to find
the problem.
2015-05-15 18:13:06 +01:00
Simon Kelley 62018e1f72 Use correct DHCP context for PXE-proxy server-id. 2015-05-14 21:30:00 +01:00
Simon Kelley 7c0f2543a7 Tweak last commit. 2015-05-14 21:16:18 +01:00
Simon Kelley ca85a28241 Allow T1 and T2 DHCPv4 options to be set. 2015-05-13 22:33:04 +01:00
Simon Kelley 585840b033 Pointer to mail-archive mailing list mirror in doc.html. 2015-05-13 12:35:57 +01:00
Simon Kelley dec180ac00 Tweak Debian systemd unit file. 2015-05-13 12:16:13 +01:00
Simon Kelley 86fa104692 Tweak EDNS timeout code. 2015-05-10 14:04:06 +01:00
Simon Kelley b059c96dc6 Check IPv4-mapped IPv6 addresses with --stop-rebind. 2015-05-08 20:25:51 +01:00
Simon Kelley a77cec8d58 Handle UDP packet loss when fragmentation of large packets is broken. 2015-05-08 16:25:38 +01:00
Nicolas Cavallari 64bcff1c7c Constify some DHCP lease management functions. 2015-04-28 21:55:18 +01:00
Simon Kelley 2ed162ac20 Don't remove RRSIG RR from answers to ANY queries when the do bit is not set. 2015-04-28 21:26:35 +01:00
Simon Kelley e66b4dff3c Fix argument-order botch which broke DNSSEC for TCP queries. 2015-04-28 20:45:57 +01:00
Johnny S. Lee 8efd731cc4 Make get-version work when repo is a git submodule. 2015-04-26 22:23:57 +01:00
Simon Kelley a5ae1f8587 Logs in DHCPv6 not suppressed by dhcp6-quiet. 2015-04-25 21:46:10 +01:00
Simon Kelley b8f16556d3 Tweaks to previous, DNS label charset commit. 2015-04-22 21:14:31 +01:00
Simon Kelley cbe379ad6b Handle domain names with '.' or /000 within labels.
Only in DNSSEC mode, where we might need to validate or store
such names. In none-DNSSEC mode, simply don't cache these, as before.
2015-04-21 22:57:06 +01:00
Simon Kelley 338b340be9 Revert 61b838dd57 and just quieten log instead. 2015-04-20 21:34:05 +01:00
Moshe Levi a006eb7e14 Check IP address command line arg in dhcp_release.c 2015-04-19 22:10:40 +01:00
Simon Kelley 554b580e97 Log domain when reporting DNSSEC validation failure. 2015-04-17 22:50:20 +01:00
Simon Kelley 0df29f5e23 Note CVE-2015-3294 2015-04-16 15:24:52 +01:00
Stefan Tomanek b4c0f092d8 Fix (srk induced) crash in new tftp_no_fail code. 2015-04-16 15:20:59 +01:00
Simon Kelley 78c6184752 Auth: correct replies to NS and SOA in .arpa zones. 2015-04-16 15:05:30 +01:00
Simon Kelley 38440b204d Fix crash in auth code with odd configuration. 2015-04-12 21:52:47 +01:00
Simon Kelley ad4a8ff7d9 Fix crash on receipt of certain malformed DNS requests. 2015-04-09 21:48:00 +01:00
Simon Kelley 04b0ac0537 Fix crash caused by looking up servers.bind when many servers defined. 2015-04-06 17:19:13 +01:00
Simon Kelley 982faf4024 Fix compiler warning when not including DNSSEC. 2015-04-03 21:42:30 +01:00
Simon Kelley fe3992f9fa Return INSECURE, rather than BOGUS when DS proved not to exist.
Return INSECURE when validating DNS replies which have RRSIGs, but
when a needed DS record in the trust chain is proved not to exist.
It's allowed for a zone to set up DNSKEY and RRSIG records first, then
add a DS later, completing the chain of trust.

Also, since we don't have the infrastructure to track that these
non-validated replies have RRSIGS, don't cache them, so we don't
provide answers with missing RRSIGS from the cache.
2015-04-03 21:25:05 +01:00
Stefan Tomanek 7aa970e2c7 Whitespace fixes. 2015-04-01 17:55:07 +01:00
Stefan Tomanek 30d0879ed5 add --tftp-no-fail to ignore missing tftp root 2015-03-31 22:32:11 +01:00
26 changed files with 538 additions and 244 deletions

No files matched your search

+58 -5
View File
@@ -68,10 +68,63 @@ version 2.73
Fix broken DNSSEC validation of ECDSA signatures.
Add --dnssec-timestamp option, which provides an automatic
way to detect when the system time becomes valid after boot
on systems without an RTC, whilst allowing DNS queries before the
clock is valid so that NTP can run. Thanks to
Kevin Darbyshire-Bryant for developing this idea.
way to detect when the system time becomes valid after
boot on systems without an RTC, whilst allowing DNS
queries before the clock is valid so that NTP can run.
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.
Fix logging of DHCPREPLY which should be suppressed
by quiet-dhcp6. Thanks to J. Pablo Abonia for
spotting the problem.
Try and handle net connections with broken fragmentation
that lose large UDP packets. If a server times out,
reduce the maximum UDP packet size field in the EDNS0
header to 1280 bytes. If it then answers, make that
change permanent.
Check IPv4-mapped IPv6 addresses when --stop-rebind
is active. Thanks to Jordan Milne for spotting this.
Allow DHCPv4 options T1 and T2 to be set using --dhcp-option.
Thanks to Kevin Benton for patches and work on this.
Fix code for DHCPCONFIRM DHCPv6 messages to confirm addresses
in the correct subnet, even of not in dynamic address
allocation range. Thanks to Steve Hirsch for spotting
the problem.
version 2.72
@@ -117,7 +170,7 @@ version 2.72
Fix problem with --local-service option on big-endian platforms
Thanks to Richard Genoud for the patch.
version 2.71
Subtle change to error handling to help DNSSEC validation
when servers fail to provide NODATA answers for
+3 -2
View File
@@ -11,8 +11,9 @@
# If there is more than one v[0-9].* tag, sort them and use the
# first. This favours, eg v2.63 over 2.63rc6.
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
cd $1; git describe | sed 's/^v//'
if which git >/dev/null 2>&1 && \
([ -d $1/.git ] || grep '^gitdir:' $1/.git >/dev/null 2>&1); then
cd $1; git describe | sed 's/^v//'
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
+5
View File
@@ -277,6 +277,11 @@ int main(int argc, char **argv)
exit(1);
}
if (inet_addr(argv[2]) == INADDR_NONE)
{
perror("invalid ip address");
exit(1);
}
lease.s_addr = inet_addr(argv[2]);
server = find_interface(lease, nl, if_nametoindex(argv[1]));
+3 -2
View File
@@ -1,12 +1,13 @@
dnsmasq (2.73-1) unstable; urgency=low
* New upstream.
* New upstream. (closes: #786996)
* Tweak field width in cache dump to avoid truncating IPv6
addresses. (closes: #771557)
* Add newline at the end of example config file. (LP: #1416895)
* Make Debian package build reproducible. (closes: #777323)
* Add Requires=network.target to systemd unit.
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:59:42 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 4 Jun 2015 22:31:42 +0000
dnsmasq (2.72-3) unstable; urgency=medium
+7 -3
View File
@@ -24,6 +24,7 @@ DEB_COPTS = $(COPTS)
TARGET = install-i18n
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
@@ -118,8 +119,9 @@ binary-indep: checkroot
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol $(PACKAGE_VERSION) -T -pdnsmasq -Pdebian/daemon
find debian/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
@@ -169,9 +171,10 @@ endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
find debian/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
@@ -196,9 +199,10 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
find debian/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..
+1
View File
@@ -1,5 +1,6 @@
[Unit]
Description=dnsmasq - A lightweight DHCP and caching DNS server
Requires=network.target
[Service]
Type=forking
+18
View File
@@ -251,6 +251,13 @@
# the IP address 192.168.0.60
#dhcp-host=id:01:02:02:04,192.168.0.60
# Always give the Infiniband interface with hardware address
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
# ip address 192.168.0.61. The client id is derived from the prefix
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
# hex digits of the hardware address.
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
# Always give the host with client identifier "marjorie"
# the IP address 192.168.0.60
#dhcp-host=id:marjorie,192.168.0.60
@@ -345,6 +352,14 @@
# Ask client to poll for option changes every six hours. (RFC4242)
#dhcp-option=option6:information-refresh-time,6h
# Set option 58 client renewal time (T1). Defaults to half of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T1:1m
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T2:2m
# Set the NTP time server address to be the same machine as
# is running dnsmasq
#dhcp-option=42,0.0.0.0
@@ -486,6 +501,9 @@
# Set the root directory for files available via FTP.
#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
# the user dnsmasq is running as will be send over the net.
#tftp-secure
+3 -1
View File
@@ -74,7 +74,9 @@ for details.
There is a dnsmasq mailing list at <A
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
first location for queries, bugreports, suggestions etc.
first location for queries, bugreports, suggestions etc. The list is mirrored, with a
search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</A>.
You can contact me at <A
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
+4 -1
View File
@@ -1388,7 +1388,7 @@ enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP
.B \-5, --no-ping
(IPv4 only) By default, the DHCP server will attempt to ensure that an address in
(IPv4 only) By default, the DHCP server will attempt to ensure that an address is
not in use before allocating it to a host. It does this by sending an
ICMP echo request (aka "ping") to the address in question. If it gets
a reply, then the address must already be in use, and another is
@@ -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
directory is only used for TFTP requests via that interface.
.TP
.B --tftp-no-fail
Do not abort startup if specified tftp root directories are inaccessible.
.TP
.B --tftp-unique-root
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
+37 -25
View File
@@ -131,24 +131,27 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
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)))
continue;
if (!local_query)
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = find_subnet(zone, flag, &addr)))
break;
if (!zone)
{
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = find_subnet(zone, flag, &addr)))
break;
if (!zone)
{
auth = 0;
continue;
}
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;
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 (in_zone(zone, intr->name, NULL))
if (local_query || in_zone(zone, intr->name, NULL))
{
found = 1;
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 */
/* add external domain */
strcat(name, ".");
strcat(name, zone->domain);
if (zone)
{
strcat(name, ".");
strcat(name, zone->domain);
}
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
found = 1;
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))
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));
found = 1;
@@ -240,14 +246,20 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
cname_restart:
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
if (found)
/* NS and SOA .arpa requests have set found above. */
cut = NULL;
else
{
auth = 0;
continue;
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
{
auth = 0;
continue;
}
}
for (rec = daemon->mxnames; rec; rec = rec->next)
+2 -2
View File
@@ -1367,7 +1367,7 @@ int cache_make_stat(struct txt_record *t)
}
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
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);
if (bytes_needed >= bytes_avail)
{
@@ -1381,7 +1381,7 @@ int cache_make_stat(struct txt_record *t)
lenp = p - 1;
buff = new;
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);
}
*lenp = bytes_needed;
+1
View File
@@ -19,6 +19,7 @@
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define SAFE_PKTSZ 1280 /* "go anywhere" UDP packet size */
#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 */
+2 -2
View File
@@ -545,8 +545,8 @@ static const struct opttab_t {
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_INTERNAL | OT_TIME},
{ "T2", 59, OT_INTERNAL | OT_TIME},
{ "T1", 58, OT_TIME},
{ "T2", 59, OT_TIME},
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
+15 -7
View File
@@ -84,15 +84,15 @@ struct dns_header {
u16 qdcount,ancount,nscount,arcount;
};
#define HB3_QR 0x80
#define HB3_QR 0x80 /* Query */
#define HB3_OPCODE 0x78
#define HB3_AA 0x04
#define HB3_TC 0x02
#define HB3_RD 0x01
#define HB3_AA 0x04 /* Authoritative Answer */
#define HB3_TC 0x02 /* TrunCated */
#define HB3_RD 0x01 /* Recursion Desired */
#define HB4_RA 0x80
#define HB4_AD 0x20
#define HB4_CD 0x10
#define HB4_RA 0x80 /* Recursion Available */
#define HB4_AD 0x20 /* Authenticated Data */
#define HB4_CD 0x10 /* Checking Disabled */
#define HB4_RCODE 0x0f
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
@@ -142,3 +142,11 @@ struct dns_header {
#define ADD_RDLEN(header, pp, plen, len) \
(!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
+46 -13
View File
@@ -58,6 +58,9 @@ int main (int argc, char **argv)
struct dhcp_context *context;
struct dhcp_relay *relay;
#endif
#ifdef HAVE_TFTP
int tftp_prefix_missing = 0;
#endif
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -99,8 +102,19 @@ int main (int argc, char **argv)
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID))
{
daemon->keyname = safe_malloc(MAXDNAME);
daemon->workspacename = safe_malloc(MAXDNAME);
/* Note that both /000 and '.' are allowed within labels. These get
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
@@ -342,7 +356,7 @@ int main (int argc, char **argv)
#else
die(_("DBus not available: set HAVE_DBUS in src/config.h"), NULL, EC_BADCONF);
#endif
if (daemon->port != 0)
pre_allocate_sfds();
@@ -636,7 +650,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_TFTP
if (option_bool(OPT_TFTP))
if (option_bool(OPT_TFTP))
{
DIR *dir;
struct tftp_prefix *p;
@@ -645,20 +659,31 @@ int main (int argc, char **argv)
{
if (!((dir = opendir(daemon->tftp_prefix))))
{
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, daemon->tftp_prefix);
_exit(0);
tftp_prefix_missing = 1;
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)
{
p->missing = 0;
if (!((dir = opendir(p->prefix))))
{
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
_exit(0);
}
closedir(dir);
{
p->missing = 1;
if (!option_bool(OPT_TFTP_NO_FAIL))
{
send_event(err_pipe[1], EVENT_TFTP_ERR, errno, p->prefix);
_exit(0);
}
}
else
closedir(dir);
}
}
#endif
@@ -773,6 +798,7 @@ int main (int argc, char **argv)
#ifdef HAVE_TFTP
if (option_bool(OPT_TFTP))
{
struct tftp_prefix *p;
#ifdef FD_SETSIZE
if (FD_SETSIZE < (unsigned)max_fd)
max_fd = FD_SETSIZE;
@@ -782,7 +808,14 @@ int main (int argc, char **argv)
daemon->tftp_prefix ? _("root is ") : _("enabled"),
daemon->tftp_prefix ? daemon->tftp_prefix: "",
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,
disjoint files might be served, but for large limits,
a single file will be sent to may clients (the file only needs
+11 -6
View File
@@ -240,7 +240,8 @@ struct event_desc {
#define OPT_LOCAL_SERVICE 49
#define OPT_LOOP_DETECT 50
#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
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -503,7 +504,7 @@ struct server {
char interface[IF_NAMESIZE+1];
struct serverfd *sfd;
char *domain; /* set if this server only handles a domain. */
int flags, tcpfd;
int flags, tcpfd, edns_pktsz;
unsigned int queries, failed_queries;
#ifdef HAVE_LOOP
u32 uid;
@@ -582,6 +583,7 @@ struct hostsfile {
#define STAT_NO_NS 10
#define STAT_NEED_DS_NEG 11
#define STAT_CHASE_CNAME 12
#define STAT_INSECURE_DS 13
#define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2
@@ -592,6 +594,7 @@ struct hostsfile {
#define FREC_DO_QUESTION 64
#define FREC_ADDED_PHEADER 128
#define FREC_CHECK_NOSIGN 256
#define FREC_TEST_PKTSZ 512
#ifdef HAVE_DNSSEC
#define HASH_SIZE 20 /* SHA-1 digest size */
@@ -901,6 +904,7 @@ struct addr_list {
struct tftp_prefix {
char *interface;
char *prefix;
int missing;
struct tftp_prefix *next;
};
@@ -1145,7 +1149,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif
/* dnssec.c */
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr);
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr, int edns_pktsz);
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t n, char *name, char *keyname, int class);
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class, int *neganswer, int *nons);
@@ -1301,9 +1305,10 @@ void lease_update_slaac(time_t now);
void lease_set_iaid(struct dhcp_lease *lease, int iaid);
void lease_make_duid(time_t now);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now, int force);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
const unsigned char *clid, int hw_len, int hw_type,
int clid_len, time_t now, int force);
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
+49 -17
View File
@@ -321,10 +321,18 @@ static int verify(struct blockdata *key_data, unsigned int key_len, unsigned cha
thus generating names in canonical form.
Calling to_wire followed by from_wire is almost an identity,
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)
{
unsigned char *l, *p, term;
unsigned char *l, *p, *q, term;
int len;
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++)
if (*p >= 'A' && *p <= 'Z')
*p = *p - 'A' + 'a';
else if (*p == NAME_ESCAPE)
{
for (q = p; *q; q++)
*q = *(q+1);
(*p)--;
}
term = *p;
if ((len = p - l) != 0)
@@ -351,13 +364,24 @@ static int to_wire(char *name)
/* Note: no compression allowed in input. */
static void from_wire(char *name)
{
unsigned char *l;
unsigned char *l, *p, *last;
int len;
for (last = (unsigned char *)name; *last != 0; last += *last+1);
for (l = (unsigned char *)name; *l != 0; l += len+1)
{
len = *l;
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] = '.';
}
@@ -645,7 +669,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
if (left1 != 0)
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;
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)
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;
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;
/* 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;
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 = htons(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. */
cp = p;
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);
if (cp != end)
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 (crecp->flags & F_NEG)
return STAT_INSECURE;
return STAT_INSECURE_DS;
/* NOTE, we need to find ONE DNSKEY which matches the DS */
for (valid = 0, j = ntohs(header->ancount); j != 0 && !valid; j--)
@@ -1468,13 +1493,13 @@ static int prove_non_existence_nsec(struct dns_header *header, size_t plen, unsi
{
/* Normal case, name falls between NSEC name and next domain name,
wrap around case, name falls between NSEC name (rc == -1) and end */
if (hostname_cmp(workspace2, name) == 1 || hostname_cmp(workspace1, workspace2) == 1)
if (hostname_cmp(workspace2, name) >= 0 || hostname_cmp(workspace1, workspace2) >= 0)
return STAT_SECURE;
}
else
{
/* wrap around case, name falls between start and next domain name */
if (hostname_cmp(workspace1, workspace2) == 1 && hostname_cmp(workspace2, name) == 1)
if (hostname_cmp(workspace1, workspace2) >= 0 && hostname_cmp(workspace2, name) >=0 )
return STAT_SECURE;
}
}
@@ -1607,17 +1632,17 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
return 1;
}
else if (rc <= 0)
else if (rc < 0)
{
/* Normal case, hash falls between NSEC3 name-hash and next domain name-hash,
wrap around case, name-hash falls between NSEC3 name-hash and end */
if (memcmp(p, digest, digest_len) > 0 || memcmp(workspace2, p, digest_len) > 0)
if (memcmp(p, digest, digest_len) >= 0 || memcmp(workspace2, p, digest_len) >= 0)
return 1;
}
else
{
/* wrap around case, name falls between start and next domain name */
if (memcmp(workspace2, p, digest_len) > 0 && memcmp(p, digest, digest_len) > 0)
if (memcmp(workspace2, p, digest_len) >= 0 && memcmp(p, digest, digest_len) >= 0)
return 1;
}
}
@@ -2137,10 +2162,12 @@ int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen)
}
}
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class, int type, union mysockaddr *addr)
size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, int class,
int type, union mysockaddr *addr, int edns_pktsz)
{
unsigned char *p;
char *types = querystr("dnssec-query", type);
size_t ret;
if (addr->sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, name, (struct all_addr *)&addr->in.sin_addr, types);
@@ -2169,7 +2196,12 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
PUTSHORT(type, p);
PUTSHORT(class, p);
return add_do_bit(header, p - (unsigned char *)header, end);
ret = add_do_bit(header, p - (unsigned char *)header, end);
if (find_pseudoheader(header, ret, NULL, &p, NULL))
PUTSHORT(edns_pktsz, p);
return ret;
}
/* Go through a domain name, find "pointers" and fix them up based on how many bytes
+113 -35
View File
@@ -253,6 +253,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
void *hash = &crc;
#endif
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
unsigned char *pheader;
(void)do_bit;
@@ -261,19 +262,32 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward = NULL;
else if (forward || (hash && (forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, hash))))
{
/* If we didn't get an answer advertising a maximal packet in EDNS,
fall back to 1280, which should work everywhere on IPv6.
If that generates an answer, it will become the new default
for this server */
forward->flags |= FREC_TEST_PKTSZ;
#ifdef HAVE_DNSSEC
/* If we've already got an answer to this query, but we're awaiting keys for validation,
there's no point retrying the query, retry the key query instead...... */
if (forward->blocking_query)
{
int fd;
forward->flags &= ~FREC_TEST_PKTSZ;
while (forward->blocking_query)
forward = forward->blocking_query;
forward->flags |= FREC_TEST_PKTSZ;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : forward->sentto->edns_pktsz, pheader);
if (forward->sentto->addr.sa.sa_family == AF_INET)
log_query(F_NOEXTRA | F_DNSSEC | F_IPV4, "retry", (struct all_addr *)&forward->sentto->addr.in.sin_addr, "dnssec");
#ifdef HAVE_IPV6
@@ -417,7 +431,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
plen = new_plen;
}
#endif
while (1)
{
/* only send to servers dealing with our domain.
@@ -464,6 +478,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#endif
}
if (find_pseudoheader(header, plen, NULL, &pheader, NULL))
PUTSHORT((forward->flags & FREC_TEST_PKTSZ) ? SAFE_PKTSZ : start->edns_pktsz, pheader);
if (retry_send(sendto(fd, (char *)header, plen, 0,
&start->addr.sa,
@@ -521,7 +538,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,
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;
char **sets = 0;
@@ -529,7 +547,8 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
size_t plen;
(void)ad_reqd;
(void) do_bit;
(void)do_bit;
(void)bogusanswer;
#ifdef HAVE_IPSET
if (daemon->ipsets && extract_request(header, n, daemon->namebuff, NULL))
@@ -634,7 +653,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
#ifdef HAVE_DNSSEC
if (no_cache && !(header->hb4 & HB4_CD))
if (bogusanswer && !(header->hb4 & HB4_CD))
{
if (!option_bool(OPT_DNSSEC_DEBUG))
{
@@ -750,7 +769,8 @@ void reply_query(int fd, int family, time_t now)
header->arcount = htons(0);
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
{
header->hb3 &= ~(HB3_QR | HB3_TC);
header->hb3 &= ~(HB3_QR | HB3_AA | HB3_TC);
header->hb4 &= ~(HB4_RA | HB4_RCODE);
forward_query(-1, NULL, NULL, 0, header, nn, now, forward, 0, 0);
return;
}
@@ -758,7 +778,6 @@ void reply_query(int fd, int family, time_t now)
}
server = forward->sentto;
if ((forward->sentto->flags & SERV_TYPE) == 0)
{
if (RCODE(header) == REFUSED)
@@ -779,14 +798,21 @@ void reply_query(int fd, int family, time_t now)
if (!option_bool(OPT_ALL_SERVERS))
daemon->last_server = server;
}
/* We tried resending to this server with a smaller maximum size and got an answer.
Make that permanent. To avoid reduxing the packet size for an single dropped packet,
only do this when we get a truncated answer, or one larger than the safe size. */
if (server && (forward->flags & FREC_TEST_PKTSZ) &&
((header->hb3 & HB3_TC) || n >= SAFE_PKTSZ))
server->edns_pktsz = SAFE_PKTSZ;
/* If the answer is an error, keep the forward record in place in case
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) != 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))
check_rebind = !(forward->flags & FREC_NOREBIND);
@@ -819,7 +845,13 @@ void reply_query(int fd, int family, time_t now)
else if (forward->flags & FREC_DS_QUERY)
{
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;
}
else if (forward->flags & FREC_CHECK_NOSIGN)
@@ -882,7 +914,7 @@ void reply_query(int fd, int family, time_t now)
{
new->flags |= FREC_DNSKEY_QUERY;
nn = dnssec_generate_query(header, ((char *) header) + daemon->packet_buff_sz,
daemon->keyname, forward->class, T_DNSKEY, &server->addr);
daemon->keyname, forward->class, T_DNSKEY, &server->addr, server->edns_pktsz);
}
else
{
@@ -891,7 +923,7 @@ void reply_query(int fd, int family, time_t now)
else
new->flags |= FREC_DS_QUERY;
nn = dnssec_generate_query(header,((char *) header) + daemon->packet_buff_sz,
daemon->keyname, forward->class, T_DS, &server->addr);
daemon->keyname, forward->class, T_DS, &server->addr, server->edns_pktsz);
}
if ((hash = hash_questions(header, nn, daemon->namebuff)))
memcpy(new->hash, hash, HASH_SIZE);
@@ -959,8 +991,14 @@ void reply_query(int fd, int family, time_t now)
else if (forward->flags & FREC_DS_QUERY)
{
status = dnssec_validate_ds(now, header, n, daemon->namebuff, daemon->keyname, forward->class);
if (status == STAT_NO_DS || status == STAT_NO_NS)
status = STAT_BOGUS;
/* 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;
}
else if (forward->flags & FREC_CHECK_NOSIGN)
{
@@ -985,11 +1023,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)
header->hb3 |= HB3_TC;
else
{
char *result;
char *result, *domain = "result";
if (forward->work_counter == 0)
{
@@ -999,15 +1048,19 @@ void reply_query(int fd, int family, time_t now)
else
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;
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
}
no_cache_dnssec = 0;
if (status == STAT_SECURE)
cache_secure = 1;
else if (status == STAT_BOGUS)
no_cache_dnssec = 1;
{
no_cache_dnssec = 1;
bogusanswer = 1;
}
}
#endif
@@ -1017,7 +1070,7 @@ void reply_query(int fd, int family, time_t now)
else
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_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->source)))
{
@@ -1420,7 +1473,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
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,
@@ -1497,7 +1550,7 @@ static int tcp_check_for_unsigned_zone(time_t now, struct dns_header *header, s
/* Can't find it in the cache, have to send a query */
m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr);
m = dnssec_generate_query(header, ((char *) header) + 65536, name_start, class, T_DS, &server->addr, server->edns_pktsz);
*length = htons(m);
@@ -1570,8 +1623,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)
{
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))
new_status = STAT_BOGUS;
if (status == STAT_NEED_DS)
{
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)
new_status = dnssec_chase_cname(now, header, n, name, keyname);
@@ -1604,7 +1662,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
another_tcp_key:
m = dnssec_generate_query(new_header, ((char *) new_header) + 65536, keyname, class,
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr);
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, &server->addr, server->edns_pktsz);
*length = htons(m);
@@ -1630,8 +1688,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)
{
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))
new_status = STAT_BOGUS; /* Validated no DS */
if (status == STAT_NEED_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)
new_status = dnssec_chase_cname(now, header, n, name, keyname);
@@ -1652,7 +1715,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
goto another_tcp_key;
}
}
free(packet);
}
return new_status;
@@ -1673,7 +1736,7 @@ unsigned char *tcp_request(int confd, time_t now,
int local_auth = 0;
#endif
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;
unsigned short qtype;
unsigned int gotname;
@@ -1939,8 +2002,17 @@ 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 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)
{
result = "ABANDONED";
@@ -1949,11 +2021,17 @@ unsigned char *tcp_request(int confd, time_t now,
else
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, m, daemon->namebuff, NULL))
domain = daemon->namebuff;
log_query(F_KEYTAG | F_SECSTAT, domain, NULL, result);
if (status == STAT_BOGUS)
no_cache_dnssec = 1;
{
no_cache_dnssec = 1;
bogusanswer = 1;
}
if (status == STAT_SECURE)
cache_secure = 1;
}
@@ -1987,8 +2065,8 @@ unsigned char *tcp_request(int confd, time_t now,
#endif
m = process_reply(header, now, last_server, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec,
cache_secure, ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
ad_question, do_bit, added_pheader, check_subnet, &peer_addr);
break;
}
+4 -4
View File
@@ -813,9 +813,9 @@ void lease_set_iaid(struct dhcp_lease *lease, int iaid)
}
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len,
time_t now, int force)
void lease_set_hwaddr(struct dhcp_lease *lease, const unsigned char *hwaddr,
const unsigned char *clid, int hw_len, int hw_type,
int clid_len, time_t now, int force)
{
#ifdef HAVE_DHCP6
int change = force;
@@ -897,7 +897,7 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
void lease_set_hostname(struct dhcp_lease *lease, const char *name, int auth, char *domain, char *config_domain)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
+1
View File
@@ -1396,6 +1396,7 @@ void add_update_server(int flags,
serv->domain = domain_str;
serv->next = next;
serv->queries = serv->failed_queries = 0;
serv->edns_pktsz = daemon->edns_pktsz;
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
+14 -7
View File
@@ -153,6 +153,7 @@ struct myoption {
#define LOPT_DHOPT_INOTIFY 341
#define LOPT_HOST_INOTIFY 342
#define LOPT_DNSSEC_STAMP 343
#define LOPT_TFTP_NO_FAIL 344
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -235,6 +236,7 @@ static const struct myoption opts[] =
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
{ "enable-tftp", 2, 0, LOPT_TFTP },
{ "tftp-secure", 0, 0, LOPT_SECURE },
{ "tftp-no-fail", 0, 0, LOPT_TFTP_NO_FAIL },
{ "tftp-unique-root", 0, 0, LOPT_APREF },
{ "tftp-root", 1, 0, LOPT_PREFIX },
{ "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_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_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_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 },
@@ -4495,15 +4498,19 @@ void read_opts(int argc, char **argv, char *compile_opts)
{
struct server *tmp;
for (tmp = daemon->servers; tmp; tmp = tmp->next)
if (!(tmp->flags & SERV_HAS_SOURCE))
{
if (tmp->source_addr.sa.sa_family == AF_INET)
tmp->source_addr.in.sin_port = htons(daemon->query_port);
{
tmp->edns_pktsz = daemon->edns_pktsz;
if (!(tmp->flags & SERV_HAS_SOURCE))
{
if (tmp->source_addr.sa.sa_family == AF_INET)
tmp->source_addr.in.sin_port = htons(daemon->query_port);
#ifdef HAVE_IPV6
else if (tmp->source_addr.sa.sa_family == AF_INET6)
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
else if (tmp->source_addr.sa.sa_family == AF_INET6)
tmp->source_addr.in6.sin6_port = htons(daemon->query_port);
#endif
}
}
}
}
if (daemon->if_addrs)
+60 -68
View File
@@ -20,7 +20,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
{
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;
if (isExtract)
@@ -77,49 +77,10 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
p = l + (unsigned char *)header;
}
else if (label_type == 0x80)
return 0; /* reserved */
else if (label_type == 0x40)
{ /* ELT */
unsigned int count, digs;
if ((l & 0x3f) != 1)
return 0; /* we only understand bitstrings */
if (!isExtract)
return 0; /* Cannot compare bitsrings */
count = *p++;
if (count == 0)
count = 256;
digs = ((count-1)>>2)+1;
/* output is \[x<hex>/siz]. which is digs+9 chars */
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0;
if (!CHECK_LEN(header, p, plen, (count-1)>>3))
return 0;
*cp++ = '\\';
*cp++ = '[';
*cp++ = 'x';
for (j=0; j<digs; j++)
{
unsigned int dig;
if (j%2 == 0)
dig = *p >> 4;
else
dig = *p++ & 0x0f;
*cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
}
cp += sprintf((char *)cp, "/%d]", count);
/* do this here to overwrite the zero char from sprintf */
*cp++ = '.';
}
else
else if (label_type == 0x00)
{ /* label_type = 0 -> label. */
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
namelen += l + 1; /* include period */
if (namelen >= MAXDNAME)
return 0;
if (!CHECK_LEN(header, p, plen, l))
return 0;
@@ -128,6 +89,19 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
if (isExtract)
{
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 != '.')
*cp++ = c;
else
@@ -144,19 +118,26 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
cp++;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && c1 == NAME_ESCAPE)
c1 = (*cp++)-1;
#endif
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
retvalue = 2;
}
}
if (isExtract)
*cp++ = '.';
else if (*cp != 0 && *cp++ != '.')
retvalue = 2;
}
else
return 0; /* label types 0x40 and 0x80 not supported */
}
}
@@ -527,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
return plen;
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */
PUTSHORT(0, p); /* extended RCODE and version */
PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
lenp = p;
@@ -1092,10 +1073,23 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
memcpy(&addr, p1, addrlen);
/* check for returned address in private space */
if (check_rebind &&
(flags & F_IPV4) &&
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
if (check_rebind)
{
if ((flags & F_IPV4) &&
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
#ifdef HAVE_IPV6
if ((flags & F_IPV6) &&
IN6_IS_ADDR_V4MAPPED(&addr.addr.addr6))
{
struct in_addr v4;
v4.s_addr = ((const uint32_t *) (&addr.addr.addr6))[3];
if (private_net(v4, !option_bool(OPT_LOCAL_REBIND)))
return 1;
}
#endif
}
#ifdef HAVE_IPSET
if (ipsets && (flags & (F_IPV4 | F_IPV6)))
@@ -1198,7 +1192,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,
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 */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
@@ -1214,7 +1211,7 @@ size_t setup_reply(struct dns_header *header, size_t qlen,
SET_RCODE(header, NOERROR); /* empty domain */
else if (flags == F_NXDOMAIN)
SET_RCODE(header, NXDOMAIN);
else if (p && flags == F_IPV4)
else if (flags == F_IPV4)
{ /* we know the address */
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
@@ -1222,7 +1219,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);
}
#ifdef HAVE_IPV6
else if (p && flags == F_IPV6)
else if (flags == F_IPV6)
{
SET_RCODE(header, NOERROR);
header->ancount = htons(1);
@@ -1509,7 +1506,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
unsigned short flag;
int q, ans, anscount = 0, addncount = 0;
int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0;
int is_sign;
struct crec *crecp;
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec;
@@ -1529,28 +1525,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
forward rather than answering from the cache, which doesn't include
security information, unless we're in DNSSEC validation mode. */
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
{
unsigned short udpsz, flags;
unsigned char *psave = pheader;
unsigned short flags;
have_pseudoheader = 1;
GETSHORT(udpsz, pheader);
pheader += 2; /* ext_rcode */
pheader += 4; /* udp size, ext_rcode */
GETSHORT(flags, pheader);
if ((sec_reqd = flags & 0x8000))
*do_bit = 1;/* do bit */
*ad_reqd = 1;
/* If our client is advertising a larger UDP packet size
than we allow, trim it so that we don't get an overlarge
response from upstream */
if (!is_sign && (udpsz > daemon->edns_pktsz))
PUTSHORT(daemon->edns_pktsz, psave);
dryrun = 1;
}
@@ -1580,6 +1567,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
GETSHORT(qtype, p);
GETSHORT(qclass, p);
/* Don't filter RRSIGS from answers to ANY queries, even if do-bit
not set. */
if (qtype == T_ANY)
*do_bit = 1;
ans = 0; /* have we answered this question */
if (qtype == T_TXT || qtype == T_ANY)
+59 -25
View File
@@ -52,7 +52,9 @@ static void do_options(struct dhcp_context *context,
int null_term, int pxearch,
unsigned char *uuid,
int vendor_class_len,
time_t now);
time_t now,
unsigned int lease_time,
unsigned short fuzz);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
@@ -610,7 +612,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now, 0xffffffff, 0);
}
}
@@ -803,9 +805,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (service->type == type)
break;
if (!service || !service->basename)
return 0;
for (; context; context = context->current)
if (match_netid(context->filter, tagif_netid, 1) &&
is_same_net(mess->ciaddr, context->start, context->netmask))
break;
if (!service || !service->basename || !context)
return 0;
clear_packet(mess, end);
mess->yiaddr = mess->ciaddr;
@@ -886,10 +893,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(tmp->local.s_addr));
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
do_encap_opts(pxe_opts(pxearch, tagif_netid, tmp->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", NULL, mess->xid);
log_tags(tagif_netid, ntohl(mess->xid));
@@ -1042,13 +1049,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
/* T1 and T2 are required in DHCPOFFER by HP's wacky Jetdirect client. */
if (time != 0xffffffff)
{
option_put(mess, end, OPTION_T1, 4, (time/2));
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1367,15 +1369,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
if (time != 0xffffffff)
{
while (fuzz > (time/16))
fuzz = fuzz/2;
option_put(mess, end, OPTION_T1, 4, (time/2) - fuzz);
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, time, fuzz);
}
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1440,7 +1435,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now, 0xffffffff, 0);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end);
@@ -2137,7 +2132,9 @@ static void do_options(struct dhcp_context *context,
int null_term, int pxe_arch,
unsigned char *uuid,
int vendor_class_len,
time_t now)
time_t now,
unsigned int lease_time,
unsigned short fuzz)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
struct dhcp_boot *boot;
@@ -2261,7 +2258,42 @@ static void do_options(struct dhcp_context *context,
/* rfc3011 says this doesn't need to be in the requested options list. */
if (subnet_addr.s_addr)
option_put(mess, end, OPTION_SUBNET_SELECT, INADDRSZ, ntohl(subnet_addr.s_addr));
if (lease_time != 0xffffffff)
{
unsigned int t1val = lease_time/2;
unsigned int t2val = (lease_time*7)/8;
unsigned int hval;
/* If set by user, sanity check, so not longer than lease. */
if ((opt = option_find2(OPTION_T1)))
{
hval = ntohl(*((unsigned int *)opt->val));
if (hval < lease_time && hval > 2)
t1val = hval;
}
if ((opt = option_find2(OPTION_T2)))
{
hval = ntohl(*((unsigned int *)opt->val));
if (hval < lease_time && hval > 2)
t2val = hval;
}
/* ensure T1 is still < T2 */
if (t2val <= t1val)
t1val = t2val - 1;
while (fuzz > (t1val/8))
fuzz = fuzz/2;
t1val -= fuzz;
t2val -= fuzz;
option_put(mess, end, OPTION_T1, 4, t1val);
option_put(mess, end, OPTION_T2, 4, t2val);
}
/* replies to DHCPINFORM may not have a valid context */
if (context)
{
@@ -2356,12 +2388,14 @@ static void do_options(struct dhcp_context *context,
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
continue;
/* prohibit some used-internally options */
/* prohibit some used-internally options. T1 and T2 already handled. */
if (optno == OPTION_CLIENT_FQDN ||
optno == OPTION_MAXMESSAGE ||
optno == OPTION_OVERLOAD ||
optno == OPTION_PAD ||
optno == OPTION_END)
optno == OPTION_END ||
optno == OPTION_T1 ||
optno == OPTION_T2)
continue;
if (optno == OPTION_SNAME && done_server)
+13 -17
View File
@@ -824,25 +824,21 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
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 */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("no addresses available"));
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;
@@ -1051,9 +1047,9 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
{
preferred_time = valid_time = 0;
message = _("address invalid");
}
}
if (message)
if (message && (message != state->hostname))
log6_packet(state, "DHCPREPLY", req_addr, message);
else
log6_quiet(state, "DHCPREPLY", req_addr, message);
@@ -1093,7 +1089,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
if (!address6_available(state->context, req_addr, tagif, 1))
if (!address6_valid(state->context, req_addr, tagif, 1))
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOTONLINK);
+1 -1
View File
@@ -236,7 +236,7 @@ void tftp_request(struct listener *listen, time_t now)
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
}
if (name)
{
/* check for per-interface prefix */
+8 -1
View File
@@ -226,7 +226,14 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
{
unsigned char *cp = p++;
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;
if (*sval)
sval++;