Compare commits

...
30 Commits
Author SHA1 Message Date
Simon Kelley 353ae4d270 Check assumed SLAAC addresses by pinging them. 2012-03-19 20:07:51 +00:00
Simon Kelley e759d426fa --host-record support 2012-03-16 13:18:57 +00:00
Simon Kelley 40ef23b547 Move DHCP option stuff to dhcp-common.c 2012-03-13 21:59:28 +00:00
Simon Kelley f5e8562f96 More DHCP-option logging tweaks. 2012-03-13 14:22:30 +00:00
Simon Kelley 1567feae3c Log vendor class for DHCPv6 2012-03-12 22:15:35 +00:00
Simon Kelley daf061c9de randomise DHCPv6 lease renewal intervals 2012-03-12 21:57:18 +00:00
Simon Kelley d0e2c6c9ab decode DHCPv4 T1, T2 and lease-time options better. 2012-03-12 21:44:14 +00:00
Simon Kelley 8643ec7fea Update CHANGLEOG 2012-03-12 20:04:14 +00:00
Simon Kelley 5cfea3d402 Tidy last commit. 2012-03-12 17:28:27 +00:00
Simon Kelley 6c8f21e4a4 More useful DHCPv6 packet logging. 2012-03-12 15:06:55 +00:00
Simon Kelley 1d0f91c4a9 Don't trust the port in the source address of requests.
At least one client gets it wrong: always send to the client port for
clients, and the server port for relays.
2012-03-12 11:56:22 +00:00
Simon Kelley 2a82db4caf Supply zero preference in advertise and reply messages 2012-03-10 21:40:10 +00:00
Simon Kelley dd88c17f15 Add status code containing "success" to all IA_TA and IA_NA
which have IAADDR options. This communicates zero information and
RFC3315 is unclear that it's needed, but at least one client seems
to require it.
2012-03-10 20:46:57 +00:00
Simon Kelley 8b37270410 Implement --dhcp-duid 2012-03-09 17:45:10 +00:00
Simon Kelley 760169fc43 Debian updates. 2012-03-09 14:27:49 +00:00
Simon Kelley 7023e38294 Docs changes for ra-names. 2012-03-09 12:05:49 +00:00
Simon Kelley a7cf58cc47 Merge branch 'ra-names' 2012-03-09 11:37:42 +00:00
Simon Kelley e25d1a2ea2 Fix prefix-map build code logic. 2012-03-08 13:24:17 +00:00
Simon Kelley 70969c1757 move #include for Solaris and Apple. 2012-03-07 20:46:28 +00:00
Simon Kelley 3803437dcc tidying 2012-03-07 20:39:40 +00:00
Simon Kelley eabc6dd76a Use getifaddrs on *BSD. 2012-03-07 20:28:20 +00:00
Simon Kelley e28d2e2b77 Merge branch 'getifaddrs' 2012-03-07 20:26:23 +00:00
Simon Kelley 96fafe2ed6 Fixed typos and tested. 2012-03-07 20:25:39 +00:00
Simon Kelley c81d390f84 Update man page to reflect the existance of DHCPv6 and RA. 2012-03-07 19:10:19 +00:00
Simon Kelley 08456c61f6 Use getifaddrs to find interfaces on *BSD 2012-03-07 19:08:11 +00:00
Simon Kelley bc26f9a03f Handle firewire and EUI-64 addresses in the SLAAC code. 2012-03-07 13:13:56 +00:00
Simon Kelley 6ffeff86be Teach emit_dbus_signal() about IPv6 DHCPv6 leases. 2012-03-07 10:32:35 +00:00
Simon Kelley f444cddbaf Don't waste time calculating EUI-64 when a lease doesn't have a name. 2012-03-07 10:15:57 +00:00
Simon Kelley d13191a46c Bump Debian version number. 2012-03-06 19:57:39 +00:00
Simon Kelley 801ca9a7b7 Add ra-names SLAAC-hostnames from DHCPv4 option. 2012-03-06 19:30:17 +00:00
25 changed files with 1256 additions and 546 deletions

No files matched your search

+27
View File
@@ -1,3 +1,30 @@
version 2.61
Re-write interface discovery code on *BSD to use
getifaddrs. This is more portable, more straightforward,
and allows us to find the prefix length for IPv6
addresses.
Add ra-names DHCPv6 keyword which adds AAAA records
for dual-stack hosts which get IPv6 addresses via SLAAC.
Add --dhcp-duid to allow DUID-EN uids to be used.
Explicity send DHCPv6 replies to the correct port, instead
of relying on clients to send requests with the correct
source address, since at least one client in the wild gets
this wrong. Thanks to Conrda Kostecki for help tracking
this down.
Send a preference value of 255 in DHCPv6 replies when
--dhcp-authoritative is in effect. This tells clients not
to wait around for other DHCP servers.
Better logging of DHCPv6 options.
Add --host-record. Thanks to Rob Zwissler for the
suggestion.
version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
Flebbe for the patch.
+1 -1
View File
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o
dhcp-common.o outpacket.o radv.o slaac.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h
+1 -1
View File
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c
radv.c slaac.c
LOCAL_MODULE := dnsmasq
+9
View File
@@ -1,3 +1,12 @@
dnsmasq (2.61-1) unstable; urgency=low
* New upstream.
* Provide "dump-stats" initscript method. (closes: #654656)
* Add (empty) build-indep and build-arch rules targets.
* Bump standards-version to 3.9.3
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Mar 2012 19:45:43 +0000
dnsmasq (2.60-1) unstable; urgency=low
* New upstream.
+1 -1
View File
@@ -3,7 +3,7 @@ Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.2
Standards-Version: 3.9.3
Package: dnsmasq
Architecture: all
Vendored
+4 -1
View File
@@ -256,8 +256,11 @@ case "$1" in
*) log_success_msg "(unknown)" ; exit 4 ;;
esac
;;
dump-stats)
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3
;;
esac
+3
View File
@@ -184,7 +184,10 @@ endef
# Below here is fairly generic really
binary: binary-arch binary-indep
build:
build-arch:
build-indep:
checkroot:
test root = "`whoami`"
+9
View File
@@ -164,6 +164,15 @@
# Do Router Advertisements, BUT NOT DHCP for this subnet.
#dhcp-range=1234::, ra-only
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
# hosts. Use the DHCPv4 lease to derive the name, network segment and
# MAC address and assume that the host will also have an
# IPv6 address calculated using the SLAAC alogrithm.
# This will generate an erroneous AAAA record if a host is using privacy
# extensions or does not support IPv6. Use with care.
#dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet.
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
#dhcp-range=1234::, ra-only, 48h
+39 -2
View File
@@ -23,7 +23,7 @@ options. It includes a secure, read-only,
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
.PP
Dnsmasq
supports IPv6 for DNS and TFTP, but not DHCP.
supports IPv6 for all functions and a minimal router-advertisemnet daemon.
.SH OPTIONS
Note that in general missing parameters are allowed and switch off
functions, for instance "--pid-file" disables writing a PID file. On
@@ -416,6 +416,22 @@ zone files: the port, weight and priority numbers are in a different
order. More than one SRV record for a given service/domain is allowed,
all that match are returned.
.TP
.B --host-record=<name>[,<name>....][<IPv4-address>],[IPv6-address]
Add A, AAAA and PTR records to the DNS. This adds one or more names to
the DNS with associated IPv4 (A) and IPv6 (AAAA) records. A name may
appear in more than one
.B host-record
and therefore be assigned more than one address. Only the first
address creates a PTR record linking the address to the name. This is
the same rule as is used reading hosts-files.
.B host-record
options are considered to be read before host-files, so a name
appearing there inhibits PTR-record creation if it appears in
hosts-file also. Unlike host-files, names are not expanded, even when
.B expand-hosts
is in effect. Short and long names may appear in the same
.B host-record, eg. --host-record=laptop,laptop.thekelleys.org,192.168.0.1,1234::100
.TP
.B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings,
so any number may be included, delimited by commas; use quotes to put
@@ -556,7 +572,18 @@ the keyword
which tells dnsmasq to offer Router Advertisement only on this subnet,
and not DHCP. This applies to IPv6 only, see
.B enable-ra
for details.
for details. Instead, the keyword
.B ra-names
may be used. This does the same at ra-only, but also enables a mode
which gives DNS names to dual-stack hosts which do SLAAC for
IPv6. Dnsmasq uses the hosts IPv4 lease to derive the name, network
segment and MAC address and assumes that the host will also have an
IPv6 address calculated using the SLAAC alogrithm, on the same network
segment. An AAAA record is added to the DNS for this IPv6
address. Note that this is only happens for directly-connected
networks, (not one doing DHCP via a relay) and it will generate an
erroneous AAAA record if a host is using privacy extensions or does
not support IPv6. Use with care.
The interface:<interface name> section is not normally used. See the
NOTES section for details of this.
@@ -1031,6 +1058,16 @@ the tags used to determine them.
.B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information.
.TP
.B --dhcp-duid=<enterprise-id>,<uid>
(IPv6 only) Specify the server persistent UID which the DHCPv6 server
will use. This option is not normally required as dnsmasq creates a
DUID automatically when it is first needed. When given, this option
provides dnsmasq the data required to create a DUID-EN type DUID. Note
that once set, the DUID is stored in the lease database, so to change between DUID-EN and
automatically created DUIDs or vice-versa, the lease database must be
re-intialised. The enterprise-id is assigned by IANA, and the uid is a
string of hex octets unique to a particular device.
.TP
.B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the
executable specified by this option is run. <path>
+50 -97
View File
@@ -17,19 +17,9 @@
#include "dnsmasq.h"
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
static struct iovec ifconf = {
.iov_base = NULL,
.iov_len = 0
};
static struct iovec ifreq = {
.iov_base = NULL,
.iov_len = 0
};
#include <ifaddrs.h>
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
#include <sys/sysctl.h>
#include <net/route.h>
#include <net/if_dl.h>
@@ -50,8 +40,12 @@ int arp_enumerate(void *parm, int (*callback)())
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin2;
struct sockaddr_dl *sdl;
struct iovec buff;
int rc;
buff.iov_base = NULL;
buff.iov_len = 0;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
@@ -67,9 +61,9 @@ int arp_enumerate(void *parm, int (*callback)())
while (1)
{
if (!expand_buf(&ifconf, needed))
if (!expand_buf(&buff, needed))
return 0;
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
errno != ENOMEM)
break;
needed += needed / 8;
@@ -77,7 +71,7 @@ int arp_enumerate(void *parm, int (*callback)())
if (rc == -1)
return 0;
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
{
rtm = (struct rt_msghdr *)next;
sin2 = (struct sockaddr_inarp *)(rtm + 1);
@@ -88,19 +82,14 @@ int arp_enumerate(void *parm, int (*callback)())
return 1;
}
#endif
int iface_enumerate(int family, void *parm, int (*callback)())
{
char *ptr;
struct ifreq *ifr;
struct ifconf ifc;
int fd, errsav, ret = 0;
int lastlen = 0;
size_t len = 0;
struct ifaddrs *head, *addrs;
int errsav, ret = 0;
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
return arp_enumerate(parm, callback);
@@ -112,95 +101,62 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (family == AF_LOCAL)
family = AF_LINK;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
if (getifaddrs(&head) == -1)
return 0;
while(1)
{
len += 10*sizeof(struct ifreq);
if (!expand_buf(&ifconf, len))
goto err;
ifc.ifc_len = len;
ifc.ifc_buf = ifconf.iov_base;
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
{
if (errno != EINVAL || lastlen != 0)
goto err;
}
else
{
if (ifc.ifc_len == lastlen)
break; /* got a big enough buffer now */
lastlen = ifc.ifc_len;
}
}
for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
{
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
len = sizeof(struct ifreq);
#ifdef HAVE_SOCKADDR_SA_LEN
ifr = (struct ifreq *)ptr;
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#endif
if (!expand_buf(&ifreq, len))
goto err;
ifr = (struct ifreq *)ifreq.iov_base;
memcpy(ifr, ptr, len);
if (ifr->ifr_addr.sa_family == family)
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)
continue;
if (family == AF_INET)
{
struct in_addr addr, netmask, broadcast;
broadcast.s_addr = 0;
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
continue;
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (!((*callback)(addr,
(int)if_nametoindex(ifr->ifr_name),
netmask, broadcast,
parm)))
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
goto err;
}
#ifdef HAVE_IPV6
else if (family == AF_INET6)
{
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
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;
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)
break;
/* voodoo to clear interface field in address */
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
/* We have no way to determine the prefix, so we assume it's 64 for now....... */
if (!((*callback)(addr, 64,
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
(int)if_nametoindex(ifr->ifr_name), 0,
parm)))
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
goto err;
}
}
#endif
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
/* Assume ethernet again here */
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
if (sdl->sdl_alen != 0 && !((*callback)((int)if_nametoindex(ifr->ifr_name),
ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
if (sdl->sdl_alen != 0 &&
!((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
goto err;
}
#endif
@@ -211,7 +167,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
err:
errsav = errno;
close(fd);
freeifaddrs(head);
errno = errsav;
return ret;
@@ -228,13 +184,10 @@ void init_bpf(void)
while (1)
{
/* useful size which happens to be sufficient */
if (expand_buf(&ifreq, sizeof(struct ifreq)))
{
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
return;
}
sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
return;
if (errno != EBUSY)
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
}
+41 -22
View File
@@ -634,10 +634,11 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
return NULL;
}
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
unsigned short flags, int index, struct crec **rhash, int hashsz)
int index, struct crec **rhash, int hashsz)
{
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
struct crec *lookup = cache_find_by_name(NULL, cache_get_name(cache), 0, cache->flags & (F_IPV4 | F_IPV6));
int i, nameexists = 0;
struct cname *a;
unsigned int j;
@@ -670,10 +671,10 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
for (lookup = rhash[j]; lookup; lookup = lookup->next)
if ((lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
if ((lookup->flags & cache->flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
cache->flags &= ~F_REVERSE;
break;
}
@@ -684,7 +685,6 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
rhash[j] = cache;
}
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
@@ -692,7 +692,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
/* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists)
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) &&
if (hostname_isequal(cache_get_name(cache), a->target) &&
(lookup = whine_malloc(sizeof(struct crec))))
{
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
@@ -771,26 +771,19 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
{
lineno++;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
domain_suffix = get_domain6(&addr.addr.addr6);
}
#else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
}
#endif
else
{
@@ -830,13 +823,15 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
strcpy(cache->name.sname, canon);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
cache->flags = flags;
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
cache->flags = flags;
add_hosts_entry(cache, &addr, addrlen, index, rhash, hashsz);
name_count++;
}
free(canon);
@@ -860,6 +855,8 @@ void cache_reload(void)
struct crec *cache, **up, *tmp;
int revhashsz, i, total_size = daemon->cachesize;
struct hostsfile *ah;
struct host_record *hr;
struct name_list *nl;
cache_inserted = cache_live_freed = 0;
@@ -886,6 +883,34 @@ void cache_reload(void)
up = &cache->hash_next;
}
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
/* Do host_records in config. */
for (hr = daemon->host_records; hr; hr = hr->next)
for (nl = hr->names; nl; nl = nl->next)
{
if (hr->addr.s_addr != 0 &&
(cache = whine_malloc(sizeof(struct crec))))
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr, INADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
}
#ifdef HAVE_IPV6
if (!IN6_IS_ADDR_UNSPECIFIED(&hr->addr6) &&
(cache = whine_malloc(sizeof(struct crec))))
{
cache->name.namep = nl->name;
cache->flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6 | F_NAMEP | F_CONFIG;
add_hosts_entry(cache, (struct all_addr *)&hr->addr6, IN6ADDRSZ, 0, (struct crec **)daemon->packet, revhashsz);
}
#endif
}
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
{
if (daemon->cachesize > 0)
@@ -893,12 +918,6 @@ void cache_reload(void)
return;
}
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
+18 -9
View File
@@ -396,7 +396,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
char *action_str, *addr, *mac = daemon->namebuff;
char *action_str, *mac = daemon->namebuff;
unsigned char *p;
int i;
@@ -406,10 +406,21 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
if (!hostname)
hostname = "";
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
{
print_mac(mac, lease->clid, lease->clid_len);
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
}
else
#endif
{
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
}
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
@@ -419,14 +430,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
else
return;
addr = inet_ntoa(lease->addr);
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;
dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL);
+301
View File
@@ -444,4 +444,305 @@ void join_multicast(void)
}
#endif
static const struct opttab_t {
char *name;
u16 val, size;
} opttab[] = {
{ "netmask", 1, OT_ADDR_LIST },
{ "time-offset", 2, 4 },
{ "router", 3, OT_ADDR_LIST },
{ "dns-server", 6, OT_ADDR_LIST },
{ "log-server", 7, OT_ADDR_LIST },
{ "lpr-server", 9, OT_ADDR_LIST },
{ "hostname", 12, OT_INTERNAL | OT_NAME },
{ "boot-file-size", 13, 2 | OT_DEC },
{ "domain-name", 15, OT_NAME },
{ "swap-server", 16, OT_ADDR_LIST },
{ "root-path", 17, OT_NAME },
{ "extension-path", 18, OT_NAME },
{ "ip-forward-enable", 19, 1 },
{ "non-local-source-routing", 20, 1 },
{ "policy-filter", 21, OT_ADDR_LIST },
{ "max-datagram-reassembly", 22, 2 | OT_DEC },
{ "default-ttl", 23, 1 | OT_DEC },
{ "mtu", 26, 2 | OT_DEC },
{ "all-subnets-local", 27, 1 },
{ "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
{ "router-discovery", 31, 1 },
{ "router-solicitation", 32, OT_ADDR_LIST },
{ "static-route", 33, OT_ADDR_LIST },
{ "trailer-encapsulation", 34, 1 },
{ "arp-timeout", 35, 4 | OT_DEC },
{ "ethernet-encap", 36, 1 },
{ "tcp-ttl", 37, 1 },
{ "tcp-keepalive", 38, 4 | OT_DEC },
{ "nis-domain", 40, OT_NAME },
{ "nis-server", 41, OT_ADDR_LIST },
{ "ntp-server", 42, OT_ADDR_LIST },
{ "vendor-encap", 43, OT_INTERNAL },
{ "netbios-ns", 44, OT_ADDR_LIST },
{ "netbios-dd", 45, OT_ADDR_LIST },
{ "netbios-nodetype", 46, 1 },
{ "netbios-scope", 47, 0 },
{ "x-windows-fs", 48, OT_ADDR_LIST },
{ "x-windows-dm", 49, OT_ADDR_LIST },
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
{ "lease-time", 51, OT_INTERNAL | OT_DEC },
{ "option-overload", 52, OT_INTERNAL },
{ "message-type", 53, OT_INTERNAL | OT_DEC },
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_INTERNAL | OT_DEC},
{ "T2", 59, OT_INTERNAL | OT_DEC},
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
{ "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_NAME },
{ "bootfile-name", 67, OT_NAME },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
{ "smtp-server", 69, OT_ADDR_LIST },
{ "pop3-server", 70, OT_ADDR_LIST },
{ "nntp-server", 71, OT_ADDR_LIST },
{ "irc-server", 74, OT_ADDR_LIST },
{ "user-class", 77, 0 },
{ "FQDN", 81, OT_INTERNAL },
{ "agent-id", 82, OT_INTERNAL },
{ "client-arch", 93, 2 | OT_DEC },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "vendor-id-encap", 125, 0 },
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
{ NULL, 0, 0 }
};
#ifdef HAVE_DHCP6
static const struct opttab_t opttab6[] = {
{ "client-id", 1, OT_INTERNAL },
{ "server-id", 2, OT_INTERNAL },
{ "ia-na", 3, OT_INTERNAL },
{ "ia-ta", 4, OT_INTERNAL },
{ "iaaddr", 5, OT_INTERNAL },
{ "oro", 6, OT_INTERNAL },
{ "preference", 7, OT_INTERNAL | OT_DEC },
{ "unicast", 12, OT_INTERNAL },
{ "status", 13, OT_INTERNAL },
{ "rapid-commit", 14, OT_INTERNAL },
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
{ "vendor-opts", 17, OT_INTERNAL },
{ "sip-server-domain", 21, OT_RFC1035_NAME },
{ "sip-server", 22, OT_ADDR_LIST },
{ "dns-server", 23, OT_ADDR_LIST },
{ "domain-search", 24, OT_RFC1035_NAME },
{ "nis-server", 27, OT_ADDR_LIST },
{ "nis+-server", 28, OT_ADDR_LIST },
{ "nis-domain", 29, OT_RFC1035_NAME },
{ "nis+-domain", 30, OT_RFC1035_NAME },
{ "sntp-server", 31, OT_ADDR_LIST },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 }
};
#endif
void display_opts(void)
{
int i;
printf(_("Known DHCP options:\n"));
for (i = 0; opttab[i].name; i++)
if (!(opttab[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab[i].val, opttab[i].name);
}
#ifdef HAVE_DHCP6
void display_opts6(void)
{
int i;
printf(_("Known DHCPv6 options:\n"));
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
}
#endif
u16 lookup_dhcp_opt(int prot, char *name)
{
const struct opttab_t *t;
int i;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
else
#endif
t = opttab;
for (i = 0; t[i].name; i++)
if (!(t[i].size & OT_INTERNAL) &&
strcasecmp(t[i].name, name) == 0)
return t[i].val;
return 0;
}
u16 lookup_dhcp_len(int prot, u16 val)
{
const struct opttab_t *t;
int i;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
else
#endif
t = opttab;
for (i = 0; t[i].name; i++)
if (val == t[i].val)
{
if (t[i].size & OT_INTERNAL)
return 0;
return t[i].size & ~OT_DEC;
}
return 0;
}
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
{
int o, i, j, nodecode = 0;
const struct opttab_t *ot = opttab;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
ot = opttab6;
#endif
for (o = 0; ot[o].name; o++)
if (ot[o].val == opt)
{
if (buf)
{
memset(buf, 0, buf_len);
if (ot[o].size & OT_ADDR_LIST)
{
struct all_addr addr;
int addr_len = INADDRSZ;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
addr_len = IN6ADDRSZ;
#endif
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
{
if (i != 0)
strncat(buf, ", ", buf_len - strlen(buf));
/* align */
memcpy(&addr, &val[i], addr_len);
inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
}
}
else if (ot[o].size & OT_NAME)
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
{
char c = val[i];
if (isprint((int)c))
buf[j++] = c;
}
#ifdef HAVE_DHCP6
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
{
i = 0, j = 0;
while (i < opt_len && val[i] != 0)
{
int k, l = i + val[i] + 1;
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
{
char c = val[k];
if (isprint((int)c))
buf[j++] = c;
}
i = l;
if (val[i] != 0 && j < buf_len)
buf[j++] = '.';
}
}
else if ((ot[o].size & OT_CSTRING))
{
int k, len;
unsigned char *p;
i = 0, j = 0;
while (1)
{
p = &val[i];
GETSHORT(len, p);
for (k = 0; k < len && j < buf_len; k++)
{
char c = *p++;
if (isprint((int)c))
buf[j++] = c;
}
i += len +2;
if (i >= opt_len)
break;
if (j < buf_len)
buf[j++] = ',';
}
}
#endif
else if ((ot[o].size & OT_DEC) && opt_len != 0)
{
unsigned int dec = 0;
for (i = 0; i < opt_len; i++)
dec = (dec << 8) | val[i];
sprintf(buf, "%u", dec);
}
else
nodecode = 1;
}
break;
}
if (opt_len != 0 && buf && (!ot[o].name || nodecode))
{
int trunc = 0;
if (opt_len > 14)
{
trunc = 1;
opt_len = 14;
}
print_mac(buf, val, opt_len);
if (trunc)
strncat(buf, "...", buf_len - strlen(buf));
}
return ot[o].name ? ot[o].name : "";
}
#endif
+1 -1
View File
@@ -299,7 +299,7 @@ void dhcp_packet(time_t now, int pxe_fd)
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();
lease_update_dns(0);
if (iov.iov_len == 0)
return;
+35 -13
View File
@@ -75,6 +75,7 @@ void dhcp6_packet(time_t now)
ssize_t sz;
struct ifreq ifr;
struct iname *tmp;
unsigned short port;
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
@@ -84,7 +85,7 @@ void dhcp6_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1 || sz <= 4)
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
@@ -134,15 +135,23 @@ void dhcp6_packet(time_t now)
lease_prune(NULL, now); /* lose any expired leases */
sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
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();
lease_update_dns(0);
if (sz != 0)
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
/* 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
server port to a relay. */
if (port != 0)
{
from.sin6_port = htons(port);
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
retry_send());
}
}
static int complete_context6(struct in6_addr *local, int prefix,
@@ -365,13 +374,26 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
void make_duid(time_t now)
{
/* rebase epoch to 1/1/2000 */
time_t newnow = now - 946684800;
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
if(!daemon->duid)
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
if (daemon->duid_config)
{
unsigned char *p;
daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
daemon->duid_len = daemon->duid_config_len + 6;
PUTSHORT(2, p); /* DUID_EN */
PUTLONG(daemon->duid_enterprise, p);
memcpy(p, daemon->duid_config, daemon->duid_config_len);
}
else
{
/* rebase epoch to 1/1/2000 */
time_t newnow = now - 946684800;
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
if(!daemon->duid)
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
}
}
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
+43 -17
View File
@@ -23,6 +23,7 @@ struct daemon *daemon;
static volatile pid_t pid = 0;
static volatile int pipewrite;
static int alarm_queued = 0;
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
static void check_dns_listeners(fd_set *set, time_t now);
@@ -106,16 +107,14 @@ int main (int argc, char **argv)
else
open("/dev/null", O_RDWR);
#ifdef HAVE_LINUX_NETWORK
netlink_init();
#elif !(defined(IP_RECVDSTADDR) && \
defined(IP_RECVIF) && \
defined(IP_SENDSRCADDR))
#ifndef HAVE_LINUX_NETWORK
# if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
if (!option_bool(OPT_NOWILD))
{
bind_fallback = 1;
set_option_bool(OPT_NOWILD);
}
# endif
#endif
#ifndef HAVE_TFTP
@@ -180,10 +179,25 @@ int main (int argc, char **argv)
if (daemon->dhcp6)
dhcp6_init();
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
# endif
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
netlink_init();
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces(now);
#endif
if (!enumerate_interfaces())
@@ -552,6 +566,8 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_RA_NAME) ?
_("router advertisement with DHCPv4-derived names on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
_("router advertisement only on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
@@ -849,9 +865,23 @@ static void sig_handler(int sig)
}
}
void send_alarm(void)
/* now == 0 -> queue immediate callback */
void send_alarm(time_t event, time_t now)
{
send_event(pipewrite, EVENT_ALARM, 0, NULL);
if (now != 0 && event == 0)
return;
if ((now == 0 || difftime(event, now) <= 0.0))
{
if (!alarm_queued)
{
send_event(pipewrite, EVENT_ALARM, 0, NULL);
alarm_queued = 1;
}
}
else
alarm((unsigned)difftime(event, now));
}
void send_event(int fd, int event, int data, char *msg)
@@ -965,6 +995,7 @@ static void async_event(int pipe, time_t now)
break;
case EVENT_ALARM:
alarm_queued = 0;
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
{
@@ -973,13 +1004,8 @@ static void async_event(int pipe, time_t now)
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
#endif
#endif
break;
@@ -1143,7 +1169,7 @@ void clear_cache_and_reload(time_t now)
check_dhcp_hosts(0);
lease_update_from_configs();
lease_update_file(now);
lease_update_dns();
lease_update_dns(1);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
+59 -8
View File
@@ -274,6 +274,18 @@ struct cname {
struct cname *next;
};
struct host_record {
struct name_list {
char *name;
struct name_list *next;
} *names;
struct in_addr addr;
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
struct host_record *next;
};
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
@@ -432,6 +444,15 @@ struct frec {
struct frec *next;
};
/* flags in top of length field for DHCP-option tables */
#define OT_ADDR_LIST 0x8000
#define OT_RFC1035_NAME 0x4000
#define OT_INTERNAL 0x2000
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
#define OT_DEC 0x0400
/* actions in the daemon->helper RPC */
#define ACTION_DEL 1
#define ACTION_OLD_HOSTNAME 2
@@ -445,6 +466,7 @@ struct frec {
#define LEASE_USED 16 /* used this DHCPv6 transaction */
#define LEASE_NA 32 /* IPv6 no-temporary lease */
#define LEASE_TA 64 /* IPv6 temporary lease */
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
struct dhcp_lease {
int clid_len; /* length of client identifier */
@@ -462,6 +484,14 @@ struct dhcp_lease {
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
#ifdef HAVE_DHCP6
struct slaac_address {
struct in6_addr addr, local;
time_t ping_time;
int backoff; /* zero -> confirmed */
struct slaac_address *next;
} *slaac_address;
#endif
struct dhcp_lease *next;
};
@@ -606,7 +636,7 @@ struct dhcp_context {
#ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix;
int prefix, if_index;
time_t ra_time;
#endif
int flags;
@@ -621,6 +651,7 @@ struct dhcp_context {
#define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
struct ping_result {
struct in_addr addr;
@@ -678,6 +709,7 @@ extern struct daemon {
struct naptr *naptr;
struct txt_record *txt;
struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail;
struct cname *cnames;
struct interface_name *int_names;
char *mxtarget;
@@ -723,6 +755,8 @@ extern struct daemon {
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */
int tftp_unlimited;
unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config;
/* globally used stuff for DNS */
char *packet; /* packet buffer */
@@ -925,7 +959,7 @@ char *host_from_dns(struct in_addr addr);
/* lease.c */
#ifdef HAVE_DHCP
void lease_update_file(time_t now);
void lease_update_dns();
void lease_update_dns(int force);
void lease_init(time_t now);
struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6
@@ -934,12 +968,13 @@ struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len);
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface);
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
@@ -948,6 +983,7 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
void lease_find_interfaces(time_t now);
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim);
@@ -967,7 +1003,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
#endif
void send_alarm(void);
void send_alarm(time_t event, time_t now);
void send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now);
void poll_resolv(int force, int do_reload, time_t now);
@@ -1042,8 +1078,8 @@ void make_duid(time_t now);
/* rfc3315.c */
#ifdef HAVE_DHCP6
size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
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);
#endif
/* dhcp-common.c */
@@ -1059,7 +1095,13 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
void dhcp_update_configs(struct dhcp_config *configs);
void check_dhcp_hosts(int fatal);
void display_opts(void);
u16 lookup_dhcp_opt(int prot, char *name);
u16 lookup_dhcp_len(int prot, u16 val);
char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len);
# ifdef HAVE_DHCP6
void display_opts6(void);
void join_multicast(void);
# endif
#endif
@@ -1082,5 +1124,14 @@ void put_opt6_string(char *s);
void ra_init(time_t now);
void icmp6_packet(void);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now);
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
#endif
/* slaac.c */
#ifdef HAVE_DHCP6
void build_subnet_map(void);
void slaac_add_addrs(struct dhcp_lease *lease, time_t now);
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
void schedule_subnet_map(void);
#endif
+131 -23
View File
@@ -97,7 +97,8 @@ void lease_init(time_t now)
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet,
hw_len, hw_type, clid_len, now);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
@@ -118,7 +119,7 @@ void lease_init(time_t now)
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len, now);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
@@ -175,16 +176,6 @@ void lease_init(time_t now)
file_dirty = 0;
lease_prune(NULL, now);
dns_dirty = 1;
#ifdef HAVE_DHCP6
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (!daemon->duid && daemon->dhcp6)
{
file_dirty = 1;
make_duid(now);
}
#endif
}
void lease_update_from_configs(void)
@@ -316,9 +307,16 @@ void lease_update_file(time_t now)
next_event = 0;
#ifdef HAVE_DHCP6
/* do timed RAs and determine when the next is */
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
if (daemon->ra_contexts)
next_event = periodic_ra(now);
{
time_t ra_event = periodic_slaac(now, leases);
next_event = periodic_ra(now);
if (next_event == 0 || difftime(next_event, ra_event) > 0.0)
next_event = ra_event;
}
#endif
for (lease = leases; lease; lease = lease->next)
@@ -336,24 +334,104 @@ void lease_update_file(time_t now)
(unsigned int)difftime(next_event, now));
}
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
send_alarm(next_event, now);
}
void lease_update_dns(void)
static int find_interface_v4(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_lease *lease;
if (daemon->port != 0 && dns_dirty)
(void) broadcast;
(void) vparam;
for (lease = leases; lease; lease = lease->next)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net(local, lease->addr, netmask))
lease_set_interface(lease, if_index, *((time_t *)vparam));
return 1;
}
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_lease *lease;
(void)scope;
(void)dad;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
lease_set_interface(lease, if_index, *((time_t *)vparam));
return 1;
}
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
{
slaac_ping_reply(sender, packet, interface, leases);
}
#endif
/* Find interfaces associated with leases at start-up. This gets updated as
we do DHCP transactions, but information about directly-connected subnets
is useful from scrips and necessary for determining SLAAC addresses from
start-time. */
void lease_find_interfaces(time_t now)
{
#ifdef HAVE_DHCP6
build_subnet_map();
#endif
iface_enumerate(AF_INET, &now, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (!daemon->duid && daemon->dhcp6)
{
file_dirty = 1;
make_duid(now);
}
#endif
}
void lease_update_dns(int force)
{
struct dhcp_lease *lease;
if (daemon->port != 0 && (dns_dirty || force))
{
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
int prot = AF_INET;
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6;
else if (lease->hostname || lease->fqdn)
{
struct slaac_address *slaac;
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
if (slaac->backoff == 0)
{
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
}
}
#endif
if (lease->fqdn)
@@ -621,8 +699,13 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
}
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len)
unsigned char *clid, int hw_len, int hw_type, int clid_len, time_t now)
{
#ifdef HAVE_DHCP6
int change = 0;
lease->flags |= LEASE_HAVE_HWADDR;
#endif
if (hw_len != lease->hwaddr_len ||
hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
@@ -633,6 +716,9 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
lease->hwaddr_type = hw_type;
lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */
#ifdef HAVE_DHCP6
change = 1;
#endif
}
/* only update clid when one is available, stops packets
@@ -650,17 +736,27 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len)))
return;
#ifdef HAVE_DHCP6
change = 1;
#endif
}
else if (memcmp(lease->clid, clid, clid_len) != 0)
{
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
#ifdef HAVE_DHCP6
change = 1;
#endif
}
lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len);
}
#ifdef HAVE_DHCP6
if (change)
slaac_add_addrs(lease, now);
#endif
}
static void kill_name(struct dhcp_lease *lease)
@@ -778,13 +874,17 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *do
lease->flags |= LEASE_CHANGED; /* run script on change */
}
void lease_set_interface(struct dhcp_lease *lease, int interface)
void lease_set_interface(struct dhcp_lease *lease, int interface, time_t now)
{
if (lease->last_interface == interface)
return;
lease->last_interface = interface;
lease->flags |= LEASE_CHANGED;
#ifdef HAVE_DHCP6
slaac_add_addrs(lease, now);
#endif
}
void rerun_scripts(void)
@@ -827,6 +927,14 @@ int do_script_run(time_t now)
}
else
{
#ifdef HAVE_DHCP6
struct slaac_address *slaac, *tmp;
for (slaac = lease->slaac_address; slaac; slaac = tmp)
{
tmp = slaac->next;
free(slaac);
}
#endif
kill_name(lease);
#ifdef HAVE_SCRIPT
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
+3 -2
View File
@@ -345,10 +345,11 @@ static void nl_routechange(struct nlmsghdr *h)
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
ra_start_unsolicted(dnsmasq_time());
schedule_subnet_map();
ra_start_unsolicted(dnsmasq_time(), NULL);
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm();
send_alarm(0, 0);
}
#endif
+94 -295
View File
@@ -115,6 +115,8 @@ struct myoption {
#define LOPT_FQDN 304
#define LOPT_LUASCRIPT 305
#define LOPT_RA 306
#define LOPT_DUID 307
#define LOPT_HOST_REC 308
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -235,6 +237,8 @@ static const struct myoption opts[] =
{ "dhcp-client-update", 0, 0, LOPT_FQDN },
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
{ "enable-ra", 0, 0, LOPT_RA },
{ "dhcp-duid", 1, 0, LOPT_DUID },
{ "host-record", 1, 0, LOPT_HOST_REC },
{ NULL, 0, 0, 0 }
};
@@ -362,242 +366,11 @@ 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_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 },
{ 0, 0, NULL, NULL, NULL }
};
#ifdef HAVE_DHCP
#define OT_ADDR_LIST 0x8000
#define OT_RFC1035_NAME 0x4000
#define OT_INTERNAL 0x2000
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
static const struct opttab_t {
char *name;
u16 val, size;
} opttab[] = {
{ "netmask", 1, OT_ADDR_LIST },
{ "time-offset", 2, 4 },
{ "router", 3, OT_ADDR_LIST },
{ "dns-server", 6, OT_ADDR_LIST },
{ "log-server", 7, OT_ADDR_LIST },
{ "lpr-server", 9, OT_ADDR_LIST },
{ "hostname", 12, OT_INTERNAL | OT_NAME },
{ "boot-file-size", 13, 2 },
{ "domain-name", 15, OT_NAME },
{ "swap-server", 16, OT_ADDR_LIST },
{ "root-path", 17, OT_NAME },
{ "extension-path", 18, OT_NAME },
{ "ip-forward-enable", 19, 1 },
{ "non-local-source-routing", 20, 1 },
{ "policy-filter", 21, OT_ADDR_LIST },
{ "max-datagram-reassembly", 22, 2 },
{ "default-ttl", 23, 1 },
{ "mtu", 26, 2 },
{ "all-subnets-local", 27, 1 },
{ "broadcast", 28, OT_INTERNAL | OT_ADDR_LIST },
{ "router-discovery", 31, 1 },
{ "router-solicitation", 32, OT_ADDR_LIST },
{ "static-route", 33, OT_ADDR_LIST },
{ "trailer-encapsulation", 34, 1 },
{ "arp-timeout", 35, 4 },
{ "ethernet-encap", 36, 1 },
{ "tcp-ttl", 37, 1 },
{ "tcp-keepalive", 38, 4 },
{ "nis-domain", 40, OT_NAME },
{ "nis-server", 41, OT_ADDR_LIST },
{ "ntp-server", 42, OT_ADDR_LIST },
{ "vendor-encap", 43, OT_INTERNAL },
{ "netbios-ns", 44, OT_ADDR_LIST },
{ "netbios-dd", 45, OT_ADDR_LIST },
{ "netbios-nodetype", 46, 1 },
{ "netbios-scope", 47, 0 },
{ "x-windows-fs", 48, OT_ADDR_LIST },
{ "x-windows-dm", 49, OT_ADDR_LIST },
{ "requested-address", 50, OT_INTERNAL | OT_ADDR_LIST },
{ "lease-time", 51, OT_INTERNAL },
{ "option-overload", 52, OT_INTERNAL },
{ "message-type", 53, OT_INTERNAL, },
{ "server-identifier", 54, OT_INTERNAL | OT_ADDR_LIST },
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_INTERNAL },
{ "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
{ "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_NAME },
{ "bootfile-name", 67, OT_NAME },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
{ "smtp-server", 69, OT_ADDR_LIST },
{ "pop3-server", 70, OT_ADDR_LIST },
{ "nntp-server", 71, OT_ADDR_LIST },
{ "irc-server", 74, OT_ADDR_LIST },
{ "user-class", 77, 0 },
{ "FQDN", 81, OT_INTERNAL },
{ "agent-id", 82, OT_INTERNAL },
{ "client-arch", 93, 2 },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "vendor-id-encap", 125, 0 },
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
{ NULL, 0, 0 }
};
#ifdef HAVE_DHCP6
static const struct opttab_t opttab6[] = {
{ "client-id", 1, OT_INTERNAL },
{ "server-id", 2, OT_INTERNAL },
{ "ia-na", 3, OT_INTERNAL },
{ "ia-ta", 4, OT_INTERNAL },
{ "iaaddr", 5, OT_INTERNAL },
{ "oro", 6, OT_INTERNAL },
{ "preference", 7, OT_INTERNAL },
{ "unicast", 12, OT_INTERNAL },
{ "status-code", 13, OT_INTERNAL },
{ "rapid-commit", 14, OT_INTERNAL },
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
{ "vendor-opts", 17, OT_INTERNAL },
{ "sip-server-domain", 21, OT_RFC1035_NAME },
{ "sip-server", 22, OT_ADDR_LIST },
{ "dns-server", 23, OT_ADDR_LIST },
{ "domain-search", 24, OT_RFC1035_NAME },
{ "nis-server", 27, OT_ADDR_LIST },
{ "nis+-server", 28, OT_ADDR_LIST },
{ "nis-domain", 29, OT_RFC1035_NAME },
{ "nis+-domain", 30, OT_RFC1035_NAME },
{ "sntp-server", 31, OT_ADDR_LIST },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 }
};
#endif
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
{
int o, i, j, nodecode = 0;
const struct opttab_t *ot = opttab;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
ot = opttab6;
#endif
for (o = 0; ot[o].name; o++)
if (ot[o].val == opt)
{
if (buf)
{
memset(buf, 0, buf_len);
if (ot[o].size & OT_ADDR_LIST)
{
struct all_addr addr;
int addr_len = INADDRSZ;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
addr_len = IN6ADDRSZ;
#endif
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
{
if (i != 0)
strncat(buf, ", ", buf_len - strlen(buf));
/* align */
memcpy(&addr, &val[i], addr_len);
inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
}
}
else if (ot[o].size & OT_NAME)
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
{
char c = val[i];
if (isprint((int)c))
buf[j++] = c;
}
#ifdef HAVE_DHCP6
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
{
i = 0, j = 0;
while (i < opt_len && val[i] != 0)
{
int k, l = i + val[i] + 1;
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
{
char c = val[k];
if (isprint((int)c))
buf[j++] = c;
}
i = l;
if (val[i] != 0 && j < buf_len)
buf[j++] = '.';
}
}
else if ((ot[o].size & OT_CSTRING))
{
int k, len;
unsigned char *p;
i = 0, j = 0;
while (1)
{
p = &val[i];
GETSHORT(len, p);
for (k = 0; k < len && j < buf_len; k++)
{
char c = *p++;
if (isprint((int)c))
buf[j++] = c;
}
i += len +2;
if (i >= opt_len)
break;
if (j < buf_len)
buf[j++] = ',';
}
}
#endif
else
nodecode = 1;
}
break;
}
if (buf && (!ot[o].name || nodecode))
{
int trunc = 0;
if (opt_len > 13)
{
trunc = 1;
opt_len = 13;
}
print_mac(buf, val, opt_len);
if (trunc)
strncat(buf, "...", buf_len - strlen(buf));
}
return ot[o].name ? ot[o].name : "";
}
#endif
/* We hide metacharaters in quoted strings by mapping them into the ASCII control
character space. Note that the \0, \t \b \r \033 and \n characters are carefully placed in the
following sequence so that they map to themselves: it is therefore possible to call
@@ -820,29 +593,6 @@ static void do_usage(void)
}
#ifdef HAVE_DHCP
static void display_opts(void)
{
int i;
printf(_("Known DHCP options:\n"));
for (i = 0; opttab[i].name; i++)
if (!(opttab[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab[i].val, opttab[i].name);
}
#ifdef HAVE_DHCP6
static void display_opts6(void)
{
int i;
printf(_("Known DHCPv6 options:\n"));
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
}
#endif
static int is_tag_prefix(char *arg)
{
@@ -865,7 +615,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
char lenchar = 0, *cp;
int i, addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
char *comma = NULL, *problem = NULL;
struct dhcp_netid *np = NULL;
u16 opt_len = 0;
@@ -894,14 +644,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (strstr(arg, "option:") == arg)
{
for (i = 0; opttab[i].name; i++)
if (!(opttab[i].size & OT_INTERNAL) &&
strcasecmp(opttab[i].name, arg+7) == 0)
{
new->opt = opttab[i].val;
opt_len = opttab[i].size;
break;
}
new->opt = lookup_dhcp_opt(AF_INET, arg+7);
opt_len = lookup_dhcp_len(AF_INET, new->opt);
/* option:<optname> must follow tag and vendor string. */
break;
}
@@ -918,14 +662,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
opt_len = 0;
}
else
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL) &&
strcasecmp(opttab6[i].name, arg+8) == 0)
{
new->opt = opttab6[i].val;
opt_len = opttab6[i].size;
break;
}
{
new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
}
/* option6:<opt>|<optname> must follow tag and vendor string. */
is6 = 1;
break;
@@ -974,28 +714,14 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (opt_len == 0 &&
!(new->flags & DHOPT_RFC3925))
for (i = 0; opttab6[i].name; i++)
if (new->opt == opttab6[i].val)
{
opt_len = opttab6[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
opt_len = lookup_dhcp_len(AF_INET6 ,new->opt);
}
else
#endif
if (opt_len == 0 &&
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
for (i = 0; opttab[i].name; i++)
if (new->opt == opttab[i].val)
{
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
opt_len = lookup_dhcp_len(AF_INET ,new->opt);
/* option may be missing with rfc3925 match */
if (new->opt == 0)
problem = _("bad dhcp-option");
@@ -1259,10 +985,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
else if (comma && (opt_len & OT_CSTRING))
{
/* length fields are two bytes so need 16 bits for each string */
int commas = 1;
int i, commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
for (i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
@@ -1287,10 +1013,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
int commas = 1;
int i, commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
for (i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
@@ -2345,6 +2071,11 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_ONLY;
}
else if (strcmp(a[1], "ra-names") == 0)
{
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA_ONLY;
}
else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?';
@@ -2370,7 +2101,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
new->prefix = pref;
leasepos = 3;
if (new->prefix < 64)
if ((new->flags & CONTEXT_RA_ONLY) && new->prefix != 64)
problem = _("prefix must be exactly 64 for RA subnets");
else if (new->prefix < 64)
problem = _("prefix must be at least 64");
}
}
@@ -3040,6 +2773,19 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
break;
#endif
#ifdef HAVE_DHCP6
case LOPT_DUID: /* --dhcp-duid */
if (!(comma = split(arg)) || !atoi_check(arg, (int *)&daemon->duid_enterprise))
problem = _("bad DUID");
else
{
daemon->duid_config_len = parse_hex(comma,(unsigned char *)comma, strlen(comma), NULL, NULL);
daemon->duid_config = opt_malloc(daemon->duid_config_len);
memcpy(daemon->duid_config, comma, daemon->duid_config_len);
}
break;
#endif
case 'V': /* --alias */
{
char *dash, *a[3] = { NULL, NULL, NULL };
@@ -3287,6 +3033,59 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
break;
}
case LOPT_HOST_REC: /* --host-record */
{
struct host_record *new = opt_malloc(sizeof(struct host_record));
memset(new, 0, sizeof(struct host_record));
if (!arg || !(comma = split(arg)))
problem = _("Bad host-record");
else
while (arg)
{
struct all_addr addr;
if (inet_pton(AF_INET, arg, &addr))
new->addr = addr.addr.addr4;
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &addr))
new->addr6 = addr.addr.addr6;
#endif
else
{
int nomem;
char *canon = canonicalise(arg, &nomem);
struct name_list *nl = opt_malloc(sizeof(struct name_list));
if (!canon)
{
problem = _("Bad name in host-record");
break;
}
nl->name = canon;
/* keep order, so that PTR record goes to first name */
nl->next = NULL;
if (!new->names)
new->names = nl;
else
{
struct name_list *tmp;
for (tmp = new->names; tmp->next; tmp = tmp->next);
tmp->next = nl;
}
}
arg = comma;
comma = split(arg);
}
/* Keep list order */
if (!daemon->host_records_tail)
daemon->host_records = new;
else
daemon->host_records_tail->next = new;
new->next = NULL;
daemon->host_records_tail = new;
break;
}
default:
return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
+7 -3
View File
@@ -17,6 +17,13 @@
#define ALL_HOSTS "FF02::1"
#define ALL_ROUTERS "FF02::2"
struct ping_packet {
u8 type, code;
u16 checksum;
u16 identifier;
u16 sequence_no;
};
struct ra_packet {
u8 type, code;
u16 checksum;
@@ -32,9 +39,6 @@ struct prefix_opt {
struct in6_addr prefix;
};
#define ICMP6_ROUTER_SOLICIT 133
#define ICMP6_ROUTER_ADVERT 134
#define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
+35 -15
View File
@@ -55,13 +55,20 @@ void ra_init(time_t now)
#endif
int val = 255; /* radvd uses this value */
socklen_t len = sizeof(int);
struct dhcp_context *context;
/* ensure this is around even if we're not doing DHCPv6 */
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
if (context)
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
@@ -77,21 +84,21 @@ void ra_init(time_t now)
daemon->icmp6fd = fd;
ra_start_unsolicted(now);
ra_start_unsolicted(now, NULL);
}
void ra_start_unsolicted(time_t now)
void ra_start_unsolicted(time_t now, struct dhcp_context *context)
{
struct dhcp_context *context;
/* init timers so that we do ra's for all soon. some ra_times will end up zeroed
/* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
/* range 0 - 5 */
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000);
if (context)
context->ra_time = now;
else
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
@@ -158,7 +165,19 @@ void icmp6_packet(void)
p = (unsigned char *)daemon->outpacket.iov_base;
if (p[0] != ICMP6_ROUTER_SOLICIT || p[1] != 0)
if (p[1] != 0)
return;
if (p[0] == ICMP6_ECHO_REPLY)
{
/* We may be doing RA but not DHCPv4, in which case the lease
database may not exist and we have nothing to do anyway */
if (daemon->dhcp)
lease_ping_reply(&from.sin6_addr, p, interface);
return;
}
if (p[0] != ND_ROUTER_SOLICIT)
return;
/* look for link-layer address option for logging */
@@ -184,7 +203,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
save_counter(0);
ra = expand(sizeof(struct ra_packet));
ra->type = ICMP6_ROUTER_ADVERT;
ra->type = ND_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0;
@@ -238,7 +257,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
addr.sin6_port = htons(IPPROTO_ICMPV6);
if (dest)
{
memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
addr.sin6_addr = *dest;
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
IN6_IS_ADDR_MC_LINKLOCAL(dest))
addr.sin6_scope_id = iface;
@@ -406,7 +425,7 @@ static int iface_search(struct in6_addr *local, int prefix,
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) < 0.0)
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface
@@ -426,4 +445,5 @@ static int iface_search(struct in6_addr *local, int prefix,
return 1; /* keep searching */
}
#endif
+5 -5
View File
@@ -483,14 +483,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{
logaddr = &mess->yiaddr;
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0, now);
if (hostname)
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
now);
lease_set_interface(lease, int_index);
lease_set_interface(lease, int_index, now);
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
@@ -1276,7 +1276,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len);
lease_set_hwaddr(lease, mess->chaddr, clid, mess->hlen, mess->htype, clid_len, now);
/* if all the netids in the ignore_name list are present, ignore client-supplied name */
if (!hostname_auth)
@@ -1310,7 +1310,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index);
lease_set_interface(lease, int_index, now);
if (override.s_addr != 0)
lease->override = override;
@@ -1387,7 +1387,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else
time = (unsigned int)difftime(lease->expires, now);
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
lease_set_interface(lease, int_index);
lease_set_interface(lease, int_index, now);
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
+96 -30
View File
@@ -23,6 +23,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dhcp_netid *tags, struct dhcp_context *context,
int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now);
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in6_addr *addr, int xid, char *iface, char *string);
static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
@@ -34,12 +35,18 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_unicast, time_t now)
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, size_t sz, int is_unicast, time_t now)
{
struct dhcp_netid *relay_tags = NULL;
struct dhcp_vendor *vendor;
int msg_type;
if (sz <= 4)
return 0;
msg_type = *((unsigned char *)daemon->dhcp_packet.iov_base);
/* Mark these so we only match each at most once, to avoid tangled linked lists */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
vendor->netid.next = &vendor->netid;
@@ -47,7 +54,7 @@ size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name
save_counter(0);
if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now))
return save_counter(0);
return msg_type == DHCP6RELAYFORW ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
return 0;
}
@@ -283,6 +290,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
}
if (option_bool(OPT_LOG_OPTS) && (opt = opt6_find(packet_options, end, OPTION6_VENDOR_CLASS, 4)))
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %u"), xid, opt6_uint(opt, 0, 4));
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
Otherwise assume the option is an array, and look for a matching element.
If no data given, existance of the option is enough. This code handles
@@ -627,8 +637,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (lease)
{
lease_set_expires(lease, lease_time, now);
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len);
lease_set_interface(lease, interface);
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len, now);
lease_set_interface(lease, interface, now);
if (hostname && ia_type == OPTION6_IA_NA)
{
char *addr_domain = get_domain6(addrp);
@@ -737,6 +747,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{
if (address_assigned)
{
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6SUCCESS);
put_opt6_string("Oh hai from dnsmasq");
end_opt6(o1);
if (ia_type == OPTION6_IA_NA)
{
/* go back an fill in fields in IA_NA option */
@@ -750,7 +765,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
else
{
/* no address, return erro */
/* no address, return error */
o1 = new_opt6(OPTION6_STATUS_CODE);
put_opt6_short(DHCP6NOADDRS);
put_opt6_string("No addresses available");
@@ -758,6 +773,15 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
}
end_opt6(o);
if (address_assigned)
{
/* If --dhcp-authoritative is set, we can tell client not to wait for
other possible servers */
o = new_opt6(OPTION6_PREFERENCE);
put_opt6_char(option_bool(OPT_AUTHORITATIVE) ? 255 : 0);
end_opt6(o);
}
break;
}
@@ -901,9 +925,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (t1cntr != 0)
{
/* go back an fill in fields in IA_NA option */
unsigned int t1 = min_time == 0xffffffff ? 0xffffffff : min_time/2;
unsigned int t2 = min_time == 0xffffffff ? 0xffffffff : (min_time/8) * 7;
int sav = save_counter(t1cntr);
unsigned int t1, t2, fuzz = rand16();
while (fuzz > (min_time/16))
fuzz = fuzz/2;
t1 = min_time == 0xffffffff ? 0xffffffff : min_time/2 - fuzz;
t2 = min_time == 0xffffffff ? 0xffffffff : ((min_time/8)*7) - fuzz;
put_opt6_long(t1);
put_opt6_long(t2);
save_counter(sav);
@@ -1314,31 +1343,68 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
log_tags(tagif, xid);
if (option_bool(OPT_LOG_OPTS))
{
int end_opts = save_counter(-1);
/* must have created at least one option */
if (start_opts != end_opts)
for (opt = daemon->outpacket.iov_base + start_opts; opt; opt = opt6_next(opt, daemon->outpacket.iov_base + end_opts))
{
int offset = 0;
char *optname;
/* account for flag byte on FQDN */
if (opt6_type(opt) == OPTION6_FQDN)
offset = 1;
optname = option_string(AF_INET6, opt6_type(opt), opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
xid, opt6_len(opt), opt6_type(opt), optname, daemon->namebuff);
}
}
log6_opts(0, xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
return 1;
}
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts)
{
void *opt;
char *desc = nest ? "nest" : "sent";
if (start_opts == end_opts)
return;
for (opt = start_opts; opt; opt = opt6_next(opt, end_opts))
{
int type = opt6_type(opt);
void *ia_options = NULL;
char *optname;
if (type == OPTION6_IA_NA)
{
sprintf(daemon->namebuff, "IAID=%u T1=%u T2=%u",
opt6_uint(opt, 0, 4), opt6_uint(opt, 4, 4), opt6_uint(opt, 8, 4));
optname = "ia-na";
ia_options = opt6_ptr(opt, 12);
}
else if (type == OPTION6_IA_TA)
{
sprintf(daemon->namebuff, "IAID=%u", opt6_uint(opt, 0, 4));
optname = "ia-ta";
ia_options = opt6_ptr(opt, 4);
}
else if (type == OPTION6_IAADDR)
{
inet_ntop(AF_INET6, opt6_ptr(opt, 0), daemon->addrbuff, ADDRSTRLEN);
sprintf(daemon->namebuff, "%s PL=%u VL=%u",
daemon->addrbuff, opt6_uint(opt, 16, 4), opt6_uint(opt, 20, 4));
optname = "iaaddr";
ia_options = opt6_ptr(opt, 24);
}
else if (type == OPTION6_STATUS_CODE)
{
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
memcpy(daemon->namebuff + len, opt6_ptr(opt, 2), opt6_len(opt)-2);
daemon->namebuff[len + opt6_len(opt) - 2] = 0;
optname = "status";
}
else
{
/* account for flag byte on FQDN */
int offset = type == OPTION6_FQDN ? 1 : 0;
optname = option_string(AF_INET6, type, opt6_ptr(opt, offset), opt6_len(opt) - offset, daemon->namebuff, MAXDNAME);
}
my_syslog(MS_DHCP | LOG_INFO, "%u %s size:%3d option:%3d %s %s",
xid, desc, opt6_len(opt), type, optname, daemon->namebuff);
if (ia_options)
log6_opts(1, xid, ia_options, opt6_ptr(opt, opt6_len(opt)));
}
}
static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in6_addr *addr, int xid, char *iface, char *string)
{
/* avoid buffer overflow */
+243
View File
@@ -0,0 +1,243 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
static int map_rebuild = 0;
static int ping_id = 0;
void slaac_add_addrs(struct dhcp_lease *lease, time_t now)
{
struct slaac_address *slaac, *old, **up;
struct dhcp_context *context;
if (!(lease->flags & LEASE_HAVE_HWADDR) ||
lease->last_interface == 0 ||
!lease->hostname)
return ;
old = lease->slaac_address;
lease->slaac_address = NULL;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
{
struct in6_addr addr = context->start6;
if (lease->hwaddr_len == 6 &&
(lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
{
/* convert MAC address to EUI-64 */
memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
addr.s6_addr[11] = 0xff;
addr.s6_addr[12] = 0xfe;
}
#if defined(ARPHRD_EUI64)
else if (lease->hwaddr_len == 8 &&
lease->hwaddr_type == ARPHRD_EUI64)
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
#endif
#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
else if (lease->clid_len == 9 &&
lease->clid[0] == ARPHRD_EUI64 &&
lease->hwaddr_type == ARPHRD_IEEE1394)
/* firewire has EUI-64 identifier as clid */
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
#endif
else
continue;
addr.s6_addr[8] ^= 0x02;
/* check if we already have this one */
for (up = &old, slaac = old; slaac; slaac = slaac->next)
{
if (IN6_ARE_ADDR_EQUAL(&addr, &slaac->addr))
{
*up = slaac->next;
break;
}
up = &slaac->next;
}
/* No, make new one */
if (!slaac && (slaac = whine_malloc(sizeof(struct slaac_address))))
{
slaac->ping_time = now;
slaac->backoff = 1;
slaac->addr = addr;
slaac->local = context->local6;
/* Do RA's to prod it */
ra_start_unsolicted(now, context);
}
if (slaac)
{
slaac->next = lease->slaac_address;
lease->slaac_address = slaac;
}
}
/* Free any no reused */
for (; old; old = slaac)
{
slaac = old->next;
free(old);
}
}
time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
{
struct dhcp_context *context;
struct dhcp_lease *lease;
struct slaac_address *slaac;
time_t next_event = 0;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
/* nothing configured */
if (!context)
return 0;
while (ping_id == 0)
ping_id = rand16();
if (map_rebuild)
{
map_rebuild = 0;
build_subnet_map();
}
for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
{
/* confirmed? */
if (slaac->backoff == 0)
continue;
if (difftime(slaac->ping_time, now) <= 0.0)
{
struct ping_packet *ping;
struct sockaddr_in6 addr;
save_counter(0);
ping = expand(sizeof(struct ping_packet));
ping->type = ICMP6_ECHO_REQUEST;
ping->code = 0;
ping->identifier = ping_id;
ping->sequence_no = slaac->backoff;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
addr.sin6_addr = slaac->addr;
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local, lease->last_interface);
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
if (slaac->backoff > 4)
slaac->ping_time += rand16()/4000; /* 0 - 15 */
slaac->backoff++;
}
if (next_event == 0 || difftime(next_event, slaac->ping_time) >= 0.0)
next_event = slaac->ping_time;
}
return next_event;
}
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases)
{
struct dhcp_lease *lease;
struct slaac_address *slaac;
struct ping_packet *ping = (struct ping_packet *)packet;
int gotone = 0;
if (ping->identifier == ping_id)
for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
if (slaac->backoff != 0 && IN6_ARE_ADDR_EQUAL(sender, &slaac->addr))
{
slaac->backoff = 0;
gotone = 1;
inet_ntop(AF_INET6, sender, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "SLAAC-CONFIRM(%s) %s %s", interface, daemon->addrbuff, lease->hostname);
}
lease_update_dns(gotone);
}
/* Build a map from ra-names subnets to corresponding interfaces. This
is used to go from DHCPv4 leases to SLAAC addresses,
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
*/
static int add_subnet(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)vparam;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
context->if_index = if_index;
context->local6 = *local;
}
return 1;
}
void build_subnet_map(void)
{
struct dhcp_context *context;
int ok = 0;
for (context = daemon->ra_contexts; context; context = context->next)
{
context->if_index = 0;
if ((context->flags & CONTEXT_RA_NAME))
ok = 1;
}
/* ra-names configured */
if (ok)
iface_enumerate(AF_INET6, NULL, add_subnet);
}
void schedule_subnet_map(void)
{
map_rebuild = 1;
}
#endif