Compare commits

...
40 Commits
Author SHA1 Message Date
Simon Kelley 02ed24d351 Add gitversion Debian build option. 2013-09-09 18:06:45 +01:00
Simon Kelley 6acef73052 Sponsorhip details in CHANGELOG. 2013-09-09 15:21:39 +01:00
Simon Kelley 10ae7b50f2 Don't use BINDTODEVICE on DHCP socket when relaying. 2013-09-05 20:08:01 +01:00
Simon Kelley 831b5ba12b Debian resolvconf script update. 2013-09-05 15:36:25 +01:00
Simon Kelley 0932f9c08b CHANGELOG update. 2013-09-05 11:30:30 +01:00
Simon Kelley 397542b213 Fix bug resulting in tight-loop when new interfaces arrive. 2013-09-05 11:27:34 +01:00
Simon Kelley 0c38719fe0 Don't crash with empty tag: in dhcp-range. 2013-09-05 10:21:12 +01:00
Simon Kelley ff7eea27e7 Add --dhcp-relay config option. 2013-09-04 18:01:38 +01:00
Simon Kelley 6692a1a53f Fix dhcp-range sanity checking. 2013-08-20 14:41:31 +01:00
Simon Kelley a37cd7aaf5 Use tags from pxe-proxy dhcp-range statements. 2013-08-20 10:33:32 +01:00
Vladislav Grishenko e4cdbbf521 Allow prefix :: in constructed dhcp-range. 2013-08-19 16:20:31 +01:00
Vladislav Grishenko 4568a6f842 IFACE_PERMANENT interface flag in enumeration. 2013-08-19 16:07:07 +01:00
Simon Kelley 5c72bb9e33 Silence compiler warning. 2013-08-19 14:12:59 +01:00
Vladislav Grishenko 8c3bdb4ffc Add code to get IPv6 address lifetimes and flags for *BSD. 2013-08-19 14:04:38 +01:00
Simon Kelley ffbad34b31 Set SOREUSEADDR as well as SOREUSEPORT on DHCP sockets when both available. 2013-08-14 15:53:57 +01:00
Simon Kelley f086d39641 Debian package change: update resolvconf script. 2013-08-14 14:54:23 +01:00
Simon Kelley cc4baaab0d Fix DHCPv6 lease time calculation when client sends VL==0 or PL==0 2013-08-05 15:03:44 +01:00
Simon Kelley 66409193dc Sanity check for dhcp-range template. 2013-08-01 20:19:32 +01:00
Simon Kelley 2937f8a040 Provide independent control over which interfaces get TFTP. 2013-07-29 19:49:07 +01:00
Simon Kelley edf0bde0c6 Make --listen-address higher priority than --except-interface. 2013-07-29 17:21:48 +01:00
Simon Kelley 8d03046269 Add --force-fast-ra option. 2013-07-29 15:41:26 +01:00
Simon Kelley 9f48ffa1e8 Apply ceiling of configured dhcp-range leasetime to deprecated prefix adverts. 2013-07-28 15:47:04 +01:00
Simon Kelley 871d4562f1 Support RFC-4242 information-refresh-time. 2013-07-28 09:37:38 +01:00
Simon Kelley 0f371f9e1a Remove dead code. 2013-07-27 15:15:38 +01:00
Simon Kelley 6bd109aa2f Better job with domain for DHCPv6 information-request. 2013-07-27 15:11:44 +01:00
Simon Kelley f7a40ec650 Tweak when old prefix returns. 2013-07-27 13:36:08 +01:00
Simon Kelley ff1b41dc57 Merge branch 'master' of ssh://thekelleys.org.uk/var/cache/git/dnsmasq
Conflicts:
	CHANGELOG
2013-07-27 12:32:29 +01:00
Simon Kelley fc4c4fda05 Fix MAC address enumeration on *BSD. 2013-07-26 15:38:59 +01:00
Simon Kelley ef1a94abaa Advertise lost prefixes with pref_time == 0 for 2 hours. 2013-07-26 13:59:03 +01:00
Simon Kelley d9fb0be8c7 Make --clear-on-reload apply to DBus API too. 2013-07-25 21:47:17 +01:00
Roy Marples 3f3adae6bc DHCP FQDN option tweaks. 2013-07-25 16:22:46 +01:00
Simon Kelley 1ecbaaa382 Tweak parameter lifetimes in Router advertisements. 2013-07-25 14:19:27 +01:00
Kyle Mestery d859ca2f9b Allow hostnames to start with a number. 2013-07-24 13:17:54 +01:00
Simon Kelley 3953dcc7f2 Typo in name in CHANGELOG. 2013-07-03 20:40:45 +01:00
Simon Kelley 625ac28c61 Fix crash with empty DHCP string options. 2013-07-02 21:19:32 +01:00
Simon Kelley b4b9308079 Increase timeout/number of retries in TFTP. 2013-06-19 10:31:23 +01:00
Simon Kelley e2ba0df2d4 Don't BIND DHCP socket if more interfaces may come along later. 2013-05-31 17:04:25 +01:00
Simon Kelley 921360ce62 Add constructor-noauth: keyword 2013-05-31 14:07:22 +01:00
Simon Kelley 429805dbbc Allow constructed ranges from interface address at end of range.
Also make man page on this clearer, as it's been confusing many.
2013-05-31 13:47:26 +01:00
Marcelo Salhab Brogliato 0da5e8979b Log forwarding table overflows. 2013-05-31 11:49:06 +01:00
28 changed files with 1214 additions and 414 deletions

No files matched your search

+61 -1
View File
@@ -47,7 +47,67 @@ version 2.67
Remove restriction on prefix-length in --auth-zone. Thanks
to Toke Hoiland-Jorgensen for suggesting this.
Log when the maximum number of concurrent DNS queries is
reached. Thanks to Marcelo Salhab Brogliato for the patch.
If wildcards are used in --interface, don't assume that
there will only ever be one available interface for DHCP
just because there is one at start-up. More may appear, so
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
report.
Increase timeout/number of retries in TFTP to accomodate
AudioCodes Voice Gateways doing streaming writes to flash.
Thanks to Damian Kaczkowski for spotting the problem.
Fix crash with empty DHCP string options when adding zero
terminator. Thanks to Patrick McLean for the bug report.
Allow hostnames to start with a number, as allowed in
RFC-1123. Thanks to Kyle Mestery for the patch.
Fixes to DHCP FQDN option handling: don't terminate FQDN
if domain not known and allow a FQDN option with blank
name to request that a FQDN option is returned in the
reply. Thanks to Roy Marples for the patch.
Make --clear-on-reload apply to setting upstream servers
via DBus too.
When the address which triggered the construction of an
advertised IPv6 prefix disappears, continue to advertise
the prefix for up to 2 hours, with the preferred lifetime
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
things work better if a prefix disappears without being
deprecated first. Thanks to Uwe Schindler for persuasively
arguing for this.
Fix MAC address enumeration on *BSD. Thanks to Brad Smith
for the bug report.
Support RFC-4242 information-refresh-time options in the
reply to DHCPv6 information-request. The lease time of the
smallest valid dhcp-range is sent. Thanks to Uwe Schindler
for suggesting this.
Add --force-fast-ra option. Another thanks to Uwe Schindler.
Make --listen-address higher priority than --except-interface
in all circumstances. Thanks to Thomas Hood for the bugreport.
Provide independent control over which interfaces get TFTP
service. If enable-tftp is given a list of interfaces, then TFTP
is provided on those. Without the list, the previous behaviour
(provide TFTP to the same interfaces we provide DHCP to)
is retained. Thanks to Lonnie Abelbeck for the suggestion.
Add --dhcp-relay config option. Many thanks to vtsl.net
for sponsoring this development.
Fix crash with empty tag: in --dhcp-range. Thanks to
Kaspar Schleiser for the bug report.
version 2.66
Add the ability to act as an authoritative DNS
server. Dnsmasq can now answer queries from the wider 'net
+1 -1
View File
@@ -12,7 +12,7 @@
# first. This favours, eg v2.63 over 2.63rc6.
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
cd $1; git describe
cd $1; git describe | sed 's/^v//'
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
+8 -1
View File
@@ -1,8 +1,15 @@
dnsmasq (2.67-1) unstable; urgency=low
* New upstream.
* Update resolvconf script. (closes: #720732)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:50:22 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:53:22 +0000
dnsmasq (2.66-4) unstable; urgency=low
* Update resolvconf script. (closes: #716908)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:48:21 +0000
dnsmasq (2.66-3) unstable; urgency=low
+3 -1
View File
@@ -64,7 +64,9 @@ Notes on configuring dnsmasq as packaged for Debian.
noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be
combined with noi18n to be effective.
gitversion : set the version of the produced packages from the
git-derived versioning information on the source,
rather the the debian changelog.
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
+7 -8
View File
@@ -16,8 +16,7 @@ set -e
RUN_DIR="/var/run/dnsmasq"
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
MY_RECORD_NAME="lo.dnsmasq"
DNSCRYPT_RECORD_NAME="lo.dnscrypt"
MY_NAME_FOR_RESOLVCONF="dnsmasq"
[ -x /usr/sbin/dnsmasq ] || exit 0
[ -x /lib/resolvconf/list-records ] || exit 1
@@ -46,14 +45,14 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
fi
RSLVCNFFILES=""
for F in $(/lib/resolvconf/list-records) ; do
for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
case "$F" in
"$MY_RECORD_NAME")
# Omit
"lo.$MY_NAME_FOR_RESOLVCONF")
# Omit own record
;;
"$DNSCRYPT_RECORD_NAME")
# Dnscrypt, I only have eyes for you
RSLVCNFFILES="$DNSCRYPT_RECORD_NAME"
lo.*)
# Include no more records after one for a local nameserver
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
break
;;
*)
+8 -3
View File
@@ -23,6 +23,11 @@ TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/[a-z]/~&/; s/$$/-1/; s/^/-v/')
endif
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_DBUS
endif
@@ -103,7 +108,7 @@ binary-indep: checkroot
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq -Pdebian/daemon
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
@@ -151,7 +156,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
endif
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/base
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
@@ -178,7 +183,7 @@ ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
endif
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..
+71 -6
View File
@@ -338,7 +338,8 @@ by '/', like the --server syntax, eg.
Don't poll /etc/resolv.conf for changes.
.TP
.B --clear-on-reload
Whenever /etc/resolv.conf is re-read, clear the DNS cache.
Whenever /etc/resolv.conf is re-read or the upstream servers are set
via DBus, clear the DNS cache.
This is useful when new nameservers may have different
data than that held in cache.
.TP
@@ -574,9 +575,11 @@ needed for a client to do validation itself.
.TP
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
will be served, except that A and AAAA records must be in one of the
will be served. A and AAAA records must be in one of the
specified subnets, or in a subnet corresponding to a constructed DHCP
range. The subnet(s) are also used to define in-addr.arpa and
range. (This can be overridden with
.B constructor-noauth:
) The subnet(s) are also used to define in-addr.arpa and
ipv6.arpa domains which are served for reverse-DNS queries. If not
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
@@ -649,7 +652,30 @@ This forms a template which describes how to create ranges, based on the address
.B --dhcp-range=::1,::400,constructor:eth0
will look for addresses of the form <network>::1 on eth0 and then create a range from <network>::1 to <network>::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard.
will look for addresses of the form <network>::1 or <network>:400 on
eth0 and then create a range from <network>::1 to <network>::400. If
the interface is assigned more than one network, then the
corresponding ranges will be automatically created, and then
deprecated and finally removed again as the address is deprecated and
then deleted. The interface name may have a final "*" wildcard. Note
that just any address on eth0 will not do: the non-prefix part must be
equal either the start or end address given in the dhcp-range. This is
to prevent prefixes becoming perpetual if the interface
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
If a dhcp-range is only being used for stateless DHCP and/or SLAAC,
then the address can be simply ::
.B --dhcp-range=::,constructor:eth0
This removes the condition above, and will pick up the prefix from any address on eth0 which is NOT
autoconfigured, slaac, temporary or deprecated.
There is a variant of the constructor: syntax using the keyword
.B constructor-noauth.
See
.B --auth-zone
for an explanation of this.
The optional
.B set:<tag>
@@ -947,6 +973,38 @@ DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case.
.TP
.B --dhcp-relay=<local address>,<server address>[,<interface]
Configure dnsmasq to do DHCP relay. The local address is an address
allocated to an interface on the host running dnsmasq. All DHCP
requests arriving on that interface will we relayed to a remote DHCP
server at the server address. It is possible to relay from a single local
address to multiple remote servers by using multiple dhcp-relay
configs with the same local address and different server
addresses. A server address must be an IP literal address, not a
domain name. In the case of DHCPv6, the server address may be the
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
must be given, not be wildcard, and is used to direct the multicast to the
correct interface to reach the DHCP server.
Access control for DHCP clients has the same rules as for the DHCP
server, see --interface, --except-interface, etc. The optional
interface name in the dhcp-relay config has a different function: it
controls on which interface DHCP replies from the server will be
accepted. This is intended for configurations which have three
interfaces: one being relayed from, a second connecting the DHCP
server, and a third untrusted network, typically the wider
internet. It avoids the possibility of spoof replies arriving via this
third interface.
It is allowed to have dnsmasq act as a DHCP server on one set of
interfaces and relay from a disjoint set of interfaces. Note that
whilst it is quite possible to write configurations which appear to
act as a server and a relay on the same interface, this is not
supported: the relay function will take precedence.
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
DHCPv4 to a DHCPv6 server or vice-versa.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
Map from a vendor-class string to a tag. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This option
@@ -1469,11 +1527,18 @@ the relevant link-local address of the machine running dnsmasq is sent
as recursive DNS server. If provided, the DHCPv6 options dns-server and
domain-search are used for RDNSS and DNSSL.
.TP
.B --enable-tftp
.B --force-fast-ra
Normally, dnsmasq advertises a new IPv6 prefix frequently (every 10 seconds or so) for the first minute, and then
drops back to sending "maintenance" advertisements every 10 minutes or so. This option forces dnsmasq to be always in
frequent RA mode. It's a bug workaround for mobile devices which go deaf to RAs during sleep and therefore
lose conectivity; with frequent RAs they recover in a reasonable time after wakeup.
.TP
.B --enable-tftp[=<interface>[,<interface>]]
Enable the TFTP server function. This is deliberately limited to that
needed to net-boot a client. Only reading is allowed; the tsize and
blksize extensions are supported (tsize is only supported in octet
mode).
mode). Without an argument, the TFTP service is provided to the same set of interfaces as DHCP service.
If the list of interfaces is provided, that defines which interfaces recieve TFTP service.
.TP
.B --tftp-root=<directory>[,<interface>]
Look for files to transfer using TFTP relative to the given
+1
View File
@@ -54,6 +54,7 @@ static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_
if (flag & F_IPV6)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
!(context->flags & CONTEXT_NOAUTH) &&
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
return 1;
#endif
+53 -11
View File
@@ -25,6 +25,10 @@
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/if_ether.h>
#if defined(__FreeBSD__)
# include <net/if_var.h>
#endif
#include <netinet/in_var.h>
#ifndef SA_SIZE
#define SA_SIZE(sa) \
@@ -89,7 +93,7 @@ int arp_enumerate(void *parm, int (*callback)())
int iface_enumerate(int family, void *parm, int (*callback)())
{
struct ifaddrs *head, *addrs;
int errsav, ret = 0;
int errsav, fd = -1, ret = 0;
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
@@ -105,13 +109,19 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (getifaddrs(&head) == -1)
return 0;
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_IPV6)
if (family == AF_INET6)
fd = socket(PF_INET6, SOCK_DGRAM, 0);
#endif
for (addrs = head; addrs; addrs = addrs->ifa_next)
{
if (addrs->ifa_addr->sa_family == family)
{
int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0 || !addrs->ifa_addr || !addrs->ifa_netmask)
if (iface_index == 0 || !addrs->ifa_addr ||
(!addrs->ifa_netmask && family != AF_LINK))
continue;
if (family == AF_INET)
@@ -133,11 +143,40 @@ int iface_enumerate(int family, void *parm, int (*callback)())
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
int i, j, prefix = 0;
u32 valid = 0xffffffff, preferred = 0xffffffff;
int flags = 0;
#ifdef HAVE_BSD_NETWORK
struct in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
{
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
flags |= IFACE_TENTATIVE;
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED;
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
flags |= IFACE_PERMANENT;
}
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
{
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
}
#endif
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
@@ -148,13 +187,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
/* preferred and valid times == forever until we known how to dtermine them. */
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, -1, -1, parm)))
goto err;
}
#endif
}
if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
(int) preferred, (int)valid, parm)))
goto err;
}
#endif /* HAVE_IPV6 */
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
@@ -172,7 +212,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
err:
errsav = errno;
freeifaddrs(head);
freeifaddrs(head);
if (fd != -1)
close(fd);
errno = errsav;
return ret;
+16 -7
View File
@@ -305,8 +305,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
const char *addr_err;
char *dup = NULL;
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
if (!dbus_message_iter_init(message, &iter))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
@@ -478,6 +476,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{
char *method = (char *)dbus_message_get_member(message);
DBusMessage *reply = NULL;
int clear_cache = 0, new_servers = 0;
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
@@ -501,24 +500,34 @@ DBusHandlerResult message_handler(DBusConnection *connection,
}
else if (strcmp(method, "SetServers") == 0)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
dbus_read_servers(message);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "SetServersEx") == 0)
{
reply = dbus_read_servers_ex(message, 0);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "SetDomainServers") == 0)
{
reply = dbus_read_servers_ex(message, 1);
check_servers();
new_servers = 1;
}
else if (strcmp(method, "ClearCache") == 0)
clear_cache_and_reload(dnsmasq_time());
clear_cache = 1;
else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
if (new_servers)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
check_servers();
if (option_bool(OPT_RELOAD))
clear_cache = 1;
}
if (clear_cache)
clear_cache_and_reload(dnsmasq_time());
method = user_data; /* no warning */
+29 -12
View File
@@ -347,21 +347,27 @@ void bindtodevice(int fd)
to that device. This is for the use case of (eg) OpenStack, which runs a new
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
individual processes don't always see the packets they should.
SO_BINDTODEVICE is only available Linux. */
SO_BINDTODEVICE is only available Linux.
Note that if wildcards are used in --interface, or a configured interface doesn't
yet exist, then more interfaces may arrive later, so we can't safely assert there
is only one interface and proceed.
*/
struct irec *iface, *found;
struct iname *if_tmp;
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
return;
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok)
{
if (!found)
found = iface;
else if (strcmp(found->name, iface->name) != 0)
{
/* more than one. */
found = NULL;
break;
}
return; /* more than one. */
}
if (found)
@@ -714,7 +720,7 @@ void log_context(int family, struct dhcp_context *context)
p += sprintf(p, ", ");
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "constructed for %s", ifrn_name);
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
}
else if (context->flags & CONTEXT_TEMPLATE)
{
@@ -725,7 +731,8 @@ void log_context(int family, struct dhcp_context *context)
}
#endif
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET))
{
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
@@ -742,14 +749,24 @@ void log_context(int family, struct dhcp_context *context)
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_NAME)
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
#endif
}
void log_relay(int family, struct dhcp_relay *relay)
{
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
if (relay->interface)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
}
#endif
+165 -51
View File
@@ -20,6 +20,8 @@
struct iface_param {
struct dhcp_context *current;
struct dhcp_relay *relay;
struct in_addr relay_local;
int ind;
};
@@ -32,6 +34,8 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
static int make_fd(int port)
{
@@ -70,15 +74,15 @@ static int make_fd(int port)
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = -1, porterr = 0;
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno != ENOPROTOOPT)
porterr = 1;
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc == -1 && !porterr)
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
@@ -132,6 +136,8 @@ void dhcp_packet(time_t now, int pxe_fd)
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
struct dhcp_packet *mess;
struct dhcp_context *context;
struct dhcp_relay *relay;
int is_relay_reply = 0;
struct iname *tmp;
struct ifreq ifr;
struct msghdr msg;
@@ -250,57 +256,86 @@ void dhcp_packet(time_t now, int pxe_fd)
unicast_dest = 1;
#endif
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
{
/* Reply from server, using us as relay. */
iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
is_relay_reply = 1;
iov.iov_len = sz;
#ifdef HAVE_LINUX_NETWORK
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
#endif
}
else
{
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
parm.current = NULL;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
else
{
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
match.matched = 0;
match.ind = iface_index;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
/* unlinked contexts/relays are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
for (relay = daemon->relay4; relay; relay = relay->next)
relay->current = relay;
parm.current = NULL;
parm.relay = NULL;
parm.relay_local.s_addr = 0;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
match.matched = 0;
match.ind = iface_index;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
relay_upstream4(parm.relay, (struct dhcp_packet *)daemon->dhcp_packet.iov_base, (size_t)sz, iface_index))
return;
/* May have configured relay, but not DHCP server */
if (!daemon->dhcp)
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now);
lease_update_dns(0);
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
lease_prune(NULL, now); /* lose any expired leases */
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now);
lease_update_dns(0);
if (iov.iov_len == 0)
return;
if (iov.iov_len == 0)
return;
}
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
@@ -321,7 +356,7 @@ void dhcp_packet(time_t now, int pxe_fd)
if (mess->ciaddr.s_addr != 0)
dest.sin_addr = mess->ciaddr;
}
else if (mess->giaddr.s_addr)
else if (mess->giaddr.s_addr && !is_relay_reply)
{
/* Send to BOOTP relay */
dest.sin_port = htons(daemon->dhcp_server_port);
@@ -334,7 +369,7 @@ void dhcp_packet(time_t now, int pxe_fd)
source port too, and send back to that. If we're replying
to a DHCPINFORM, trust the source address always. */
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
{
dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->ciaddr;
@@ -450,6 +485,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
(void)label;
@@ -495,6 +531,15 @@ static int complete_context(struct in_addr local, int if_index, char *label,
}
}
for (relay = daemon->relay4; relay; relay = relay->next)
if (if_index == param->ind && relay->local.addr.addr4.s_addr == local.s_addr && relay->current == relay &&
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = local;
}
return 1;
}
@@ -988,5 +1033,74 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
#endif
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
{
/* ->local is same value for all relays on ->current chain */
struct all_addr from;
if (mess->op != BOOTREQUEST)
return 0;
/* source address == relay address */
from.addr.addr4 = relay->local.addr.addr4;
/* already gatewayed ? */
if (mess->giaddr.s_addr)
{
/* if so check if by us, to stomp on loops. */
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
return 1;
}
else
{
/* plug in our address */
mess->giaddr.s_addr = relay->local.addr.addr4.s_addr;
}
if ((mess->hops++) > 20)
return 1;
for (; relay; relay = relay->current)
{
union mysockaddr to;
to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr.addr4;
to.in.sin_port = htons(daemon->dhcp_server_port);
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, inet_ntoa(relay->server.addr.addr4));
}
/* Save this for replies */
relay->iface_index = iface_index;
}
return 1;
}
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
{
struct dhcp_relay *relay;
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
return NULL;
for (relay = daemon->relay4; relay; relay = relay->next)
{
if (mess->giaddr.s_addr == relay->local.addr.addr4.s_addr)
{
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
return relay->iface_index != 0 ? relay : NULL;
}
}
return NULL;
}
#endif
+1
View File
@@ -55,6 +55,7 @@
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_DOMAIN_SEARCH 24
#define OPTION6_REFRESH_TIME 32
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
+187 -114
View File
@@ -20,7 +20,8 @@
struct iface_param {
struct dhcp_context *current;
struct in6_addr fallback;
struct dhcp_relay *relay;
struct in6_addr fallback, relay_local;
int ind, addr_match;
};
@@ -55,15 +56,15 @@ void dhcp6_init(void)
support it. This handles the introduction of REUSEPORT on Linux. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = -1, porterr = 0;
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno != ENOPROTOOPT)
porterr = 1;
errno == ENOPROTOOPT)
rc = 0;
#endif
if (rc == -1 && !porterr)
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
@@ -87,6 +88,7 @@ void dhcp6_init(void)
void dhcp6_packet(time_t now)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param parm;
struct cmsghdr *cmptr;
struct msghdr msg;
@@ -126,56 +128,75 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
parm.current = NULL;
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break;
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
parm.current = NULL;
parm.relay = NULL;
memset(&parm.relay_local, 0, IN6ADDRSZ);
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
if (!tmp && !parm.addr_match)
for (relay = daemon->relay6; relay; relay = relay->next)
relay->current = relay;
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break;
if (!tmp && !parm.addr_match)
return;
}
if (parm.relay)
{
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
return;
}
/* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6)
return;
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now);
lease_update_dns(0);
}
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now);
lease_update_dns(0);
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
@@ -194,70 +215,84 @@ static int complete_context6(struct in6_addr *local, int prefix,
unsigned int valid, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
if (if_index == param->ind)
{
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
struct dhcp_context *tmp, **up;
/* use interface values only for contructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
}
return 1;
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
@@ -538,7 +573,11 @@ static int construct_worker(struct in6_addr *local, int prefix,
}
}
else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
else if ((addr6part(local) == addr6part(&template->start6) ||
addr6part(local) == addr6part(&template->end6) ||
(IN6_IS_ADDR_UNSPECIFIED(&template->start6) &&
IFACE_PERMANENT == (flags & (IFACE_PERMANENT | IFACE_DEPRECATED)))) &&
wildcard_match(template->template_interface, ifrn_name))
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
@@ -550,7 +589,18 @@ static int construct_worker(struct in6_addr *local, int prefix,
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
context->flags &= ~CONTEXT_GC;
int flags = context->flags;
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
if (flags & CONTEXT_OLD)
{
/* address went, now it's back */
log_context(AF_INET6, context);
/* fast RAs for a while */
ra_start_unsolicted(param->now, context);
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
}
break;
}
@@ -563,6 +613,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->saved_valid = 0;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
@@ -585,35 +636,57 @@ static int construct_worker(struct in6_addr *local, int prefix,
void dhcp_construct_contexts(time_t now)
{
struct dhcp_context *tmp, *context, **up;
struct dhcp_context *context, *tmp, **up;
struct cparam param;
param.newone = 0;
param.newname = 0;
param.now = now;
for (context = daemon->dhcp6; context; context = context->next)
{
context->if_index = 0;
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
}
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->flags & CONTEXT_GC)
tmp = context->next;
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
{
*up = context->next;
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
free(context);
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
option_bool(OPT_RA))
{
/* previously constructed context has gone. advertise it's demise */
context->flags |= CONTEXT_OLD;
context->address_lost_time = now;
/* Apply same ceiling of configured lease time as in radv.c */
if (context->saved_valid > context->lease_time)
context->saved_valid = context->lease_time;
/* maximum time is 2 hours, from RFC */
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
ra_start_unsolicted(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
log_context(AF_INET6, context);
up = &context->next;
}
else
{
/* we were never doing RA for this, so free now */
*up = context->next;
free(context);
}
}
else
up = &context->next;
up = &context->next;
}
if (param.newone)
+50 -45
View File
@@ -52,6 +52,7 @@ int main (int argc, char **argv)
cap_user_data_t data = NULL;
#endif
struct dhcp_context *context;
struct dhcp_relay *relay;
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -166,50 +167,47 @@ int main (int argc, char **argv)
daemon->soa_sn = now;
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
{
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
daemon->doing_ra = option_bool(OPT_RA);
# ifdef HAVE_DHCP6
if (daemon->dhcp6)
for (context = daemon->dhcp6; context; context = context->next)
{
daemon->doing_ra = option_bool(OPT_RA);
for (context = daemon->dhcp6; context; context = context->next)
{
if (context->flags & CONTEXT_DHCP)
daemon->doing_dhcp6 = 1;
if (context->flags & CONTEXT_RA)
daemon->doing_ra = 1;
if (context->flags & CONTEXT_DHCP)
daemon->doing_dhcp6 = 1;
if (context->flags & CONTEXT_RA)
daemon->doing_ra = 1;
#ifndef HAVE_LINUX_NETWORK
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
#endif
}
}
# endif
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
if (daemon->dhcp || daemon->doing_dhcp6)
{
dhcp_common_init();
lease_init(now);
}
if (daemon->dhcp)
dhcp_init();
# ifdef HAVE_DHCP6
if (daemon->doing_ra)
ra_init(now);
if (daemon->doing_dhcp6)
dhcp6_init();
# endif
}
#endif
#ifdef HAVE_DHCP
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
if (daemon->dhcp || daemon->doing_dhcp6 || daemon->relay4 || daemon->relay6)
{
dhcp_common_init();
if (daemon->dhcp || daemon->doing_dhcp6)
lease_init(now);
}
if (daemon->dhcp || daemon->relay4)
dhcp_init();
# ifdef HAVE_DHCP6
if (daemon->doing_ra)
ra_init(now);
if (daemon->doing_dhcp6 || daemon->relay6)
dhcp6_init();
# endif
#endif
@@ -241,14 +239,15 @@ int main (int argc, char **argv)
/* after enumerate_interfaces() */
if (daemon->dhcp)
{
bindtodevice(daemon->dhcpfd);
if (!daemon->relay4)
bindtodevice(daemon->dhcpfd);
if (daemon->enable_pxe)
bindtodevice(daemon->pxefd);
}
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
if (daemon->doing_dhcp6)
if (daemon->doing_dhcp6 && !daemon->relay6)
bindtodevice(daemon->dhcp6fd);
#endif
}
@@ -257,7 +256,7 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
if (daemon->doing_dhcp6 || daemon->doing_ra)
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
join_multicast(1);
#endif
@@ -641,10 +640,16 @@ int main (int argc, char **argv)
for (context = daemon->dhcp; context; context = context->next)
log_context(AF_INET, context);
for (relay = daemon->relay4; relay; relay = relay->next)
log_relay(AF_INET, relay);
# ifdef HAVE_DHCP6
for (context = daemon->dhcp6; context; context = context->next)
log_context(AF_INET6, context);
for (relay = daemon->relay6; relay; relay = relay->next)
log_relay(AF_INET6, relay);
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
@@ -749,7 +754,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->relay4)
{
FD_SET(daemon->dhcpfd, &rset);
bump_maxfd(daemon->dhcpfd, &maxfd);
@@ -762,7 +767,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6)
if (daemon->doing_dhcp6 || daemon->relay6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
@@ -874,7 +879,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->relay4)
{
if (FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now, 0);
@@ -883,7 +888,7 @@ int main (int argc, char **argv)
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
if ((daemon->doing_dhcp6 || daemon->relay6) && FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
+20 -4
View File
@@ -221,7 +221,8 @@ struct event_desc {
#define OPT_TFTP_LC 38
#define OPT_CLEVERBIND 39
#define OPT_TFTP 40
#define OPT_LAST 41
#define OPT_FAST_RA 41
#define OPT_LAST 42
/* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -399,6 +400,7 @@ union mysockaddr {
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2
#define IFACE_PERMANENT 4
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
@@ -706,8 +708,8 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
unsigned int valid, preferred;
time_t ra_time, ra_short_period_start;
unsigned int valid, preferred, saved_valid;
time_t ra_time, ra_short_period_start, address_lost_time;
char *template_interface;
#endif
int flags;
@@ -731,6 +733,9 @@ struct dhcp_context {
#define CONTEXT_RA 8192
#define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768
#define CONTEXT_NOAUTH 65536
#define CONTEXT_OLD 131072
struct ping_result {
struct in_addr addr;
@@ -770,6 +775,12 @@ struct tftp_prefix {
struct tftp_prefix *next;
};
struct dhcp_relay {
struct all_addr local, server;
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
int iface_index; /* working - interface in which requests arrived, for return */
struct dhcp_relay *current, *next;
};
extern struct daemon {
/* datastuctures representing the command-line and
@@ -799,7 +810,7 @@ extern struct daemon {
struct cond_domain *cond_domain, *synth_domains;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers, *tftp_interfaces;
struct bogus_addr *bogus_addr;
struct server *servers;
struct ipsets *ipsets;
@@ -819,6 +830,7 @@ extern struct daemon {
struct pxe_service *pxe_services;
struct tag_if *tag_if;
struct addr_list *override_relays;
struct dhcp_relay *relay4, *relay6;
int override;
int enable_pxe;
int doing_ra, doing_dhcp6;
@@ -1212,6 +1224,9 @@ void dhcp_construct_contexts(time_t now);
#ifdef HAVE_DHCP6
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
#endif
/* dhcp-common.c */
@@ -1238,6 +1253,7 @@ void bindtodevice(int fd);
void display_opts6(void);
# endif
void log_context(int family, struct dhcp_context *context);
void log_relay(int family, struct dhcp_relay *relay);
#endif
/* outpacket.c */
+1 -1
View File
@@ -224,7 +224,7 @@ char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
if ((c = search_domain6(addr, daemon->cond_domain)))
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
+9
View File
@@ -1205,8 +1205,17 @@ struct frec *get_new_frec(time_t now, int *wait)
/* none available, calculate time 'till oldest record expires */
if (count > daemon->ftabsize)
{
static time_t last_log = 0;
if (oldest && wait)
*wait = oldest->time + (time_t)TIMEOUT - now;
if ((int)difftime(now, last_log) > 5)
{
last_log = now;
my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
}
return NULL;
}
+8 -5
View File
@@ -265,6 +265,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifa->ifa_flags & IFA_F_DEPRECATED)
flags |= IFACE_DEPRECATED;
if (ifa->ifa_flags & IFA_F_PERMANENT)
flags |= IFACE_PERMANENT;
if (addrp && callback_ok)
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
@@ -399,18 +402,18 @@ static int nl_async(struct nlmsghdr *h)
static void nl_newaddress(time_t now)
{
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
enumerate_interfaces(0);
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
join_multicast(0);
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
join_multicast(0);
dhcp_construct_contexts(now);
}
dhcp_construct_contexts(now);
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
+26 -11
View File
@@ -112,7 +112,7 @@ int indextoname(int fd, int index, char *name)
int iface_check(int family, struct all_addr *addr, char *name, int *auth)
{
struct iname *tmp;
int ret = 1;
int ret = 1, match_addr = 0;
/* Note: have to check all and not bail out early, so that we set the
"used" flags. */
@@ -134,19 +134,20 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
{
if (family == AF_INET &&
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
ret = tmp->used = 1;
ret = match_addr = tmp->used = 1;
#ifdef HAVE_IPV6
else if (family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
&addr->addr.addr6))
ret = tmp->used = 1;
ret = match_addr = tmp->used = 1;
#endif
}
}
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
ret = 0;
if (!match_addr)
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
ret = 0;
for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
@@ -358,6 +359,16 @@ static int iface_allowed(struct iface_param *param, int if_index, char *label,
}
#endif
if (daemon->tftp_interfaces)
{
/* dedicated tftp interface list */
tftp_ok = 0;
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
tftp_ok = 1;
}
/* add to list */
if ((iface = whine_malloc(sizeof(struct irec))))
{
@@ -432,7 +443,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
int enumerate_interfaces(int reset)
{
static struct addrlist *spare = NULL;
static int done = 0;
static int done = 0, active = 0;
struct iface_param param;
int errsave, ret = 1;
struct addrlist *addr, *tmp;
@@ -440,18 +451,21 @@ int enumerate_interfaces(int reset)
/* Do this max once per select cycle - also inhibits netlink socket use
in TCP child processes. */
if (reset)
{
done = 0;
return 1;
}
if (done)
if (done || active)
return 1;
done = 1;
/* protect against recusive calls from iface_enumerate(); */
active = 1;
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
@@ -493,7 +507,8 @@ int enumerate_interfaces(int reset)
errno = errsave;
spare = param.spare;
active = 0;
return ret;
}
@@ -840,7 +855,7 @@ void join_multicast(int dienow)
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
if ((daemon->doing_dhcp6 || daemon->relay6) &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
+84 -25
View File
@@ -132,6 +132,8 @@ struct myoption {
#ifdef OPTION6_PREFIX_CLASS
#define LOPT_PREF_CLSS 321
#endif
#define LOPT_FAST_RA 322
#define LOPT_RELAY 323
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -207,7 +209,7 @@ static const struct myoption opts[] =
{ "dns-forward-max", 1, 0, '0' },
{ "clear-on-reload", 0, 0, LOPT_RELOAD },
{ "dhcp-ignore-names", 2, 0, LOPT_NO_NAMES },
{ "enable-tftp", 0, 0, LOPT_TFTP },
{ "enable-tftp", 2, 0, LOPT_TFTP },
{ "tftp-secure", 0, 0, LOPT_SECURE },
{ "tftp-unique-root", 0, 0, LOPT_APREF },
{ "tftp-root", 1, 0, LOPT_PREFIX },
@@ -269,6 +271,8 @@ static const struct myoption opts[] =
#ifdef OPTION6_PREFIX_CLASS
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
#endif
{ "force-fast-ra", 0, 0, LOPT_FAST_RA },
{ "dhcp-relay", 1, 0, LOPT_RELAY },
{ NULL, 0, 0, 0 }
};
@@ -366,7 +370,7 @@ static struct {
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
{ LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
{ LOPT_TFTP, OPT_TFTP, NULL, gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_TFTP, ARG_DUP, "[=<intr>[,<intr>]]", gettext_noop("Enable integrated read-only TFTP server."), NULL },
{ LOPT_PREFIX, ARG_DUP, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
@@ -387,6 +391,7 @@ static struct {
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
{ LOPT_RELAY, ARG_DUP, "<local-addr>,<server>[,<interface>]", gettext_noop("Relay DHCP requests to a remote server"), NULL},
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
@@ -397,6 +402,7 @@ static struct {
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
{ LOPT_RA, OPT_RA, NULL, gettext_noop("Send router-advertisements for interfaces doing DHCPv6"), NULL },
{ LOPT_FAST_RA, OPT_FAST_RA, NULL, gettext_noop("Always send frequent router-advertisements"), NULL },
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
@@ -1655,7 +1661,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_AUTHSOA: /* --auth-soa */
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_sn);
daemon->soa_sn = (u32)atoi(arg);
if (comma)
{
char *cp;
@@ -1670,17 +1676,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_refresh);
daemon->soa_refresh = (u32)atoi(arg);
if (comma)
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_retry);
daemon->soa_retry = (u32)atoi(arg);
if (comma)
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_expiry);
daemon->soa_expiry = (u32)atoi(arg);
}
}
}
@@ -1901,6 +1907,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
} while (arg);
break;
case LOPT_TFTP: /* --enable-tftp */
set_option_bool(OPT_TFTP);
if (!arg)
break;
/* fall through */
case 'I': /* --except-interface */
case '2': /* --no-dhcp-interface */
do {
@@ -1912,6 +1924,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->if_except;
daemon->if_except = new;
}
else if (option == LOPT_TFTP)
{
new->next = daemon->tftp_interfaces;
daemon->tftp_interfaces = new;
}
else
{
new->next = daemon->dhcp_except;
@@ -2320,7 +2337,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
tt->net = opt_string_alloc(arg+4);
tt->next = new->filter;
new->filter = tt;
/* ignore empty tag */
if (tt->net)
new->filter = tt;
}
else
{
@@ -2387,11 +2406,9 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
new->prefix = 64; /* default */
new->end6 = new->start6;
/* dhcp-range=:: enables DHCP stateless on any interface */
if (IN6_IS_ADDR_UNSPECIFIED(&new->start6))
new->prefix = 0;
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
for (leasepos = 1; leasepos < k; leasepos++)
{
if (strcmp(a[leasepos], "static") == 0)
@@ -2409,13 +2426,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->template_interface = opt_string_alloc(a[leasepos] + 12);
new->flags |= CONTEXT_TEMPLATE;
}
else if (strstr(a[leasepos], "constructor-noauth:") == a[leasepos])
{
new->template_interface = opt_string_alloc(a[leasepos] + 19);
new->flags |= CONTEXT_TEMPLATE | CONTEXT_NOAUTH;
}
else
break;
}
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
/* bare integer < 128 is prefix value */
if (leasepos < k)
{
@@ -2427,20 +2446,35 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
new->prefix = pref;
leasepos++;
if (new->prefix != 64)
{
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
ret_err(_("prefix must be exactly 64 for RA subnets"));
else if (new->template_interface)
ret_err(_("prefix must be exactly 64 for subnet constructors"));
}
if (new->prefix < 64)
ret_err(_("prefix must be at least 64"));
}
}
if (new->prefix != 64)
{
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
ret_err(_("prefix length must be exactly 64 for RA subnets"));
else if (new->flags & CONTEXT_TEMPLATE)
ret_err(_("prefix length must be exactly 64 for subnet constructors"));
}
if (new->prefix < 64)
ret_err(_("prefix length must be at least 64"));
if (!is_same_net6(&new->start6, &new->end6, new->prefix))
ret_err(_("inconsistent DHCPv6 range"));
/* dhcp-range=:: enables DHCP stateless on any interface */
if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
new->prefix = 0;
if (new->flags & CONTEXT_TEMPLATE)
{
struct in6_addr zero;
memset(&zero, 0, sizeof(zero));
if (!is_same_net6(&zero, &new->start6, new->prefix))
ret_err(_("prefix must be zero with \"constructor:\" argument"));
}
if (addr6part(&new->start6) > addr6part(&new->end6))
{
struct in6_addr tmp = new->start6;
@@ -3149,6 +3183,31 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
arg = comma;
}
break;
case LOPT_RELAY: /* --dhcp-relay */
{
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
comma = split(arg);
new->interface = opt_string_alloc(split(comma));
new->iface_index = 0;
if (inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
{
new->next = daemon->relay4;
daemon->relay4 = new;
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
{
new->next = daemon->relay6;
daemon->relay6 = new;
}
#endif
else
ret_err(_("Bad dhcp-relay"));
break;
}
#endif
#ifdef HAVE_DHCP6
+2 -2
View File
@@ -70,9 +70,9 @@ void *put_opt6(void *data, size_t len)
{
void *p;
if ((p = expand(len)))
if ((p = expand(len)) && data)
memcpy(p, data, len);
return p;
}
+97 -27
View File
@@ -47,6 +47,7 @@ static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static void new_timeout(struct dhcp_context *context, time_t now);
static int hop_limit;
@@ -187,9 +188,8 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
{
struct ra_packet *ra;
struct ra_param parm;
struct ifreq ifr;
struct sockaddr_in6 addr;
struct dhcp_context *context;
struct dhcp_context *context, *tmp, **up;
struct dhcp_netid iface_id;
struct dhcp_opt *opt_cfg;
int done_dns = 0;
@@ -228,12 +228,66 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
context->netid.next = &context->netid;
}
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
/* Look for constructed contexts associated with addresses which have gone,
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
{
unsigned int old = difftime(now, context->address_lost_time);
if (old > context->saved_valid)
{
/* We've advertised this enough, time to go */
*up = context->next;
free(context);
}
else
{
struct prefix_opt *opt;
struct in6_addr local = context->start6;
int do_slaac = 0;
parm.found_context = 1;
/* zero net part of address */
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
do_slaac = 1;
if ((opt = expand(sizeof(struct prefix_opt))))
{
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = context->prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
opt->valid_lifetime = htonl(context->saved_valid - old);
opt->preferred_lifetime = htonl(0);
opt->reserved = 0;
opt->prefix = local;
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
}
up = &context->next;
}
}
else
up = &context->next;
}
if (!parm.found_context)
return;
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
available from SIOCGIFMTU */
@@ -291,7 +345,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
put_opt6_char(ICMP6_OPT_DNSSL);
put_opt6_char(len + 1);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
put_opt6(opt_cfg->val, opt_cfg->len);
/* pad */
@@ -361,11 +415,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
struct dhcp_context *context;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
context->saved_valid = valid;
if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
{
@@ -386,12 +442,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->other = 1;
}
/* find floor time, don't reduce below RA interval. */
/* find floor time, don't reduce below 3 * RA interval. */
if (time > context->lease_time)
{
time = context->lease_time;
if (time < ((unsigned int)RA_INTERVAL))
time = RA_INTERVAL;
if (time < ((unsigned int)(3 * RA_INTERVAL)))
time = 3 * RA_INTERVAL;
}
if (context->flags & CONTEXT_DEPRECATE)
@@ -466,6 +522,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
}
@@ -520,16 +577,25 @@ time_t periodic_ra(time_t now)
if (!context)
break;
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
if (iface_enumerate(AF_INET6, &param, iface_search))
if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
{
/* A context for an old address. We'll not find the interface by
looking for addresses, but we know it anyway, as long as we
sent at least one RA whilst the address was current. */
param.iface = context->if_index;
new_timeout(context, now);
}
else if (iface_enumerate(AF_INET6, &param, iface_search))
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
context->ra_time = 0;
else if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface, NULL))
if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface, NULL))
{
struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -554,7 +620,7 @@ static int iface_search(struct in6_addr *local, int prefix,
(void)valid;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix) &&
@@ -568,12 +634,7 @@ static int iface_search(struct in6_addr *local, int prefix,
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
new_timeout(context, param->now);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
@@ -588,6 +649,15 @@ static int iface_search(struct in6_addr *local, int prefix,
return 1; /* keep searching */
}
static void new_timeout(struct dhcp_context *context, time_t now)
{
if (difftime(now, context->ra_short_period_start) < 60.0 || option_bool(OPT_FAST_RA))
/* range 5 - 20 */
context->ra_time = now + 5 + (rand16()/4400);
else
/* range 3/4 - 1 times RA_INTERVAL */
context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
}
#endif
+23 -10
View File
@@ -615,7 +615,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
{
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
int len = option_len(opt);
@@ -645,7 +645,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
if (fqdn_flags & 0x04)
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
while (*op != 0 && ((op + (*op)) - pp) < len)
{
memcpy(pq, op+1, *op);
pq += *op;
@@ -848,8 +848,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (tmp)
{
struct dhcp_boot *boot = find_boot(tagif_netid);
struct dhcp_boot *boot;
if (tmp->netid.net)
{
tmp->netid.next = netid;
tagif_netid = run_tag_if(&tmp->netid);
}
boot = find_boot(tagif_netid);
mess->yiaddr.s_addr = 0;
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
{
@@ -1385,8 +1393,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease->hostname)
hostname = lease->hostname;
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
domain = get_domain(mess->ciaddr);
if (!hostname)
hostname = host_from_dns(mess->ciaddr);
if (context && context->netid.net)
{
@@ -1833,7 +1841,8 @@ static int do_opt(struct dhcp_opt *opt, unsigned char *p, struct dhcp_context *c
}
}
else
memcpy(p, opt->val, len);
/* empty string may be extended to "\0" by null_term */
memcpy(p, opt->val ? opt->val : (unsigned char *)"", len);
}
return len;
}
@@ -2289,7 +2298,9 @@ static void do_options(struct dhcp_context *context,
if (domain)
len += strlen(domain) + 1;
else if (fqdn_flags & 0x04)
len--;
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
{
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
@@ -2300,8 +2311,10 @@ static void do_options(struct dhcp_context *context,
{
p = do_rfc1035_name(p, hostname);
if (domain)
p = do_rfc1035_name(p, domain);
*p++ = 0;
{
p = do_rfc1035_name(p, domain);
*p++ = 0;
}
}
else
{
+249 -49
View File
@@ -54,13 +54,13 @@ static struct prefix_class *prefix_class_from_context(struct dhcp_context *conte
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr);
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
static int check_address(struct state *state, struct in6_addr *addr);
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now);
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
static int add_local_addrs(struct dhcp_context *context);
struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context);
static struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context, int do_refresh);
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time);
unsigned int *preferred_timep, unsigned int lease_time);
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
@@ -120,7 +120,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
!IN6_IS_ADDR_MULTICAST(link_address))
for (c = daemon->dhcp6; c; c = c->next)
if ((c->flags & CONTEXT_DHCP) &&
!(c->flags & CONTEXT_TEMPLATE) &&
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
is_same_net6(link_address, &c->start6, c->prefix) &&
is_same_net6(link_address, &c->end6, c->prefix))
{
@@ -155,7 +155,8 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
return 0;
/* copy header stuff into reply message and set type to reply */
outmsgtypep = put_opt6(inbuff, 34);
if (!(outmsgtypep = put_opt6(inbuff, 34)))
return 0;
*outmsgtypep = DHCP6RELAYREPL;
/* look for relay options and set tags if found. */
@@ -252,7 +253,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
state.tags = &v6_id;
/* copy over transaction-id, and save pointer to message type */
outmsgtypep = put_opt6(inbuff, 4);
if (!(outmsgtypep = put_opt6(inbuff, 4)))
return 0;
start_opts = save_counter(-1);
state.xid = outmsgtypep[3] | outmsgtypep[2] << 8 | outmsgtypep[1] << 16;
@@ -574,7 +576,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
/* set unless we're sending a particular prefix-class, when we
want only dhcp-ranges with the correct tags set and not those without any tags. */
int plain_range = 1;
u32 lease_time, requested_time;
u32 lease_time;
struct dhcp_lease *ltmp;
struct in6_addr *req_addr;
struct in6_addr addr;
@@ -645,8 +647,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
req_addr = opt6_ptr(ia_option, 0);
requested_time = opt6_uint(ia_option, 16, 4);
if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
{
lease_time = c->lease_time;
@@ -670,7 +671,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now);
add_address(&state, c, lease_time, ia_option, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr);
get_context_tag(&state, c);
address_assigned = 1;
@@ -694,7 +695,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, lease_time, lease_time, &min_time, &addr, rapid_commit != NULL, now);
add_address(&state, c, lease_time, NULL, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr);
get_context_tag(&state, c);
address_assigned = 1;
@@ -711,7 +712,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now);
add_address(&state, c, c->lease_time, NULL, &min_time, req_addr, rapid_commit != NULL, now);
mark_context_used(&state, context, req_addr);
get_context_tag(&state, c);
address_assigned = 1;
@@ -725,7 +726,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now);
add_address(&state, c, c->lease_time, NULL, &min_time, &addr, rapid_commit != NULL, now);
mark_context_used(&state, context, &addr);
get_context_tag(&state, c);
address_assigned = 1;
@@ -747,7 +748,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o = new_opt6(OPTION6_PREFERENCE);
put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
end_opt6(o);
tagif = add_options(&state, fallback, context);
tagif = add_options(&state, fallback, context, 0);
}
else
{
@@ -788,7 +789,6 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 requested_time = opt6_uint(ia_option, 16, 4);
struct dhcp_context *dynamic, *c;
unsigned int lease_time;
struct in6_addr addr;
@@ -829,7 +829,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
state.send_prefix_class = prefix_class_from_context(c);
#endif
add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now);
add_address(&state, dynamic, lease_time, ia_option, &min_time, req_addr, 1, now);
get_context_tag(&state, dynamic);
address_assigned = 1;
}
@@ -865,7 +865,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available"));
}
tagif = add_options(&state, fallback, context);
tagif = add_options(&state, fallback, context, 0);
break;
}
@@ -893,9 +893,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{
struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
u32 requested_time = opt6_uint(ia_option, 16, 4);
unsigned int preferred_time = 0; /* in case renewal inappropriate */
unsigned int valid_time = 0;
unsigned int preferred_time = opt6_uint(ia_option, 16, 4);
unsigned int valid_time = opt6_uint(ia_option, 20, 4);
char *message = NULL;
struct dhcp_context *this_context;
@@ -915,6 +914,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
put_opt6_short(DHCP6NOBINDING);
put_opt6_string(_("no binding found"));
end_opt6(o1);
preferred_time = valid_time = 0;
break;
}
@@ -932,7 +933,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
else
lease_time = this_context->lease_time;
calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time);
calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time);
lease_set_expires(lease, valid_time, now);
if (state.ia_type == OPTION6_IA_NA && state.hostname)
@@ -949,8 +950,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
message = _("deprecated");
}
else
message = _("address invalid");
{
preferred_time = valid_time = 0;
message = _("address invalid");
}
log6_packet(&state, "DHCPREPLY", req_addr, message);
o1 = new_opt6(OPTION6_IAADDR);
@@ -964,7 +968,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
end_opt6(o);
}
tagif = add_options(&state, fallback, context);
tagif = add_options(&state, fallback, context, 0);
break;
}
@@ -1015,11 +1019,20 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
context->netid.next = NULL;
state.context_tags = &context->netid;
}
/* Similarly, we can't determine domain from address, but if the FQDN is
given in --dhcp-host, we can use that, and failing that we can use the
unqualified configured domain, if any. */
if (state.hostname_auth)
state.send_domain = state.domain;
else
state.send_domain = get_domain6(NULL);
log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname);
if (ignore)
return 0;
*outmsgtypep = DHCP6REPLY;
tagif = add_options(&state, fallback, context);
tagif = add_options(&state, fallback, context, 1);
break;
}
@@ -1169,13 +1182,16 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context)
static struct dhcp_netid *add_options(struct state *state,
struct in6_addr *fallback,
struct dhcp_context *context,
int do_refresh)
{
void *oro;
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
struct dhcp_netid *tagif = option_filter(state->tags, state->context_tags, daemon->dhcp_opts6);
struct dhcp_opt *opt_cfg;
int done_dns = 0, do_encap = 0;
int done_dns = 0, done_refresh = !do_refresh, do_encap = 0;
int i, o, o1;
oro = opt6_find(state->packet_options, state->end, OPTION6_ORO, 0);
@@ -1203,6 +1219,9 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s
if (opt_cfg->len == 0)
continue;
}
if (opt_cfg->opt == OPTION6_REFRESH_TIME)
done_refresh = 1;
o = new_opt6(opt_cfg->opt);
if (opt_cfg->flags & DHOPT_ADDR6)
@@ -1226,15 +1245,35 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s
end_opt6(o);
}
if (daemon->port == NAMESERVER_PORT && !done_dns &&
(!IN6_IS_ADDR_UNSPECIFIED(&context->local6) ||
!IN6_IS_ADDR_UNSPECIFIED(fallback)))
if (daemon->port == NAMESERVER_PORT && !done_dns)
{
o = new_opt6(OPTION6_DNS_SERVER);
if (!add_local_addrs(context))
put_opt6(fallback, IN6ADDRSZ);
end_opt6(o);
}
if (context && !done_refresh)
{
struct dhcp_context *c;
unsigned int lease_time = 0xffffffff;
/* Find the smallest lease tie of all contexts,
subjext to the RFC-4242 stipulation that this must not
be less than 600. */
for (c = context; c; c = c->next)
if (c->lease_time < lease_time)
{
if (c->lease_time < 600)
lease_time = 600;
else
lease_time = c->lease_time;
}
o = new_opt6(OPTION6_REFRESH_TIME);
put_opt6_long(lease_time);
end_opt6(o);
}
/* handle vendor-identifying vendor-encapsulated options,
dhcp-option = vi-encap:13,17,....... */
@@ -1299,16 +1338,18 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s
size_t len = strlen(state->hostname);
if (state->send_domain)
len += strlen(state->send_domain) + 1;
len += strlen(state->send_domain) + 2;
o = new_opt6(OPTION6_FQDN);
if ((p = expand(len + 3)))
if ((p = expand(len + 2)))
{
*(p++) = state->fqdn_flags;
p = do_rfc1035_name(p, state->hostname);
if (state->send_domain)
p = do_rfc1035_name(p, state->send_domain);
*p = 0;
{
p = do_rfc1035_name(p, state->send_domain);
*p = 0;
}
}
end_opt6(o);
}
@@ -1463,14 +1504,21 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
}
}
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, void *ia_option,
unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
{
unsigned int valid_time, preferred_time;
unsigned int valid_time = 0, preferred_time = 0;
int o = new_opt6(OPTION6_IAADDR);
struct dhcp_lease *lease;
calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time);
/* get client requested times */
if (ia_option)
{
preferred_time = opt6_uint(ia_option, 16, 4);
valid_time = opt6_uint(ia_option, 20, 4);
}
calculate_times(context, min_time, &valid_time, &preferred_time, lease_time);
put_opt6(addr, sizeof(*addr));
put_opt6_long(preferred_time);
@@ -1554,22 +1602,60 @@ static int check_address(struct state *state, struct in6_addr *addr)
return 1;
}
/* Calculate valid and preferred times to send in leases/renewals.
Inputs are:
*valid_timep, *preferred_timep - requested times from IAADDR options.
context->valid, context->preferred - times associated with subnet address on local interface.
context->flags | CONTEXT_DEPRECATE - "deprecated" flag in dhcp-range.
lease_time - configured time for context for individual client.
*min_time - smallest valid time sent so far.
Outputs are :
*valid_timep, *preferred_timep - times to be send in IAADDR option.
*min_time - smallest valid time sent so far, to calculate T1 and T2.
*/
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time)
unsigned int *preferred_timep, unsigned int lease_time)
{
unsigned int preferred_time, valid_time;
unsigned int req_preferred = *preferred_timep, req_valid = *valid_timep;
unsigned int valid_time = lease_time, preferred_time = lease_time;
/* RFC 3315: "A server ignores the lifetimes set
by the client if the preferred lifetime is greater than the valid
lifetime. */
if (req_preferred <= req_valid)
{
if (req_preferred != 0)
{
/* 0 == "no preference from client" */
if (req_preferred < 120u)
req_preferred = 120u; /* sanity */
if (req_preferred < preferred_time)
preferred_time = req_preferred;
}
if (req_valid != 0)
/* 0 == "no preference from client" */
{
if (req_valid < 120u)
req_valid = 120u; /* sanity */
if (req_valid < valid_time)
valid_time = req_valid;
}
}
if (requested_time < 120u )
requested_time = 120u; /* sanity */
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = requested_time;
valid_time = (context->valid < lease_time) ? context->valid : lease_time;
preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time;
if (context->flags & CONTEXT_DEPRECATE)
/* deprecate (preferred == 0) which configured, or when local address
is deprecated */
if ((context->flags & CONTEXT_DEPRECATE) || context->preferred == 0)
preferred_time = 0;
if (preferred_time != 0 && preferred_time < *min_time)
*min_time = preferred_time;
@@ -1828,4 +1914,118 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret;
}
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address, u32 scope_id)
{
/* ->local is same value for all relays on ->current chain */
struct all_addr from;
unsigned char *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff;
int hopcount;
struct in6_addr multicast;
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
/* source address == relay address */
from.addr.addr6 = relay->local.addr.addr6;
/* Get hop count from nested relayed message */
if (msg_type == DHCP6RELAYFORW)
hopcount = *((unsigned char *)inbuff+1) + 1;
else
hopcount = 0;
/* RFC 3315 HOP_COUNT_LIMIT */
if (hopcount > 32)
return;
save_counter(0);
if ((header = put_opt6(NULL, 34)))
{
int o;
header[0] = DHCP6RELAYFORW;
header[1] = hopcount;
memcpy(&header[2], &relay->local.addr.addr6, IN6ADDRSZ);
memcpy(&header[18], peer_address, IN6ADDRSZ);
o = new_opt6(OPTION6_RELAY_MSG);
put_opt6(inbuff, sz);
end_opt6(o);
for (; relay; relay = relay->current)
{
union mysockaddr to;
to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
to.in6.sin6_flowinfo = 0;
to.in6.sin6_scope_id = 0;
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr.addr6, &multicast))
{
int multicast_iface;
if (!relay->interface || strchr(relay->interface, '*') ||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
}
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(0), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
}
/* Save this for replies */
relay->iface_index = scope_id;
}
}
}
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
{
struct dhcp_relay *relay;
struct in6_addr link;
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
/* must have at least msg_type+hopcount+link_address+peer_address+minimal size option
which is 1 + 1 + 16 + 16 + 2 + 2 = 38 */
if (sz < 38 || *inbuff != DHCP6RELAYREPL)
return 0;
memcpy(&link, &inbuff[2], IN6ADDRSZ);
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(&link, &relay->local.addr.addr6) &&
(!relay->interface || wildcard_match(relay->interface, arrival_interface)))
break;
save_counter(0);
if (relay)
{
void *opt, *opts = inbuff + 34;
void *end = inbuff + sz;
for (opt = opts; opt; opt = opt6_next(opt, end))
if (opt6_type(opt) == OPTION6_RELAY_MSG && opt6_len(opt) > 0)
{
int encap_type = *((unsigned char *)opt6_ptr(opt, 0));
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
peer->sin6_scope_id = relay->iface_index;
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
}
}
return 0;
}
#endif
+4 -2
View File
@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
lease->slaac_address = NULL;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
if ((context->flags & CONTEXT_RA_NAME) &&
!(context->flags & CONTEXT_OLD) &&
lease->last_interface == context->if_index)
{
struct in6_addr addr = context->start6;
if (lease->hwaddr_len == 6 &&
@@ -123,7 +125,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
time_t next_event = 0;
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
break;
/* nothing configured */
+26 -12
View File
@@ -198,22 +198,36 @@ void tftp_request(struct listener *listen, time_t now)
addra.addr.addr6 = addr.in6.sin6_addr;
#endif
if (!iface_check(listen->family, &addra, name, NULL))
if (daemon->tftp_interfaces)
{
if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces(0);
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
!label_exception(if_index, listen->family, &addra) )
/* dedicated tftp interface list */
for (tmp = daemon->tftp_interfaces; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
break;
if (!tmp)
return;
}
else
{
/* Do the same as DHCP */
if (!iface_check(listen->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) )
return;
}
#ifdef HAVE_DHCP
/* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
return;
/* allowed interfaces are the same as for DHCP */
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, name))
return;
#endif
}
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
@@ -555,7 +569,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
}
/* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */
else if (++transfer->backoff > 5 && len != 0)
else if (++transfer->backoff > 7 && len != 0)
{
endcon = 1;
len = 0;
+4 -5
View File
@@ -151,14 +151,13 @@ int legal_hostname(char *name)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9'))
continue;
if (!first &&
((c >= '0' && c <= '9') ||
c == '-' || c == '_'))
if (!first && (c == '-' || c == '_'))
continue;
/* end of hostname part */
if (c == '.')
return 1;