Compare commits

...
34 Commits
Author SHA1 Message Date
Simon Kelley fbc5205702 Fix problems validating NSEC3 and wildcards. 2014-12-23 15:46:08 +00:00
Simon Kelley cbc6524234 Make caching work for CNAMEs pointing to A/AAAA records shadowed in /etc/hosts
If the answer to an upstream query is a CNAME which points to an
A/AAAA record which also exists in /etc/hosts and friends, then
caching is suppressed, to avoid inconsistent answers. This is
now modified to allow caching when the upstream and local A/AAAA
records have the same value.
2014-12-21 21:21:53 +00:00
Simon Kelley 094b5c3d90 Fix crash in DNSSEC code when attempting to verify large RRs. 2014-12-21 16:11:52 +00:00
Simon Kelley 3267804598 Tweak field width in cache dump to avoid truncating IPv6 addresses. 2014-12-17 20:38:20 +00:00
Simon Kelley 476693678e Eliminate IPv6 privacy addresses from --interface-name answers. 2014-12-17 12:41:56 +00:00
Simon Kelley bd9520b7ad Remove redundant IN6_IS_ADDR_ULA(a) macro defn. 2014-12-16 20:41:29 +00:00
Simon Kelley 3ad3f3bbd4 Fix breakage of --domain=<domain>,<subnet>,local 2014-12-16 18:25:17 +00:00
Simon Kelley ad946d555d CHANGELOG re. inotify. 2014-12-15 17:52:22 +00:00
Simon Kelley 800c5cc1e7 Remove floor on EDNS0 packet size with DNSSEC. 2014-12-15 17:50:15 +00:00
Simon Kelley 857973e6f7 Teach the new inotify code about symlinks. 2014-12-15 15:58:13 +00:00
Simon Kelley 9c448c8018 Merge branch 'inotify' 2014-12-10 17:40:03 +00:00
Simon Kelley 193de4abf5 Use inotify instead of polling on Linux.
This should solve problems people are seeing when a file changes
twice within a second and thus is missed for polling.
2014-12-10 17:32:16 +00:00
Hans Dedecker 98906275a0 Fix conntrack with --bind-interfaces
Make sure dst_addr is assigned the correct address in receive_query when OPTNOWILD is
enabled so the assigned mark can be correctly retrieved and set in forward_query when
conntrack is enabled.

Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
2014-12-09 22:22:53 +00:00
Vladislav Grishenko b9ff5c8f43 Improve RFC-compliance when unable to supply addresses in DHCPv6
While testing https://github.com/sbyx/odhcp6c client I have noticed it
permanently crashes after startup.

The reason was it (odhcp6c) doesn't expect empty IA options in ADVERTISE
message without any suboptions.

Despite this validation bug of odhcp6c, dnsmasq should not generate
ADVERTISE messages with IA if there's nothing to advert per  RFC 3315
17.2.2:

   If the server will not assign any addresses to any IAs in a

   subsequent Request from the client, the server MUST send an Advertise

   message to the client that includes only a Status Code option with

   code NoAddrsAvail and a status message for the user, a Server

   Identifier option with the server's DUID, and a Client Identifier

   option with the client's DUID.

Meanwhile it's need to add status code for every IA in REPLY message per
RFC3315 18.2.1:

   If the server cannot assign any addresses to an IA in the message
   from the client, the server MUST include the IA in the Reply message
   with no addresses in the IA and a Status Code option in the IA
   containing status code NoAddrsAvail.

So, I've changed the logic to skip IA completely from ADVERTISE messages and
to add NoAddrsAvail subcode into IA of REPLY messages.

As for overhead, yes, I believe it's ok to return NoAddrsAvail twice in IA
and in global section for compatibility with all old and new clients.
2014-10-06 14:34:24 +01:00
Tomas Hozza 3d9d2dd001 Fit example conf file typo. 2014-10-06 10:46:48 +01:00
Daniel Collins 17b475912f Fix typo in new Dbus code.
Simon's fault.
2014-10-03 21:58:43 +01:00
Karl Vogel e9828b6f66 Set conntrack mark before connect() call.
SO_MARK has to be done before issuing the connect() call on the
TCP socket.
2014-10-03 21:45:15 +01:00
Simon Kelley 72eba2bffc Bump Debian version. 2014-10-03 08:50:37 +01:00
Simon Kelley 6ac3bc0452 Debian build fixes for kFreeBSD 2014-10-03 08:48:11 +01:00
Simon Kelley 00cd9d5519 crash at startup when an empty suffix is supplied to --conf-dir 2014-10-02 21:44:21 +01:00
Simon Kelley f2658275b2 Add newline at the end of example config file. 2014-09-25 21:51:25 +01:00
Jan Psota 25e27235dd Update Polish translation. 2014-09-23 22:16:15 +01:00
Simon Kelley bf2db4b084 Fix CHANGELOG entry under wrong version. 2014-09-18 22:10:46 +01:00
Simon Kelley 5782649ad9 Fix bug which caused dnsmasq to become unresponsive when an interface goes. 2014-09-18 22:08:58 +01:00
Simon Kelley 288df49c96 Fix bug when resulted in NXDOMAIN answers instead of NODATA.
check_for_local_domain() was broken due to new code matching F_*
bits in cache entries for DNSSEC. Because F_DNSKEY | F_DS is
used to match RRSIG entries, cache_find_by_name() insists on an exact match
of those bits. So adding F_DS to the bits that check_for_local_domain()
sends to cache_find_by_name() won't result in DS records as well
as the others, it results in only DS records. Add a new bit, F_NSIGMATCH
which suitably changes the behaviour of cache_find_by_name().
2014-09-18 21:55:27 +01:00
Richard Genoud 10cfc0ddb3 Fix length->netmask conversions to avoid undefined behaviour. 2014-09-17 21:17:39 +01:00
Richard Genoud 15b1b7e9c3 Fix endian bug in --local-service code. 2014-09-17 21:12:00 +01:00
Simon Kelley 00c0f69aa5 Debian bug closure. 2014-09-16 11:22:33 +01:00
Ilya Ponetaev 51943369e3 Supply "Success" status code in reply to DHCPDECLINE. 2014-09-13 21:19:01 +01:00
Ilya Ponetaev 2d75f2e4a5 Don't reply to DHCPCONFIRM messages with no addresses in them. 2014-09-13 21:11:16 +01:00
Ilya Ponetaev 976afc93e4 Set DHCPv6 message type when returning "use multicast". 2014-09-13 20:56:14 +01:00
Ilya Ponetaev 7f68f82146 DHCPv6 REBIND messages don't need a server-id. 2014-09-13 20:52:27 +01:00
Simon Kelley 85900a246c Revert route-information option in RA. There are problems with some clients.
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2014q3/008796.html
2014-09-13 20:42:54 +01:00
Simon Kelley b4f971a081 Update *.po files for new release. 2014-09-13 20:28:30 +01:00
33 changed files with 6253 additions and 4426 deletions

No files matched your search

+36 -4
View File
@@ -1,3 +1,29 @@
version 2.73
Fix crash at startup when an empty suffix is supplied to
--conf-dir, also trivial memory leak. Thanks to
Tomas Hozza for spotting this.
Remove floor of 4096 on advertised EDNS0 packet size when
DNSSEC in use, the original rationale for this has long gone.
Thanks to Anders Kaseorg for spotting this.
Use inotify for checking on updates to /etc/resolv.conf and
friends under Linux. This fixes race conditions when the files are
updated rapidly and saves CPU by noy polling.
Fix breakage of --domain=<domain>,<subnet>,local - only reverse
queries were intercepted. THis appears to have been broken
since 2.69. Thanks to Josh Stone for finding the bug.
Eliminate IPv6 privacy addresses and deprecated addresses from
the answers given by --interface-name. Note that reverse queries
(ie looking for names, given addresses) are not affected.
Thanks to Michael Gorbach for the suggestion.
Fix crash in DNSSEC code with long RRs. Thanks to Marco Davids
for the bug report.
version 2.72
Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
@@ -27,14 +53,20 @@ version 2.72
servers which loop back are disabled and this event is logged.
Thanks to Smoothwall for their sponsorship of this feature.
Include an RFC4191 route information option in router
advertisements for the prefix we're advertising. Thanks to
Ilya Ponetaev for the patch.
Extend --conf-dir to allow filtering of files. So
--conf-dir=/etc/dnsmasq.d,\*.conf
will load all the files in /etc/dnsmasq.d which end in .conf
Fix bug when resulted in NXDOMAIN answers instead of NODATA in
some circumstances.
Fix bug which caused dnsmasq to become unresponsive if it
failed to send packets due to a network interface disappearing.
Thanks to Niels Peen for spotting this.
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
+1 -1
View File
@@ -69,7 +69,7 @@ objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o \
domain.o dnssec.o blockdata.o tables.o loop.o
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h
+1 -1
View File
@@ -10,7 +10,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c
loop.c inotify.c
LOCAL_MODULE := dnsmasq
+15
View File
@@ -1,8 +1,23 @@
dnsmasq (2.73-1) unstable; urgency=low
* New upstream.
* Tweak field width in cache dump to avoid truncating IPv6
addresses. (closes: #771557)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 03 Oct 2014 08:49:42 +0000
dnsmasq (2.72-2) unstable; urgency=low
* Fix build in Debian-kFreeBSD. (closes: #763693)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 02 Oct 2014 22:34:12 +0000
dnsmasq (2.72-1) unstable; urgency=low
* New upstream.
* If dns-root-data package is installed, use it to set the DNSSEC
trust anchor(s). Recommend dns-root-data. (closes: #760460)
* Handle AD bit correctly in replies from cache. (closes: #761654)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 20 May 2014 21:01:11 +0000
+1 -1
View File
@@ -3,7 +3,7 @@ Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn11-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3)
nettle-dev (>=2.4-3), libbsd-dev [!linux-any]
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.5
+8 -3
View File
@@ -23,7 +23,7 @@ DEB_COPTS = $(COPTS)
TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
@@ -35,7 +35,7 @@ ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_BUILD_ARCH_OS),linux)
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
endif
endif
@@ -83,6 +83,11 @@ ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DNSSEC
endif
ifneq ($(DEB_HOST_ARCH_OS),linux)
# For strlcpy in FreeBSD
LDFLAGS += -lbsd
endif
clean:
$(checkdir)
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
@@ -171,7 +176,7 @@ endif
chmod -R g-ws debian/base
dpkg --build debian/base ..
ifeq ($(DEB_BUILD_ARCH_OS),linux)
ifeq ($(DEB_HOST_ARCH_OS),linux)
rm -rf debian/utils
install -m 755 -d debian/utils/DEBIAN \
-d debian/utils/usr/share/man/man1 \
+1 -1
View File
@@ -645,4 +645,4 @@
#conf-dir=/etc/dnsmasq.d,.bak
# Include all files in a directory which end in .conf
#conf-dir=/etc/dnsmasq.d/*.conf
#conf-dir=/etc/dnsmasq.d/,*.conf
+585 -482
View File
File diff suppressed because it is too large. Load diff
+545 -383
View File
File diff suppressed because it is too large. Load diff
+603 -448
View File
File diff suppressed because it is too large. Load diff
+548 -383
View File
File diff suppressed because it is too large. Load diff
+571 -398
View File
File diff suppressed because it is too large. Load diff
+603 -448
View File
File diff suppressed because it is too large. Load diff
+557 -396
View File
File diff suppressed because it is too large. Load diff
+542 -387
View File
File diff suppressed because it is too large. Load diff
+603 -448
View File
File diff suppressed because it is too large. Load diff
+557 -396
View File
File diff suppressed because it is too large. Load diff
+5 -1
View File
@@ -31,7 +31,7 @@ static struct addrlist *find_subnet(struct auth_zone *zone, int flag, struct all
if (!(flag & F_IPV4))
continue;
netmask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - subnet->prefixlen));
if (is_same_net(addr, subnet->addr.addr.addr4, netmask))
return subnet;
@@ -363,6 +363,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
(local_query || filter_zone(zone, flag, &addrlist->addr)))
{
#ifdef HAVE_IPV6
if (addrlist->flags & ADDRLIST_REVONLY)
continue;
#endif
found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
+29 -13
View File
@@ -322,7 +322,7 @@ static int is_expired(time_t now, struct crec *crecp)
return 1;
}
static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
static struct crec *cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
{
/* Scan and remove old entries.
If (flags & F_FORWARD) then remove any forward entries for name and any expired
@@ -331,8 +331,8 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
entries in the whole cache.
If (flags == 0) remove any expired entries in the whole cache.
In the flags & F_FORWARD case, the return code is valid, and returns zero if the
name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
In the flags & F_FORWARD case, the return code is valid, and returns a non-NULL pointer
to a cache entry if the name exists in the cache as a HOSTS or DHCP entry (these are never deleted)
We take advantage of the fact that hash chains have stuff in the order <reverse>,<other>,<immortal>
so that when we hit an entry which isn't reverse and is immortal, we're done. */
@@ -361,7 +361,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
{
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
return 0;
return crecp;
*up = crecp->hash_next;
cache_unlink(crecp);
cache_free(crecp);
@@ -378,7 +378,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
crecp->addr.sig.type_covered == addr->addr.dnssec.type))
{
if (crecp->flags & F_CONFIG)
return 0;
return crecp;
*up = crecp->hash_next;
cache_unlink(crecp);
cache_free(crecp);
@@ -423,7 +423,7 @@ static int cache_scan_free(char *name, struct all_addr *addr, time_t now, unsign
up = &crecp->hash_next;
}
return 1;
return NULL;
}
/* Note: The normal calling sequence is
@@ -471,10 +471,26 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
return NULL;
/* First remove any expired entries and entries for the name/address we
are currently inserting. Fail if we attempt to delete a name from
/etc/hosts or DHCP. */
if (!cache_scan_free(name, addr, now, flags))
are currently inserting. */
if ((new = cache_scan_free(name, addr, now, flags)))
{
/* We're trying to insert a record over one from
/etc/hosts or DHCP, or other config. If the
existing record is for an A or AAAA and
the record we're trying to insert is the same,
just drop the insert, but don't error the whole process. */
if ((flags & (F_IPV4 | F_IPV6)) && (flags & F_FORWARD))
{
if ((flags & F_IPV4) && (new->flags & F_IPV4) &&
new->addr.addr.addr.addr4.s_addr == addr->addr.addr4.s_addr)
return new;
#ifdef HAVE_IPV6
else if ((flags & F_IPV6) && (new->flags & F_IPV6) &&
IN6_ARE_ADDR_EQUAL(&new->addr.addr.addr.addr6, &addr->addr.addr6))
return new;
#endif
}
insert_error = 1;
return NULL;
}
@@ -636,7 +652,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
{
if ((crecp->flags & F_FORWARD) &&
#ifdef HAVE_DNSSEC
((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
(((crecp->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
#endif
(crecp->flags & prot) &&
hostname_isequal(cache_get_name(crecp), name))
@@ -696,7 +712,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
if (ans &&
(ans->flags & F_FORWARD) &&
#ifdef HAVE_DNSSEC
((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) &&
(((ans->flags & (F_DNSKEY | F_DS)) == (prot & (F_DNSKEY | F_DS))) || (prot & F_NSIGMATCH)) &&
#endif
(ans->flags & prot) &&
hostname_isequal(cache_get_name(ans), name))
@@ -1411,7 +1427,7 @@ void dump_cache(time_t now)
*a = 0;
if (strlen(n) == 0 && !(cache->flags & F_REVERSE))
n = "<Root>";
p += sprintf(p, "%-40.40s ", n);
p += sprintf(p, "%-30.30s ", n);
if ((cache->flags & F_CNAME) && !is_outdated_cname_pointer(cache))
a = cache_get_cname_target(cache);
#ifdef HAVE_DNSSEC
@@ -1454,7 +1470,7 @@ void dump_cache(time_t now)
else if (cache->flags & F_DNSKEY)
t = "K";
#endif
p += sprintf(p, "%-30.30s %s%s%s%s%s%s%s%s%s ", a, t,
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
cache->flags & F_FORWARD ? "F" : " ",
cache->flags & F_REVERSE ? "R" : " ",
cache->flags & F_IMMORTAL ? "I" : " ",
+1 -1
View File
@@ -426,7 +426,7 @@ static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
}
else
{
my_syslog(LOG_INFO, "Disabling --$s option from D-Bus", name);
my_syslog(LOG_INFO, "Disabling --%s option from D-Bus", name);
reset_option_bool(flag);
}
+23 -7
View File
@@ -87,11 +87,6 @@ int main (int argc, char **argv)
if (daemon->edns_pktsz < PACKETSZ)
daemon->edns_pktsz = PACKETSZ;
#ifdef HAVE_DNSSEC
/* Enforce min packet big enough for DNSSEC */
if (option_bool(OPT_DNSSEC_VALID) && daemon->edns_pktsz < EDNS_PKTSZ)
daemon->edns_pktsz = EDNS_PKTSZ;
#endif
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
@@ -315,9 +310,15 @@ int main (int argc, char **argv)
if (daemon->port != 0)
{
cache_init();
#ifdef HAVE_DNSSEC
blockdata_init();
#endif
#ifdef HAVE_LINUX_NETWORK
if (!option_bool(OPT_NO_POLL))
inotify_dnsmasq_init();
#endif
}
if (option_bool(OPT_DBUS))
@@ -793,6 +794,11 @@ int main (int argc, char **argv)
pid = getpid();
#ifdef HAVE_LINUX_NETWORK
/* Using inotify, have to select a resolv file at startup */
poll_resolv(1, 0, now);
#endif
while (1)
{
int maxfd = -1;
@@ -862,11 +868,16 @@ int main (int argc, char **argv)
#if defined(HAVE_LINUX_NETWORK)
FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd);
if (daemon->port != 0 && !option_bool(OPT_NO_POLL))
{
FD_SET(daemon->inotifyfd, &rset);
bump_maxfd(daemon->inotifyfd, &maxfd);
}
#elif defined(HAVE_BSD_NETWORK)
FD_SET(daemon->routefd, &rset);
bump_maxfd(daemon->routefd, &maxfd);
#endif
FD_SET(piperead, &rset);
bump_maxfd(piperead, &maxfd);
@@ -929,6 +940,10 @@ int main (int argc, char **argv)
route_sock();
#endif
#ifdef HAVE_LINUX_NETWORK
if (daemon->port != 0 && !option_bool(OPT_NO_POLL) && FD_ISSET(daemon->inotifyfd, &rset) && inotify_check())
poll_resolv(1, 1, now);
#else
/* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */
if (daemon->last_resolv == 0 ||
@@ -941,7 +956,8 @@ int main (int argc, char **argv)
poll_resolv(0, daemon->last_resolv != 0, now);
daemon->last_resolv = now;
}
#endif
if (FD_ISSET(piperead, &rset))
async_event(piperead, now);
+12 -1
View File
@@ -318,6 +318,7 @@ struct ds_config {
#define ADDRLIST_LITERAL 1
#define ADDRLIST_IPV6 2
#define ADDRLIST_REVONLY 4
struct addrlist {
struct all_addr addr;
@@ -440,6 +441,7 @@ struct crec {
#define F_SECSTAT (1u<<24)
#define F_NO_RR (1u<<25)
#define F_IPSET (1u<<26)
#define F_NSIGMATCH (1u<<27)
/* Values of uid in crecs with F_CONFIG bit set. */
#define SRC_INTERFACE 0
@@ -540,6 +542,10 @@ struct resolvc {
int is_default, logged;
time_t mtime;
char *name;
#ifdef HAVE_LINUX_NETWORK
int wd; /* inotify watch descriptor */
char *file; /* pointer to file part if path */
#endif
};
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
@@ -997,7 +1003,7 @@ extern struct daemon {
/* DHCP state */
int dhcpfd, helperfd, pxefd;
#if defined(HAVE_LINUX_NETWORK)
int netlinkfd;
int netlinkfd, inotifyfd;
#elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd, routefd;
#endif
@@ -1468,3 +1474,8 @@ void loop_send_probes();
int detect_loop(char *query, int type);
#endif
/* inotify.c */
#ifdef HAVE_LINUX_NETWORK
void inotify_dnsmasq_init();
int inotify_check(void);
#endif
+147 -133
View File
@@ -456,16 +456,27 @@ static u16 *get_desc(int type)
/* Return bytes of canonicalised rdata, when the return value is zero, the remaining
data, pointed to by *p, should be used raw. */
static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff,
static int get_rdata(struct dns_header *header, size_t plen, unsigned char *end, char *buff, int bufflen,
unsigned char **p, u16 **desc)
{
int d = **desc;
(*desc)++;
/* No more data needs mangling */
if (d == (u16)-1)
return 0;
{
/* If there's more data than we have space for, just return what fits,
we'll get called again for more chunks */
if (end - *p > bufflen)
{
memcpy(buff, *p, bufflen);
*p += bufflen;
return bufflen;
}
return 0;
}
(*desc)++;
if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
/* domain-name, canonicalise */
@@ -560,7 +571,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, &p1, &dp1)) == 0)
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, MAXDNAME - left1, &p1, &dp1)) == 0)
{
quit = 1;
len1 = end1 - p1;
@@ -571,7 +582,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, &p2, &dp2)) == 0)
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, MAXDNAME - left2, &p2, &dp2)) == 0)
{
quit = 1;
len2 = end2 - p2;
@@ -604,6 +615,7 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
Return code:
STAT_SECURE if it validates.
STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
(In this case *wildcard_out points to the "body" of the wildcard within name.)
STAT_NO_SIG no RRsigs found.
STAT_INSECURE RRset empty.
STAT_BOGUS signature is wrong, bad packet.
@@ -614,8 +626,8 @@ static void sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int
name is unchanged on exit. keyname is used as workspace and trashed.
*/
static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class,
int type, char *name, char *keyname, struct blockdata *key, int keylen, int algo_in, int keytag_in)
static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type,
char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen, int algo_in, int keytag_in)
{
static unsigned char **rrset = NULL, **sigs = NULL;
static int rrset_sz = 0, sig_sz = 0;
@@ -787,8 +799,16 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
{
int k;
for (k = name_labels - labels; k != 0; k--)
while (*name_start != '.' && *name_start != 0)
name_start++;
{
while (*name_start != '.' && *name_start != 0)
name_start++;
if (k != 1)
name_start++;
}
if (wildcard_out)
*wildcard_out = name_start+1;
name_start--;
*name_start = '*';
}
@@ -808,7 +828,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
/* canonicalise rdata and calculate length of same, use name buffer as workspace */
cp = p;
dp = rr_desc;
for (len = 0; (seg = get_rdata(header, plen, end, name, &cp, &dp)) != 0; len += seg);
for (len = 0; (seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)) != 0; len += seg);
len += end - cp;
len = htons(len);
hash->update(ctx, 2, (unsigned char *)&len);
@@ -816,7 +836,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, &cp, &dp)))
while ((seg = get_rdata(header, plen, end, name, MAXDNAME, &cp, &dp)))
hash->update(ctx, seg, (unsigned char *)name);
if (cp != end)
hash->update(ctx, end - cp, cp);
@@ -963,7 +983,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
if (recp1->addr.ds.keylen == (int)hash->digest_size &&
(ds_digest = blockdata_retrieve(recp1->addr.key.keydata, recp1->addr.ds.keylen, NULL)) &&
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, key, rdlen - 4, algo, keytag) == STAT_SECURE)
validate_rrset(now, header, plen, class, T_DNSKEY, name, keyname, NULL, key, rdlen - 4, algo, keytag) == STAT_SECURE)
{
valid = 1;
break;
@@ -1432,11 +1452,88 @@ static int base32_decode(char *in, unsigned char *out)
return p - out;
}
static int check_nsec3_coverage(struct dns_header *header, size_t plen, int digest_len, unsigned char *digest, int type,
char *workspace1, char *workspace2, unsigned char **nsecs, int nsec_count)
{
int i, hash_len, salt_len, base32_len, rdlen;
unsigned char *p, *psave;
for (i = 0; i < nsec_count; i++)
if ((p = nsecs[i]))
{
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
return 0;
p += 8; /* class, type, TTL */
GETSHORT(rdlen, p);
psave = p;
p += 4; /* algo, flags, iterations */
salt_len = *p++; /* salt_len */
p += salt_len; /* salt */
hash_len = *p++; /* p now points to next hashed name */
if (!CHECK_LEN(header, p, plen, hash_len))
return 0;
if (digest_len == base32_len && hash_len == base32_len)
{
int rc = memcmp(workspace2, digest, digest_len);
if (rc == 0)
{
/* We found an NSEC3 whose hashed name exactly matches the query, so
we just need to check the type map. p points to the RR data for the record. */
int offset = (type & 0xff) >> 3;
int mask = 0x80 >> (type & 0x07);
p += hash_len; /* skip next-domain hash */
rdlen -= p - psave;
if (!CHECK_LEN(header, p, plen, rdlen))
return 0;
while (rdlen >= 2)
{
if (p[0] == type >> 8)
{
/* Does the NSEC3 say our type exists? */
if (offset < p[1] && (p[offset+2] & mask) != 0)
return STAT_BOGUS;
break; /* finshed checking */
}
rdlen -= p[1];
p += p[1];
}
return 1;
}
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)
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)
return 1;
}
}
}
return 0;
}
static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count,
char *workspace1, char *workspace2, char *name, int type)
char *workspace1, char *workspace2, char *name, int type, char *wildname)
{
unsigned char *salt, *p, *digest;
int digest_len, i, iterations, salt_len, hash_len, base32_len, algo = 0;
int digest_len, i, iterations, salt_len, base32_len, algo = 0;
struct nettle_hash const *hash;
char *closest_encloser, *next_closest, *wildcard;
@@ -1509,7 +1606,14 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if (!(hash = hash_find("sha1")))
return STAT_BOGUS;
/* Now, we need the "closest encloser NSEC3" */
if ((digest_len = hash_name(name, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS;
if (check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
return STAT_SECURE;
/* Can't find an NSEC3 which covers the name directly, we need the "closest encloser NSEC3"
or an answer inferred from a wildcard record. */
closest_encloser = name;
next_closest = NULL;
@@ -1518,6 +1622,9 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
if (*closest_encloser == '.')
closest_encloser++;
if (wildname && hostname_isequal(closest_encloser, wildname))
break;
if ((digest_len = hash_name(closest_encloser, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS;
@@ -1540,127 +1647,33 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
}
while ((closest_encloser = strchr(closest_encloser, '.')));
/* No usable NSEC3s */
if (i == nsec_count)
if (!closest_encloser)
return STAT_BOGUS;
if (!next_closest)
{
/* We found an NSEC3 whose hashed name exactly matches the query, so
Now we just need to check the type map. p points to the RR data for the record. */
int rdlen;
unsigned char *psave;
int offset = (type & 0xff) >> 3;
int mask = 0x80 >> (type & 0x07);
p += 8; /* class, type, TTL */
GETSHORT(rdlen, p);
psave = p;
p += 5 + salt_len; /* algo, flags, iterations, salt_len, salt */
hash_len = *p++;
if (!CHECK_LEN(header, p, plen, hash_len))
return STAT_BOGUS; /* bad packet */
p += hash_len;
rdlen -= p - psave;
while (rdlen >= 2)
{
if (!CHECK_LEN(header, p, plen, rdlen))
return STAT_BOGUS;
if (p[0] == type >> 8)
{
/* Does the NSEC3 say our type exists? */
if (offset < p[1] && (p[offset+2] & mask) != 0)
return STAT_BOGUS;
break; /* finshed checking */
}
rdlen -= p[1];
p += p[1];
}
return STAT_SECURE;
}
/* Look for NSEC3 that proves the non-existence of the next-closest encloser */
if ((digest_len = hash_name(next_closest, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS;
for (i = 0; i < nsec_count; i++)
if ((p = nsecs[i]))
{
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
return STAT_BOGUS;
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
hash_len = *p++; /* p now points to next hashed name */
if (!CHECK_LEN(header, p, plen, hash_len))
return STAT_BOGUS;
if (digest_len == base32_len && hash_len == base32_len)
{
if (memcmp(workspace2, digest, digest_len) <= 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)
return STAT_SECURE;
}
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)
return STAT_SECURE;
}
}
}
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
return STAT_BOGUS;
/* Finally, check that there's no seat of wildcard synthesis */
if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
return STAT_BOGUS;
if (!wildname)
{
if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
return STAT_BOGUS;
wildcard--;
*wildcard = '*';
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS;
if (!check_nsec3_coverage(header, plen, digest_len, digest, type, workspace1, workspace2, nsecs, nsec_count))
return STAT_BOGUS;
}
wildcard--;
*wildcard = '*';
if ((digest_len = hash_name(wildcard, &digest, hash, salt, salt_len, iterations)) == 0)
return STAT_BOGUS;
for (i = 0; i < nsec_count; i++)
if ((p = nsecs[i]))
{
if (!extract_name(header, plen, &p, workspace1, 1, 0) ||
!(base32_len = base32_decode(workspace1, (unsigned char *)workspace2)))
return STAT_BOGUS;
p += 15 + salt_len; /* class, type, TTL, rdlen, algo, flags, iterations, salt_len, salt */
hash_len = *p++; /* p now points to next hashed name */
if (!CHECK_LEN(header, p, plen, hash_len))
return STAT_BOGUS;
if (digest_len == base32_len && hash_len == base32_len)
{
if (memcmp(workspace2, digest, digest_len) <= 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)
return STAT_SECURE;
}
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)
return STAT_SECURE;
}
}
}
return STAT_BOGUS;
return STAT_SECURE;
}
/* Validate all the RRsets in the answer and authority sections of the reply (4035:3.2.3) */
@@ -1781,8 +1794,9 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
struct all_addr a;
struct blockdata *key;
struct crec *crecp;
rc = validate_rrset(now, header, plen, class1, type1, name, keyname, NULL, 0, 0, 0);
char *wildname;
rc = validate_rrset(now, header, plen, class1, type1, name, keyname, &wildname, NULL, 0, 0, 0);
if (rc == STAT_SECURE_WILDCARD)
{
@@ -1796,7 +1810,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
if (nsec_type == T_NSEC)
rc = prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
else
rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1);
rc = prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, type1, wildname);
if (rc != STAT_SECURE)
return rc;
@@ -1922,7 +1936,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
if (nsec_type == T_NSEC)
return prove_non_existence_nsec(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
else
return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype);
return prove_non_existence_nsec3(header, plen, nsecs, nsec_count, daemon->workspacename, keyname, name, qtype, NULL);
}
/* Chase the CNAME chain in the packet until the first record which _doesn't validate.
@@ -1969,7 +1983,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
return STAT_INSECURE;
/* validate CNAME chain, return if insecure or need more data */
rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, 0, 0, 0);
rc = validate_rrset(now, header, plen, class, type, name, keyname, NULL, NULL, 0, 0, 0);
if (rc != STAT_SECURE)
{
if (rc == STAT_NO_SIG)
+22 -22
View File
@@ -1048,7 +1048,7 @@ void receive_query(struct listener *listen, time_t now)
/* packet buffer overwritten */
daemon->srv_save = NULL;
dst_addr_4.s_addr = 0;
dst_addr_4.s_addr = dst_addr.addr.addr4.s_addr = 0;
netmask.s_addr = 0;
if (option_bool(OPT_NOWILD) && listen->iface)
@@ -1057,7 +1057,7 @@ void receive_query(struct listener *listen, time_t now)
if (listen->family == AF_INET)
{
dst_addr_4 = listen->iface->addr.in.sin_addr;
dst_addr_4 = dst_addr.addr.addr4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask;
}
}
@@ -1118,7 +1118,7 @@ void receive_query(struct listener *listen, time_t now)
struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next)
{
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, source_addr.in.sin_addr, netmask))
break;
@@ -1652,7 +1652,7 @@ unsigned char *tcp_request(int confd, time_t now,
struct in_addr netmask;
for (addr = daemon->interface_addrs; addr; addr = addr->next)
{
netmask.s_addr = 0xffffffff << (32 - addr->prefixlen);
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - addr->prefixlen));
if (!(addr->flags & ADDRLIST_IPV6) &&
is_same_net(addr->addr.addr.addr4, peer_addr.in.sin_addr, netmask))
break;
@@ -1796,6 +1796,24 @@ unsigned char *tcp_request(int confd, time_t now,
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue;
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
@@ -1820,24 +1838,6 @@ unsigned char *tcp_request(int confd, time_t now,
size = new_size;
}
#endif
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
}
*length = htons(size);
+113
View File
@@ -0,0 +1,113 @@
/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#include <sys/inotify.h>
#ifdef HAVE_LINUX_NETWORK
/* the strategy is to set a inotify on the directories containing
resolv files, for any files in the directory which are close-write
or moved into the directory.
When either of those happen, we look to see if the file involved
is actually a resolv-file, and if so, call poll-resolv with
the "force" argument, to ensure it's read.
This adds one new error condition: the directories containing
all specified resolv-files must exist at start-up, even if the actual
files don't.
*/
static char *inotify_buffer;
#define INOTIFY_SZ (sizeof(struct inotify_event) + NAME_MAX + 1)
void inotify_dnsmasq_init()
{
struct resolvc *res;
inotify_buffer = safe_malloc(INOTIFY_SZ);
daemon->inotifyfd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (daemon->inotifyfd == -1)
die(_("failed to create inotify: %s"), NULL, EC_MISC);
for (res = daemon->resolv_files; res; res = res->next)
{
char *d = NULL, *path;
if (!(path = realpath(res->name, NULL)))
{
/* realpath will fail if the file doesn't exist, but
dnsmasq copes with missing files, so fall back
and assume that symlinks are not in use in that case. */
if (errno == ENOENT)
path = res->name;
else
die(_("cannot cannonicalise resolv-file %s: %s"), res->name, EC_MISC);
}
if ((d = strrchr(path, '/')))
{
*d = 0; /* make path just directory */
res->wd = inotify_add_watch(daemon->inotifyfd, path, IN_CLOSE_WRITE | IN_MOVED_TO);
res->file = d+1; /* pointer to filename */
*d = '/';
if (res->wd == -1 && errno == ENOENT)
die(_("directory %s for resolv-file is missing, cannot poll"), res->name, EC_MISC);
if (res->wd == -1)
die(_("failed to create inotify for %s: %s"), res->name, EC_MISC);
}
}
}
int inotify_check(void)
{
int hit = 0;
while (1)
{
int rc;
char *p;
struct resolvc *res;
struct inotify_event *in;
while ((rc = read(daemon->inotifyfd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);
if (rc <= 0)
break;
for (p = inotify_buffer; rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event); p += sizeof(struct inotify_event) + in->len)
{
in = (struct inotify_event*)p;
for (res = daemon->resolv_files; res; res = res->next)
if (res->wd == in->wd && in->len != 0 && strcmp(res->file, in->name) == 0)
hit = 1;
}
}
return hit;
}
#endif
+2 -1
View File
@@ -208,7 +208,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct in_addr netmask, addr, broadcast;
char *label = NULL;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
broadcast.s_addr = 0;
+8 -8
View File
@@ -16,10 +16,6 @@
#include "dnsmasq.h"
#ifndef IN6_IS_ADDR_ULA
#define IN6_IS_ADDR_ULA(a) ((((__const uint32_t *) (a))[0] & htonl (0xfe00000)) == htonl (0xfc000000))
#endif
#ifdef HAVE_LINUX_NETWORK
int indextoname(int fd, int index, char *name)
@@ -240,7 +236,7 @@ struct iface_param {
};
static int iface_allowed(struct iface_param *param, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int dad)
union mysockaddr *addr, struct in_addr netmask, int prefixlen, int iface_flags)
{
struct irec *iface;
int mtu = 0, loopback;
@@ -392,6 +388,10 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
{
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->flags = ADDRLIST_IPV6;
/* Privacy addresses and addresses still undergoing DAD and deprecated addresses
don't appear in forward queries, but will in reverse ones. */
if (!(iface_flags & IFACE_PERMANENT) || (iface_flags & (IFACE_DEPRECATED | IFACE_TENTATIVE)))
al->flags |= ADDRLIST_REVONLY;
}
#endif
}
@@ -403,7 +403,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, addr))
{
iface->dad = dad;
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
iface->found = 1; /* for garbage collection */
return 1;
}
@@ -478,7 +478,7 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
iface->dhcp_ok = dhcp_ok;
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
iface->found = 1;
iface->done = iface->multicast_done = iface->warned = 0;
iface->index = if_index;
@@ -523,7 +523,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
else
addr.in6.sin6_scope_id = 0;
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, !!(flags & IFACE_TENTATIVE));
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, prefix, flags);
}
#endif
+39 -17
View File
@@ -1474,22 +1474,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
for (arg = comma; arg; arg = comma)
{
comma = split(arg);
li = opt_malloc(sizeof(struct list));
if (*arg == '*')
if (strlen(arg) != 0)
{
li->next = match_suffix;
match_suffix = li;
/* Have to copy: buffer is overwritten */
li->suffix = opt_string_alloc(arg+1);
li = opt_malloc(sizeof(struct list));
if (*arg == '*')
{
li->next = match_suffix;
match_suffix = li;
/* Have to copy: buffer is overwritten */
li->suffix = opt_string_alloc(arg+1);
}
else
{
li->next = ignore_suffix;
ignore_suffix = li;
/* Have to copy: buffer is overwritten */
li->suffix = opt_string_alloc(arg);
}
}
else
{
li->next = ignore_suffix;
ignore_suffix = li;
/* Have to copy: buffer is overwritten */
li->suffix = opt_string_alloc(arg);
}
};
}
if (!(dir_stream = opendir(directory)))
die(_("cannot access directory %s: %s"), directory, EC_FILE);
@@ -1555,7 +1558,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
free(ignore_suffix->suffix);
free(ignore_suffix);
}
for(; match_suffix; match_suffix = li)
{
li = match_suffix->next;
free(match_suffix->suffix);
free(match_suffix);
}
break;
}
@@ -1933,10 +1941,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.in-addr.arpa/ */
struct server *serv = add_rev4(new->start, msize);
serv->flags |= SERV_NO_ADDR;
/* local=/<domain>/ */
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
serv->next = daemon->servers;
daemon->servers = serv;
}
}
}
@@ -1970,10 +1985,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */
struct server *serv = add_rev6(&new->start6, msize);
serv->flags |= SERV_NO_ADDR;
/* local=/<domain>/ */
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
serv->next = daemon->servers;
daemon->servers = serv;
}
}
}
-26
View File
@@ -649,32 +649,6 @@ static int add_prefixes(struct in6_addr *local, int prefix,
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
/* Send Route Information option (RFC4191, 2.3) */
put_opt6_char(ICMP6_OPT_RT_INFO);
/* Length in units of 8 octets will be 1 (header) +
* 0, 1 or 2 (0...128 bits / 64 bit per unit) */
if (0 == prefix)
put_opt6_char(1);
else if (prefix < 65)
put_opt6_char(2);
else
put_opt6_char(3);
put_opt6_char(prefix);
/* Same priority and advertised prefix */
put_opt6_char(param->prio);
/* "valid lifetime" seems more reasonable than "preferred" */
put_opt6_long(valid);
/* Actual prefix, only necessary part
* Don't append any data in case of prefix length == 0 */
if (0 != prefix)
{
if (prefix < 65)
put_opt6((void *)local, 8);
else
put_opt6((void *)local, 16);
}
}
}
}
+16 -8
View File
@@ -1246,7 +1246,12 @@ int check_for_local_domain(char *name, time_t now)
struct ptr_record *ptr;
struct naptr *naptr;
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR)) &&
/* Note: the call to cache_find_by_name is intended to find any record which matches
ie A, AAAA, CNAME, DS. Because RRSIG records are marked by setting both F_DS and F_DNSKEY,
cache_find_by name ordinarily only returns records with an exact match on those bits (ie
for the call below, only DS records). The F_NSIGMATCH bit changes this behaviour */
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME | F_DS | F_NO_RR | F_NSIGMATCH)) &&
(crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)))
return 1;
@@ -1918,14 +1923,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
{
ans = 1;
if (!dryrun)
{
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
#ifdef HAVE_IPV6
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == type)
#endif
{
#ifdef HAVE_IPV6
if (addrlist->flags & ADDRLIST_REVONLY)
continue;
#endif
ans = 1;
if (!dryrun)
{
gotit = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
@@ -1934,7 +1942,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
type == T_A ? "4" : "6", &addrlist->addr))
anscount++;
}
}
}
}
if (!dryrun && !gotit)
+41 -4
View File
@@ -313,8 +313,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
else if (msg_type != DHCP6IREQ)
return 0;
/* server-id must match except for SOLICIT and CONFIRM messages */
if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ &&
/* server-id must match except for SOLICIT, CONFIRM and REBIND messages */
if (msg_type != DHCP6SOLICIT && msg_type != DHCP6CONFIRM && msg_type != DHCP6IREQ && msg_type != DHCP6REBIND &&
(!(opt = opt6_find(state->packet_options, state->end, OPTION6_SERVER_ID, 1)) ||
opt6_len(opt) != daemon->duid_len ||
memcmp(opt6_ptr(opt, 0), daemon->duid, daemon->duid_len) != 0))
@@ -328,6 +328,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
(msg_type == DHCP6REQUEST || msg_type == DHCP6RENEW || msg_type == DHCP6RELEASE || msg_type == DHCP6DECLINE))
{
*outmsgtypep = DHCP6REPLY;
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6USEMULTI);
put_opt6_string("Use multicast");
@@ -690,6 +691,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
#endif
o = build_ia(state, &t1cntr);
if (address_assigned)
address_assigned = 2;
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
@@ -780,6 +783,27 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
address_assigned = 1;
}
if (address_assigned != 1)
{
/* If the server will not assign any addresses to any IAs in a
subsequent Request from the client, the server MUST send an Advertise
message to the client that doesn't include any IA options. */
if (!state->lease_allocate)
{
save_counter(o);
continue;
}
/* If the server cannot assign any addresses to an IA in the message
from the client, the server MUST include the IA in the Reply message
with no addresses in the IA and a Status Code option in the IA
containing status code NoAddrsAvail. */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("address unavailable"));
end_opt6(o1);
}
end_ia(t1cntr, min_time, 0);
end_opt6(o);
}
@@ -805,7 +829,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("no addresses available"));
end_opt6(o1);
log6_packet(state, "DHCPADVERTISE", NULL, _("no addresses available"));
log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
}
break;
@@ -861,7 +885,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
{
/* Static range, not configured. */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6UNSPEC);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string(_("address unavailable"));
end_opt6(o1);
}
@@ -1039,6 +1063,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
case DHCP6CONFIRM:
{
int good_addr = 0;
/* set reply message type */
*outmsgtypep = DHCP6REPLY;
@@ -1063,9 +1089,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
return 1;
}
good_addr = 1;
log6_quiet(state, "DHCPREPLY", req_addr, state->hostname);
}
}
/* No addresses, no reply: RFC 3315 18.2.2 */
if (!good_addr)
return 0;
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS );
@@ -1232,6 +1263,12 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
}
}
/* We must anwser with 'success' in global section anyway */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string(_("success"));
end_opt6(o1);
break;
}
+5 -1
View File
@@ -20,6 +20,10 @@
#if defined(HAVE_IPSET) && defined(HAVE_BSD_NETWORK)
#ifndef __FreeBSD__
#include <bsd/string.h>
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
@@ -136,7 +140,7 @@ int add_to_ipset(const char *setname, const struct all_addr *ipaddr,
return -1;
}
if (rc = pfr_add_tables(&table, 1, &n, 0))
if ((rc = pfr_add_tables(&table, 1, &n, 0)))
{
my_syslog(LOG_WARNING, _("warning: pfr_add_tables: %s(%d)"),
pfr_strerror(errno),rc);
+13 -3
View File
@@ -570,18 +570,28 @@ void bump_maxfd(int fd, int *max)
int retry_send(void)
{
struct timespec waiter;
/* Linux kernels can return EAGAIN in perpetuity when calling
sendmsg() and the relevant interface has gone. Here we loop
retrying in EAGAIN for 1 second max, to avoid this hanging
dnsmasq. */
static int retries = 0;
struct timespec waiter;
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
waiter.tv_sec = 0;
waiter.tv_nsec = 10000;
nanosleep(&waiter, NULL);
return 1;
if (retries++ < 1000)
return 1;
}
retries = 0;
if (errno == EINTR)
return 1;
return 0;
}