Compare commits
22 Commits
v2.81
...
v2.83test1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45903b7776 | ||
|
|
f60fea1fb0 | ||
|
|
4d85e409cd | ||
|
|
2bd02d2f59 | ||
|
|
7e194a0a7d | ||
|
|
9beb4d9ea2 | ||
|
|
ab5ebe9507 | ||
|
|
837e8f4eb5 | ||
|
|
e2cb655958 | ||
|
|
8270648da1 | ||
|
|
619000a3c5 | ||
|
|
1c1b925052 | ||
|
|
49bdf1ead9 | ||
|
|
60a3ae19c5 | ||
|
|
951a22165c | ||
|
|
51cdd1a227 | ||
|
|
66adee85be | ||
|
|
4890bcdea2 | ||
|
|
8baf583a3f | ||
|
|
913fa15fb1 | ||
|
|
00fe2f49e0 | ||
|
|
ec2067df75 |
29
CHANGELOG
29
CHANGELOG
@@ -1,6 +1,33 @@
|
||||
version 2.83
|
||||
Fix a remote buffer overflow problem in the DNSSEC code. Any
|
||||
dnsmasq with DNSSEC compiled in and enabled is vulnerable to this,
|
||||
referenced by CERT VU#434904.
|
||||
|
||||
|
||||
version 2.82
|
||||
Improve behaviour in the face of network interfaces which come
|
||||
and go and change index. Thanks to Petr Mensik for the patch.
|
||||
|
||||
Convert hard startup failure on NETLINK_NO_ENOBUFS under qemu-user
|
||||
to a warning.
|
||||
|
||||
Allow IPv6 addresses ofthe form [::ffff:1.2.3.4] in --dhcp-option.
|
||||
|
||||
Fix crash under heavy TCP connection load introduced in 2.81.
|
||||
Thanks to Frank for good work chasing this down.
|
||||
|
||||
Change default lease time for DHCPv6 to one day.
|
||||
|
||||
Alter calculation of preferred and valid times in router
|
||||
advertisements, so that these do not have a floor applied
|
||||
of the lease time in the dhcp-range if this is not explicitly
|
||||
specified and is merely the default.
|
||||
Thanks to Martin-Éric Racine for suggestions on this.
|
||||
|
||||
|
||||
version 2.81
|
||||
Improve cache behaviour for TCP connections. For ease of
|
||||
implementaion, dnsmasq has always forked a new process to handle
|
||||
implementation, dnsmasq has always forked a new process to handle
|
||||
each incoming TCP connection. A side-effect of this is that
|
||||
any DNS queries answered from TCP connections are not cached:
|
||||
when TCP connections were rare, this was not a problem.
|
||||
|
||||
24
debian/changelog
vendored
24
debian/changelog
vendored
@@ -1,3 +1,27 @@
|
||||
dnsmasq (2.82-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 22:22:41 +0000
|
||||
|
||||
dnsmasq (2.81-4) unstable; urgency=low
|
||||
|
||||
* Remove runit support when building for Ubuntu. (closes: #960401)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 21:52:44 +0000
|
||||
|
||||
dnsmasq (2.81-3) unstable; urgency=low
|
||||
|
||||
* Fixes to control file for bug 958100
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 19 Apr 2020 21:44:12 +0000
|
||||
|
||||
dnsmasq (2.81-2) unstable; urgency=low
|
||||
|
||||
* Fix FTBFS on kFreeBSD. (closes: #958100)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 18 Apr 2020 18:34:15 +0000
|
||||
|
||||
dnsmasq (2.81-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
5
debian/control
vendored
5
debian/control
vendored
@@ -3,8 +3,9 @@ Section: net
|
||||
Priority: optional
|
||||
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
|
||||
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
|
||||
nettle-dev (>=2.4-3), libbsd-dev [!linux-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10)
|
||||
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
|
||||
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
|
||||
pkg-config
|
||||
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
|
||||
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
|
||||
|
||||
27
debian/rules
vendored
27
debian/rules
vendored
@@ -98,9 +98,10 @@ ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
|
||||
DEB_COPTS += -DHAVE_DNSSEC
|
||||
endif
|
||||
|
||||
ifneq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq ($(DEB_HOST_ARCH_OS),kfreebsd)
|
||||
# For strlcpy in FreeBSD
|
||||
LDFLAGS += -lbsd
|
||||
LIBS += $(shell ${PKG_CONFIG} --libs libbsd-overlay)
|
||||
CFLAGS += $(shell ${PKG_CONFIG} --cflags libbsd-overlay)
|
||||
endif
|
||||
|
||||
define build_tree
|
||||
@@ -169,16 +170,20 @@ binary-indep: checkroot
|
||||
-d debian/trees/daemon/etc/resolvconf/update.d \
|
||||
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||
-d debian/trees/daemon/usr/share/dnsmasq \
|
||||
-d debian/trees/daemon/usr/share/doc/dnsmasq \
|
||||
-d debian/trees/daemon/etc/default \
|
||||
-d debian/trees/daemon/lib/systemd/system \
|
||||
-d debian/trees/daemon/usr/lib/tmpfiles.d \
|
||||
-d debian/trees/daemon/etc/insserv.conf.d
|
||||
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
|
||||
install -m 755 debian/postinst debian/postrm debian/prerm debian/trees/daemon/DEBIAN
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm
|
||||
if ! dpkg-vendor --derives-from Ubuntu; then \
|
||||
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
|
||||
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
|
||||
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst; \
|
||||
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm; \
|
||||
cd debian/trees/daemon && find etc/sv -type f -printf '/%p\n' >>DEBIAN/conffiles; \
|
||||
fi
|
||||
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
|
||||
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
|
||||
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||
@@ -190,7 +195,9 @@ binary-indep: checkroot
|
||||
install -m 644 debian/systemd@.service debian/trees/daemon/lib/systemd/system/dnsmasq@.service
|
||||
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
|
||||
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
|
||||
ln -s $(package) debian/trees/daemon/usr/share/doc/dnsmasq
|
||||
install -m 644 debian/copyright debian/trees/daemon/usr/share/doc/dnsmasq/copyright
|
||||
install -m 644 debian/changelog debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
gzip -9n debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
|
||||
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
|
||||
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/dnsmasq.substvars -pdnsmasq -Pdebian/trees/daemon
|
||||
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
|
||||
@@ -200,7 +207,7 @@ binary-indep: checkroot
|
||||
|
||||
binary-arch: checkroot
|
||||
$(call build_tree,debian/trees/base)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/base)
|
||||
else
|
||||
@@ -219,7 +226,7 @@ endif
|
||||
dpkg --build debian/trees/base ..
|
||||
|
||||
$(call build_tree,debian/trees/lua-base)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
$(call add_docs,debian/trees/lua-base)
|
||||
else
|
||||
@@ -249,7 +256,7 @@ ifeq ($(DEB_HOST_ARCH_OS),linux)
|
||||
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
|
||||
install -m 755 -d debian/trees/utils/usr/share/man/man1
|
||||
endif
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG)
|
||||
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
|
||||
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
|
||||
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
|
||||
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
|
||||
|
||||
@@ -428,7 +428,7 @@ Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||
or domain parts, to upstream nameservers. If the name is not known
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source-ip>|<interface>[#<port>]]
|
||||
.B \-S, --local, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>]][@<source-ip>|<interface>[#<port>]]
|
||||
Specify IP address of upstream servers directly. Setting this flag does
|
||||
not suppress reading of /etc/resolv.conf, use \fB--no-resolv\fP to do that. If one or more
|
||||
optional domains are given, that server is used only for those domains
|
||||
@@ -861,7 +861,7 @@ in
|
||||
options. If the lease time is given, then leases
|
||||
will be given for that length of time. The lease time is in seconds,
|
||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
||||
the default lease time is one hour. The
|
||||
the default lease time is one hour for IPv4 and one day for IPv6. The
|
||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||
lease or router advertisement to zero, which causes clients to use
|
||||
|
||||
21
src/cache.c
21
src/cache.c
@@ -472,16 +472,29 @@ void cache_start_insert(void)
|
||||
struct crec *cache_insert(char *name, union all_addr *addr, unsigned short class,
|
||||
time_t now, unsigned long ttl, unsigned int flags)
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
if (flags & (F_IPV4 | F_IPV6 | F_CNAME | F_SRV))
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (flags & (F_DNSKEY | F_DS))
|
||||
{
|
||||
/* The DNSSEC validation process works by getting needed records into the
|
||||
cache, then retrying the validation until they are all in place.
|
||||
This can be messed up by very short TTLs, and _really_ messed up by
|
||||
zero TTLs, so we force the TTL to be at least long enough to do a validation.
|
||||
Ideally, we should use some kind of reference counting so that records are
|
||||
locked until the validation that asked for them is complete, but this
|
||||
is much easier, and just as effective. */
|
||||
if (ttl < DNSSEC_MIN_TTL)
|
||||
ttl = DNSSEC_MIN_TTL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Don't log DNSSEC records here, done elsewhere */
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
/* Don't mess with TTL for DNSSEC records. */
|
||||
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
|
||||
ttl = daemon->max_cache_ttl;
|
||||
if (daemon->min_cache_ttl != 0 && daemon->min_cache_ttl > ttl)
|
||||
ttl = daemon->min_cache_ttl;
|
||||
}
|
||||
}
|
||||
|
||||
return really_insert(name, addr, class, now, ttl, flags);
|
||||
}
|
||||
|
||||
@@ -40,9 +40,11 @@
|
||||
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
|
||||
#define SMALLDNAME 50 /* most domain names are smaller than this */
|
||||
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
|
||||
#define DNSSEC_MIN_TTL 60 /* DNSKEY and DS records in cache last at least this long */
|
||||
#define HOSTSFILE "/etc/hosts"
|
||||
#define ETHERSFILE "/etc/ethers"
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define DEFLEASE 3600 /* default DHCPv4 lease time, one hour */
|
||||
#define DEFLEASE6 (3600*24) /* default lease time for DHCPv6. One day. */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||
|
||||
@@ -237,7 +237,7 @@ static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (serv->flags & SERV_LOOP)
|
||||
{
|
||||
prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void dhcp_common_init(void)
|
||||
|
||||
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
{
|
||||
ssize_t sz;
|
||||
ssize_t sz, new_sz;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -65,9 +65,18 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||
}
|
||||
}
|
||||
|
||||
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||
|
||||
/* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway.
|
||||
If that happens we get EAGAIN here because the socket is non-blocking.
|
||||
Use the result of the original testing recvmsg as long as the buffer
|
||||
was big enough. There's a small race here that may lose the odd packet,
|
||||
but it's UDP anyway. */
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||
if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
new_sz = sz;
|
||||
|
||||
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
|
||||
}
|
||||
|
||||
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
|
||||
|
||||
@@ -58,6 +58,7 @@ int main (int argc, char **argv)
|
||||
char *bound_device = NULL;
|
||||
int did_bind = 0;
|
||||
struct server *serv;
|
||||
char *netlink_warn;
|
||||
#endif
|
||||
#if defined(HAVE_DHCP) || defined(HAVE_DHCP6)
|
||||
struct dhcp_context *context;
|
||||
@@ -327,7 +328,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
netlink_init();
|
||||
netlink_warn = netlink_init();
|
||||
#elif defined(HAVE_BSD_NETWORK)
|
||||
route_init();
|
||||
#endif
|
||||
@@ -946,6 +947,9 @@ int main (int argc, char **argv)
|
||||
# ifdef HAVE_LINUX_NETWORK
|
||||
if (did_bind)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device);
|
||||
|
||||
if (netlink_warn)
|
||||
my_syslog(LOG_WARNING, netlink_warn);
|
||||
# endif
|
||||
|
||||
/* after dhcp_construct_contexts */
|
||||
@@ -1820,7 +1824,8 @@ static void check_dns_listeners(time_t now)
|
||||
addr.addr4 = tcp_addr.in.sin_addr;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
if (iface->index == if_index &&
|
||||
iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
@@ -1859,31 +1864,30 @@ static void check_dns_listeners(time_t now)
|
||||
else
|
||||
{
|
||||
int i;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
|
||||
unsigned char a;
|
||||
read_write(pipefd[0], &a, 1, 1);
|
||||
#endif
|
||||
|
||||
for (i = 0; i < MAX_PROCS; i++)
|
||||
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
|
||||
{
|
||||
char a;
|
||||
(void)a; /* suppress potential unused warning */
|
||||
|
||||
daemon->tcp_pids[i] = p;
|
||||
daemon->tcp_pipes[i] = pipefd[0];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* The child process inherits the netlink socket,
|
||||
which it never uses, but when the parent (us)
|
||||
uses it in the future, the answer may go to the
|
||||
child, resulting in the parent blocking
|
||||
forever awaiting the result. To avoid this
|
||||
the child closes the netlink socket, but there's
|
||||
a nasty race, since the parent may use netlink
|
||||
before the child has done the close.
|
||||
|
||||
To avoid this, the parent blocks here until a
|
||||
single byte comes back up the pipe, which
|
||||
is sent by the child after it has closed the
|
||||
netlink socket. */
|
||||
retry_send(read(pipefd[0], &a, 1));
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1915,16 +1919,16 @@ static void check_dns_listeners(time_t now)
|
||||
terminate the process. */
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
char a = 0;
|
||||
(void)a; /* suppress potential unused warning */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re: netlink socket. */
|
||||
unsigned char a = 0;
|
||||
|
||||
close(daemon->netlinkfd);
|
||||
read_write(pipefd[1], &a, 1, 0);
|
||||
#endif
|
||||
alarm(CHILD_LIFETIME);
|
||||
close(pipefd[0]); /* close read end in child. */
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re netlink socket. */
|
||||
close(daemon->netlinkfd);
|
||||
retry_send(write(pipefd[1], &a, 1));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* start with no upstream connections. */
|
||||
@@ -1951,8 +1955,10 @@ static void check_dns_listeners(time_t now)
|
||||
shutdown(s->tcpfd, SHUT_RDWR);
|
||||
close(s->tcpfd);
|
||||
}
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
close(daemon->pipe_to_parent);
|
||||
flush_log();
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
@@ -572,7 +572,8 @@ struct irec {
|
||||
};
|
||||
|
||||
struct listener {
|
||||
int fd, tcpfd, tftpfd, family;
|
||||
int fd, tcpfd, tftpfd, used;
|
||||
union mysockaddr addr;
|
||||
struct irec *iface; /* only sometimes valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
@@ -941,6 +942,7 @@ struct shared_network {
|
||||
#define CONTEXT_OLD (1u<<16)
|
||||
#define CONTEXT_V6 (1u<<17)
|
||||
#define CONTEXT_RA_OFF_LINK (1u<<18)
|
||||
#define CONTEXT_SETLEASE (1u<<19)
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -1450,7 +1452,7 @@ void clear_cache_and_reload(time_t now);
|
||||
|
||||
/* netlink.c */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void netlink_init(void);
|
||||
char *netlink_init(void);
|
||||
void netlink_multicast(void);
|
||||
#endif
|
||||
|
||||
|
||||
273
src/dnssec.c
273
src/dnssec.c
@@ -223,138 +223,147 @@ static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
/* 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, int bufflen,
|
||||
unsigned char **p, u16 **desc)
|
||||
/* Return bytes of canonicalised rrdata one by one.
|
||||
Init state->ip with the RR, and state->end with the end of same.
|
||||
Init state->op to NULL.
|
||||
Init state->desc to RR descriptor.
|
||||
Init state->buff with a MAXDNAME * 2 buffer.
|
||||
|
||||
After each call which returns 1, state->op points to the next byte of data.
|
||||
On returning 0, the end has been reached.
|
||||
*/
|
||||
struct rdata_state {
|
||||
u16 *desc;
|
||||
size_t c;
|
||||
unsigned char *end, *ip, *op;
|
||||
char *buff;
|
||||
};
|
||||
|
||||
static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state *state)
|
||||
{
|
||||
int d = **desc;
|
||||
int d;
|
||||
|
||||
/* No more data needs mangling */
|
||||
if (d == (u16)-1)
|
||||
if (state->op && state->c != 1)
|
||||
{
|
||||
/* 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;
|
||||
state->op++;
|
||||
state->c--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*desc)++;
|
||||
|
||||
if (d == 0 && extract_name(header, plen, p, buff, 1, 0))
|
||||
/* domain-name, canonicalise */
|
||||
return to_wire(buff);
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((end - *p) < d)
|
||||
d = end - *p;
|
||||
|
||||
while (1)
|
||||
{
|
||||
d = *(state->desc);
|
||||
|
||||
if (d != 0)
|
||||
if (d == (u16)-1)
|
||||
{
|
||||
memcpy(buff, *p, d);
|
||||
*p += d;
|
||||
/* all the bytes to the end. */
|
||||
if ((state->c = state->end - state->ip) != 0)
|
||||
{
|
||||
state->op = state->ip;
|
||||
state->ip = state->end;;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->desc++;
|
||||
|
||||
if (d == (u16)0)
|
||||
{
|
||||
/* domain-name, canonicalise */
|
||||
int len;
|
||||
|
||||
if (!extract_name(header, plen, &state->ip, state->buff, 1, 0) ||
|
||||
(len = to_wire(state->buff)) == 0)
|
||||
continue;
|
||||
|
||||
state->c = len;
|
||||
state->op = (unsigned char *)state->buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* plain data preceding a domain-name, don't run off the end of the data */
|
||||
if ((state->end - state->ip) < d)
|
||||
d = state->end - state->ip;
|
||||
|
||||
if (d == 0)
|
||||
continue;
|
||||
|
||||
state->op = state->ip;
|
||||
state->c = d;
|
||||
state->ip += d;
|
||||
}
|
||||
}
|
||||
|
||||
return d;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Bubble sort the RRset into the canonical order.
|
||||
Note that the byte-streams from two RRs may get unsynced: consider
|
||||
RRs which have two domain-names at the start and then other data.
|
||||
The domain-names may have different lengths in each RR, but sort equal
|
||||
|
||||
------------
|
||||
|abcde|fghi|
|
||||
------------
|
||||
|abcd|efghi|
|
||||
------------
|
||||
|
||||
leaving the following bytes as deciding the order. Hence the nasty left1 and left2 variables.
|
||||
*/
|
||||
/* Bubble sort the RRset into the canonical order. */
|
||||
|
||||
static int sort_rrset(struct dns_header *header, size_t plen, u16 *rr_desc, int rrsetidx,
|
||||
unsigned char **rrset, char *buff1, char *buff2)
|
||||
{
|
||||
int swap, quit, i, j;
|
||||
int swap, i, j;
|
||||
|
||||
do
|
||||
{
|
||||
for (swap = 0, i = 0; i < rrsetidx-1; i++)
|
||||
{
|
||||
int rdlen1, rdlen2, left1, left2, len1, len2, len, rc;
|
||||
u16 *dp1, *dp2;
|
||||
unsigned char *end1, *end2;
|
||||
int rdlen1, rdlen2;
|
||||
struct rdata_state state1, state2;
|
||||
|
||||
/* Note that these have been determined to be OK previously,
|
||||
so we don't need to check for NULL return here. */
|
||||
unsigned char *p1 = skip_name(rrset[i], header, plen, 10);
|
||||
unsigned char *p2 = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.ip = skip_name(rrset[i], header, plen, 10);
|
||||
state2.ip = skip_name(rrset[i+1], header, plen, 10);
|
||||
state1.op = state2.op = NULL;
|
||||
state1.buff = buff1;
|
||||
state2.buff = buff2;
|
||||
state1.desc = state2.desc = rr_desc;
|
||||
|
||||
p1 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, p1);
|
||||
end1 = p1 + rdlen1;
|
||||
state1.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen1, state1.ip);
|
||||
if (!CHECK_LEN(header, state1.ip, plen, rdlen1))
|
||||
return rrsetidx; /* short packet */
|
||||
state1.end = state1.ip + rdlen1;
|
||||
|
||||
p2 += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, p2);
|
||||
end2 = p2 + rdlen2;
|
||||
|
||||
dp1 = dp2 = rr_desc;
|
||||
|
||||
for (quit = 0, left1 = 0, left2 = 0, len1 = 0, len2 = 0; !quit;)
|
||||
state2.ip += 8; /* skip class, type, ttl */
|
||||
GETSHORT(rdlen2, state2.ip);
|
||||
if (!CHECK_LEN(header, state2.ip, plen, rdlen2))
|
||||
return rrsetidx; /* short packet */
|
||||
state2.end = state2.ip + rdlen2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (left1 != 0)
|
||||
memmove(buff1, buff1 + len1 - left1, left1);
|
||||
int ok1, ok2;
|
||||
|
||||
if ((len1 = get_rdata(header, plen, end1, buff1 + left1, (MAXDNAME * 2) - left1, &p1, &dp1)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len1 = end1 - p1;
|
||||
memcpy(buff1 + left1, p1, len1);
|
||||
}
|
||||
len1 += left1;
|
||||
|
||||
if (left2 != 0)
|
||||
memmove(buff2, buff2 + len2 - left2, left2);
|
||||
|
||||
if ((len2 = get_rdata(header, plen, end2, buff2 + left2, (MAXDNAME *2) - left2, &p2, &dp2)) == 0)
|
||||
{
|
||||
quit = 1;
|
||||
len2 = end2 - p2;
|
||||
memcpy(buff2 + left2, p2, len2);
|
||||
}
|
||||
len2 += left2;
|
||||
|
||||
if (len1 > len2)
|
||||
left1 = len1 - len2, left2 = 0, len = len2;
|
||||
else
|
||||
left2 = len2 - len1, left1 = 0, len = len1;
|
||||
|
||||
rc = (len == 0) ? 0 : memcmp(buff1, buff2, len);
|
||||
|
||||
if (rc > 0 || (rc == 0 && quit && len1 > len2))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = quit = 1;
|
||||
}
|
||||
else if (rc == 0 && quit && len1 == len2)
|
||||
ok1 = get_rdata(header, plen, &state1);
|
||||
ok2 = get_rdata(header, plen, &state2);
|
||||
|
||||
if (!ok1 && !ok2)
|
||||
{
|
||||
/* Two RRs are equal, remove one copy. RFC 4034, para 6.3 */
|
||||
for (j = i+1; j < rrsetidx-1; j++)
|
||||
rrset[j] = rrset[j+1];
|
||||
rrsetidx--;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
else if (rc < 0)
|
||||
quit = 1;
|
||||
else if (ok1 && (!ok2 || *state1.op > *state2.op))
|
||||
{
|
||||
unsigned char *tmp = rrset[i+1];
|
||||
rrset[i+1] = rrset[i];
|
||||
rrset[i] = tmp;
|
||||
swap = 1;
|
||||
break;
|
||||
}
|
||||
else if (ok2 && (!ok1 || *state2.op > *state1.op))
|
||||
break;
|
||||
|
||||
/* arrive here when bytes are equal, go round the loop again
|
||||
and compare the next ones. */
|
||||
}
|
||||
}
|
||||
} while (swap);
|
||||
@@ -569,15 +578,18 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
wire_len = to_wire(keyname);
|
||||
hash->update(ctx, (unsigned int)wire_len, (unsigned char*)keyname);
|
||||
from_wire(keyname);
|
||||
|
||||
#define RRBUFLEN 300 /* Most RRs are smaller than this. */
|
||||
|
||||
for (i = 0; i < rrsetidx; ++i)
|
||||
{
|
||||
int seg;
|
||||
unsigned char *end, *cp;
|
||||
u16 len, *dp;
|
||||
int j;
|
||||
struct rdata_state state;
|
||||
u16 len;
|
||||
unsigned char rrbuf[RRBUFLEN];
|
||||
|
||||
p = rrset[i];
|
||||
|
||||
|
||||
if (!extract_name(header, plen, &p, name, 1, 10))
|
||||
return STAT_BOGUS;
|
||||
|
||||
@@ -586,12 +598,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
{
|
||||
int k;
|
||||
for (k = name_labels - labels; k != 0; k--)
|
||||
for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
while (*name_start != '.' && *name_start != 0)
|
||||
name_start++;
|
||||
if (k != 1 && *name_start == '.')
|
||||
if (j != 1 && *name_start == '.')
|
||||
name_start++;
|
||||
}
|
||||
|
||||
@@ -612,24 +623,44 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
if (!CHECK_LEN(header, p, plen, rdlen))
|
||||
return STAT_BOGUS;
|
||||
|
||||
end = p + rdlen;
|
||||
/* canonicalise rdata and calculate length of same, use
|
||||
name buffer as workspace for get_rdata. */
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
state.buff = name;
|
||||
state.end = p + rdlen;
|
||||
|
||||
/* 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 * 2, &cp, &dp)) != 0; len += seg);
|
||||
len += end - cp;
|
||||
len = htons(len);
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
if (j < RRBUFLEN)
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
len = htons((u16)j);
|
||||
hash->update(ctx, 2, (unsigned char *)&len);
|
||||
|
||||
/* If the RR is shorter than RRBUFLEN (most of them, in practice)
|
||||
then we can just digest it now. If it exceeds RRBUFLEN we have to
|
||||
go back to the start and do it in chunks. */
|
||||
if (j >= RRBUFLEN)
|
||||
{
|
||||
state.ip = p;
|
||||
state.op = NULL;
|
||||
state.desc = rr_desc;
|
||||
|
||||
for (j = 0; get_rdata(header, plen, &state); j++)
|
||||
{
|
||||
rrbuf[j] = *state.op;
|
||||
|
||||
if (j == RRBUFLEN - 1)
|
||||
{
|
||||
hash->update(ctx, RRBUFLEN, rrbuf);
|
||||
j = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now canonicalise again and digest. */
|
||||
cp = p;
|
||||
dp = rr_desc;
|
||||
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);
|
||||
if (j != 0)
|
||||
hash->update(ctx, j, rrbuf);
|
||||
}
|
||||
|
||||
hash->digest(ctx, hash->digest_size, digest);
|
||||
|
||||
@@ -676,7 +676,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
if (!(header->hb4 & HB4_RA) && rcode == NOERROR &&
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
(void)prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!option_bool(OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
@@ -960,7 +960,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
{
|
||||
forward->sentto->edns_pktsz = SAFE_PKTSZ;
|
||||
forward->sentto->pktsz_reduced = now;
|
||||
prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&forward->sentto->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_WARNING, _("reducing DNS packet size for nameserver %s to %d"), daemon->addrbuff, SAFE_PKTSZ);
|
||||
}
|
||||
|
||||
@@ -1284,8 +1284,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||
#endif
|
||||
} control_u;
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dst = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
int check_dst = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
@@ -1297,7 +1298,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
auth_dns = listen->iface->dns_auth;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
dst_addr_4 = dst_addr.addr4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -1327,9 +1328,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
information disclosure. */
|
||||
memset(daemon->packet + n, 0, daemon->edns_pktsz - n);
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
source_addr.sa.sa_family = family;
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
/* Source-port == 0 is an error, we can't send back to that.
|
||||
http://www.ietf.org/mail-archive/web/dnsop/current/msg11441.html */
|
||||
@@ -1349,7 +1350,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
struct addrlist *addr;
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
if ((addr->flags & ADDRLIST_IPV6) &&
|
||||
@@ -1387,7 +1388,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
@@ -1400,7 +1401,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
@@ -1425,7 +1426,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
@@ -1446,16 +1447,16 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
if (!iface_check(family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, listen->family, &dst_addr))
|
||||
if (!loopback_exception(listen->fd, family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, family, &dst_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
if (family == AF_INET && option_bool(OPT_LOCALISE))
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
@@ -1500,7 +1501,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#endif
|
||||
char *types = querystr(auth_dns ? "auth" : "query", type);
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||
(union all_addr *)&source_addr.in.sin_addr, types);
|
||||
else
|
||||
|
||||
@@ -49,7 +49,7 @@ static u32 netlink_pid;
|
||||
|
||||
static void nl_async(struct nlmsghdr *h);
|
||||
|
||||
void netlink_init(void)
|
||||
char *netlink_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t slen = sizeof(addr);
|
||||
@@ -82,16 +82,21 @@ void netlink_init(void)
|
||||
}
|
||||
|
||||
if (daemon->netlinkfd == -1 ||
|
||||
(daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
|
||||
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1) ||
|
||||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == -1)
|
||||
die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
|
||||
|
||||
|
||||
/* save pid assigned by bind() and retrieved by getsockname() */
|
||||
netlink_pid = addr.nl_pid;
|
||||
|
||||
iov.iov_len = 100;
|
||||
iov.iov_base = safe_malloc(iov.iov_len);
|
||||
|
||||
if (daemon->kernel_version >= KERNEL_VERSION(2,6,30) &&
|
||||
setsockopt(daemon->netlinkfd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(opt)) == -1)
|
||||
return _("warning: failed to set NETLINK_NO_ENOBUFS on netlink socket");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t netlink_recv(void)
|
||||
|
||||
156
src/network.c
156
src/network.c
@@ -388,10 +388,11 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
/* check whether the interface IP has been added already
|
||||
we call this routine multiple times. */
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
if (sockaddr_isequal(&iface->addr, addr) && iface->index == if_index)
|
||||
{
|
||||
iface->dad = !!(iface_flags & IFACE_TENTATIVE);
|
||||
iface->found = 1; /* for garbage collection */
|
||||
iface->netmask = netmask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -532,7 +533,82 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, prefix, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clean old interfaces no longer found.
|
||||
*/
|
||||
static void clean_interfaces()
|
||||
{
|
||||
struct irec *iface;
|
||||
struct irec **up = &daemon->interfaces;
|
||||
|
||||
for (iface = *up; iface; iface = *up)
|
||||
{
|
||||
if (!iface->found && !iface->done)
|
||||
{
|
||||
*up = iface->next;
|
||||
free(iface->name);
|
||||
free(iface);
|
||||
}
|
||||
else
|
||||
{
|
||||
up = &iface->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Release listener if no other interface needs it.
|
||||
*
|
||||
* @return 1 if released, 0 if still required
|
||||
*/
|
||||
static int release_listener(struct listener *l)
|
||||
{
|
||||
if (l->used > 1)
|
||||
{
|
||||
struct irec *iface;
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->done && sockaddr_isequal(&l->addr, &iface->addr))
|
||||
{
|
||||
if (iface->found)
|
||||
{
|
||||
/* update listener to point to active interface instead */
|
||||
if (!l->iface->found)
|
||||
l->iface = iface;
|
||||
}
|
||||
else
|
||||
{
|
||||
l->used--;
|
||||
iface->done = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Someone is still using this listener, skip its deletion */
|
||||
if (l->used > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (l->iface->done)
|
||||
{
|
||||
int port;
|
||||
|
||||
port = prettyprint_addr(&l->iface->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("stopped listening on %s(#%d): %s port %d"),
|
||||
l->iface->name, l->iface->index, daemon->addrbuff, port);
|
||||
/* In case it ever returns */
|
||||
l->iface->done = 0;
|
||||
}
|
||||
|
||||
if (l->fd != -1)
|
||||
close(l->fd);
|
||||
if (l->tcpfd != -1)
|
||||
close(l->tcpfd);
|
||||
if (l->tftpfd != -1)
|
||||
close(l->tftpfd);
|
||||
|
||||
free(l);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int enumerate_interfaces(int reset)
|
||||
{
|
||||
static struct addrlist *spare = NULL;
|
||||
@@ -630,6 +706,7 @@ int enumerate_interfaces(int reset)
|
||||
in OPT_CLEVERBIND mode, that at listener will just disappear after
|
||||
a call to enumerate_interfaces, this is checked OK on all calls. */
|
||||
struct listener *l, *tmp, **up;
|
||||
int freed = 0;
|
||||
|
||||
for (up = &daemon->listeners, l = daemon->listeners; l; l = tmp)
|
||||
{
|
||||
@@ -637,25 +714,17 @@ int enumerate_interfaces(int reset)
|
||||
|
||||
if (!l->iface || l->iface->found)
|
||||
up = &l->next;
|
||||
else
|
||||
else if (release_listener(l))
|
||||
{
|
||||
*up = l->next;
|
||||
|
||||
/* In case it ever returns */
|
||||
l->iface->done = 0;
|
||||
|
||||
if (l->fd != -1)
|
||||
close(l->fd);
|
||||
if (l->tcpfd != -1)
|
||||
close(l->tcpfd);
|
||||
if (l->tftpfd != -1)
|
||||
close(l->tftpfd);
|
||||
|
||||
free(l);
|
||||
*up = tmp;
|
||||
freed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (freed)
|
||||
clean_interfaces();
|
||||
}
|
||||
|
||||
|
||||
errno = errsave;
|
||||
spare = param.spare;
|
||||
|
||||
@@ -895,10 +964,11 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, in
|
||||
{
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->next = NULL;
|
||||
l->family = addr->sa.sa_family;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->addr = *addr;
|
||||
l->used = 1;
|
||||
l->iface = NULL;
|
||||
}
|
||||
|
||||
@@ -937,20 +1007,48 @@ void create_wildcard_listeners(void)
|
||||
daemon->listeners = l;
|
||||
}
|
||||
|
||||
static struct listener *find_listener(union mysockaddr *addr)
|
||||
{
|
||||
struct listener *l;
|
||||
for (l = daemon->listeners; l; l = l->next)
|
||||
if (sockaddr_isequal(&l->addr, addr))
|
||||
return l;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void create_bound_listeners(int dienow)
|
||||
{
|
||||
struct listener *new;
|
||||
struct irec *iface;
|
||||
struct iname *if_tmp;
|
||||
struct listener *existing;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (!iface->done && !iface->dad && iface->found &&
|
||||
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
if (!iface->done && !iface->dad && iface->found)
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
existing = find_listener(&iface->addr);
|
||||
if (existing)
|
||||
{
|
||||
iface->done = 1;
|
||||
existing->used++; /* increase usage counter */
|
||||
}
|
||||
else if ((new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
|
||||
/* Don't log the initial set of listen addresses created
|
||||
at startup, since this is happening before the logging
|
||||
system is initialised and the sign-on printed. */
|
||||
if (!dienow)
|
||||
{
|
||||
int port = prettyprint_addr(&iface->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("listening on %s(#%d): %s port %d"),
|
||||
iface->name, iface->index, daemon->addrbuff, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for --listen-address options that haven't been used because there's
|
||||
@@ -970,6 +1068,12 @@ void create_bound_listeners(int dienow)
|
||||
{
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
|
||||
if (!dienow)
|
||||
{
|
||||
int port = prettyprint_addr(&if_tmp->addr, daemon->addrbuff);
|
||||
my_syslog(LOG_DEBUG, _("listening on %s port %d"), daemon->addrbuff, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1301,7 +1405,7 @@ void pre_allocate_sfds(void)
|
||||
errno != 0 &&
|
||||
option_bool(OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
(void)prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
if (srv->interface[0] != 0)
|
||||
{
|
||||
strcat(daemon->namebuff, " ");
|
||||
|
||||
12
src/option.c
12
src/option.c
@@ -1225,7 +1225,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
is_addr6 = is_dec = is_hex = 0;
|
||||
is_dec = is_hex = 0;
|
||||
dots++;
|
||||
}
|
||||
else if (c == '-')
|
||||
@@ -2991,7 +2991,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
memset (new, 0, sizeof(*new));
|
||||
new->lease_time = DEFLEASE;
|
||||
|
||||
while(1)
|
||||
{
|
||||
@@ -3041,6 +3040,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (inet_pton(AF_INET, a[0], &new->start))
|
||||
{
|
||||
new->next = daemon->dhcp;
|
||||
new->lease_time = DEFLEASE;
|
||||
daemon->dhcp = new;
|
||||
new->end = new->start;
|
||||
if (strcmp(a[1], "static") == 0)
|
||||
@@ -3088,6 +3088,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->flags |= CONTEXT_V6;
|
||||
new->prefix = 64; /* default */
|
||||
new->end6 = new->start6;
|
||||
new->lease_time = DEFLEASE6;
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
|
||||
@@ -3187,7 +3188,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (strcmp(a[leasepos], "infinite") == 0)
|
||||
new->lease_time = 0xffffffff;
|
||||
{
|
||||
new->lease_time = 0xffffffff;
|
||||
new->flags |= CONTEXT_SETLEASE;
|
||||
}
|
||||
else if (strcmp(a[leasepos], "deprecated") == 0)
|
||||
new->flags |= CONTEXT_DEPRECATE;
|
||||
else
|
||||
@@ -3226,6 +3230,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err_free(_("bad dhcp-range"), new);
|
||||
|
||||
new->lease_time = atoi(a[leasepos]) * fac;
|
||||
new->flags |= CONTEXT_SETLEASE;
|
||||
/* Leases of a minute or less confuse
|
||||
some clients, notably Apple's */
|
||||
if (new->lease_time < 120)
|
||||
@@ -3233,6 +3238,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -626,8 +626,11 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
real_prefix = context->prefix;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
/* find floor time, don't reduce below 3 * RA interval.
|
||||
If the lease time has been left as default, don't
|
||||
use that as a floor. */
|
||||
if ((context->flags & CONTEXT_SETLEASE) &&
|
||||
time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)(3 * param->adv_interval)))
|
||||
|
||||
35
src/tftp.c
35
src/tftp.c
@@ -61,8 +61,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
union all_addr addra;
|
||||
int family = listen->addr.sa.sa_family;
|
||||
/* Can always get recvd interface for IPv6 */
|
||||
int check_dest = !option_bool(OPT_NOWILD) || listen->family == AF_INET6;
|
||||
int check_dest = !option_bool(OPT_NOWILD) || family == AF_INET6;
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
@@ -121,10 +122,10 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
addr.sa.sa_family = family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
@@ -138,7 +139,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -154,7 +155,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
@@ -171,7 +172,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
#endif
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
@@ -194,7 +195,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
addra.addr4 = addr.in.sin_addr;
|
||||
|
||||
if (listen->family == AF_INET6)
|
||||
if (family == AF_INET6)
|
||||
addra.addr6 = addr.in6.sin6_addr;
|
||||
|
||||
if (daemon->tftp_interfaces)
|
||||
@@ -210,12 +211,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
else
|
||||
{
|
||||
/* Do the same as DHCP */
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
if (!iface_check(family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra))
|
||||
if (!loopback_exception(listen->tftpfd, family, &addra, name) &&
|
||||
!label_exception(if_index, family, &addra))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
prefix = pref->prefix;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -304,7 +305,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if (option_bool(OPT_SINGLE_PORT))
|
||||
transfer->sockfd = listen->tftpfd;
|
||||
else if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
else if ((transfer->sockfd = socket(family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -322,7 +323,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
prettyprint_addr(&peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&peer, daemon->addrbuff);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (!option_bool(OPT_SINGLE_PORT))
|
||||
@@ -337,7 +338,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
if (listen->family == AF_INET)
|
||||
if (family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
@@ -375,7 +376,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((opt = next(&p, end)) && !option_bool(OPT_TFTP_NOBLOCK))
|
||||
{
|
||||
/* 32 bytes for IP, UDP and TFTP headers, 52 bytes for IPv6 */
|
||||
int overhead = (listen->family == AF_INET) ? 32 : 52;
|
||||
int overhead = (family == AF_INET) ? 32 : 52;
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
transfer->blocksize = 1;
|
||||
@@ -624,7 +625,7 @@ void check_tftp_listeners(time_t now)
|
||||
{
|
||||
strcpy(daemon->namebuff, transfer->file->filename);
|
||||
sanitise(daemon->namebuff);
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
my_syslog(MS_TFTP | LOG_INFO, endcon ? _("failed sending %s to %s") : _("sent %s to %s"), daemon->namebuff, daemon->addrbuff);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
@@ -667,7 +668,7 @@ static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len)
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
(void)prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
|
||||
Reference in New Issue
Block a user