mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
33
Commits
v2.60
..
v2.61test7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a953096485 | ||
|
|
884a6dfe6d | ||
|
|
0068301d24 | ||
|
|
353ae4d270 | ||
|
|
e759d426fa | ||
|
|
40ef23b547 | ||
|
|
f5e8562f96 | ||
|
|
1567feae3c | ||
|
|
daf061c9de | ||
|
|
d0e2c6c9ab | ||
|
|
8643ec7fea | ||
|
|
5cfea3d402 | ||
|
|
6c8f21e4a4 | ||
|
|
1d0f91c4a9 | ||
|
|
2a82db4caf | ||
|
|
dd88c17f15 | ||
|
|
8b37270410 | ||
|
|
760169fc43 | ||
|
|
7023e38294 | ||
|
|
a7cf58cc47 | ||
|
|
e25d1a2ea2 | ||
|
|
70969c1757 | ||
|
|
3803437dcc | ||
|
|
eabc6dd76a | ||
|
|
e28d2e2b77 | ||
|
|
96fafe2ed6 | ||
|
|
c81d390f84 | ||
|
|
08456c61f6 | ||
|
|
bc26f9a03f | ||
|
|
6ffeff86be | ||
|
|
f444cddbaf | ||
|
|
d13191a46c | ||
|
|
801ca9a7b7 |
No files matched your search
@@ -1,3 +1,48 @@
|
||||
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.
|
||||
|
||||
Invoke the DHCP script with action "tftp" when a TFTP file
|
||||
transfer completes. The size of the file, address to which
|
||||
it was sent and complete pathname are supplied. Note that
|
||||
version 2.60 introduced some script incompatibilties
|
||||
associated with DHCPv6, and this is a further change. To
|
||||
be safe, scripts should ignore unknown actions, and if
|
||||
not IPv6-aware, should exit if the environment
|
||||
variable DNSMASQ_IAID is set. The use-case for this is
|
||||
to track netboot/install. Suggestion from Shantanu
|
||||
Gadgil.
|
||||
|
||||
Update contrib/port-forward/dnsmasq-portforward to reflect
|
||||
the above.
|
||||
|
||||
Set the environment variable DNSMASQ_LOG_DHCP when running
|
||||
the script id --log-dhcp is in effect, so that script can
|
||||
taylor their logging verbosity. Suggestion from Malte Forkel.
|
||||
|
||||
|
||||
version 2.60
|
||||
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||
Flebbe for the patch.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -34,11 +34,21 @@ if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
|
||||
hostname=${DNSMASQ_OLD_HOSTNAME}
|
||||
fi
|
||||
|
||||
# IPv6 leases are not our concern. no NAT there!
|
||||
if [ ${DNSMASQ_IAID} ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# action init is not relevant, and will only be seen when leasefile-ro is set.
|
||||
if [ ${action} = init ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# action tftp is not relevant.
|
||||
if [ ${action} = tftp ] ; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ ${hostname} ]; then
|
||||
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
|
||||
|
||||
|
||||
Vendored
+9
@@ -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.
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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
|
||||
|
||||
Vendored
+3
@@ -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`"
|
||||
|
||||
@@ -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
|
||||
|
||||
+79
-11
@@ -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 host's 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. The address is pinged, and if a reply is received, 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 not work
|
||||
if a host is using privacy extensions.
|
||||
|
||||
The interface:<interface name> section is not normally used. See the
|
||||
NOTES section for details of this.
|
||||
@@ -1031,8 +1058,19 @@ 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
|
||||
Whenever a new DHCP lease is created, or an old one destroyed, or a
|
||||
TFTP file transfer completes, the
|
||||
executable specified by this option is run. <path>
|
||||
must be an absolute pathname, no PATH search occurs.
|
||||
The arguments to the process
|
||||
@@ -1082,6 +1120,8 @@ is known.
|
||||
DNSMASQ_TAGS contains all the tags set during the
|
||||
DHCP transaction, separated by spaces.
|
||||
|
||||
DNSMASQ_LOG_DHCP is set if --log-dhcp is in effect.
|
||||
|
||||
For IPv4 only:
|
||||
|
||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||
@@ -1108,6 +1148,8 @@ only supplied for
|
||||
since these data are not held in dnsmasq's lease
|
||||
database.
|
||||
|
||||
|
||||
|
||||
All file descriptors are
|
||||
closed except stdin, stdout and stderr which are open to /dev/null
|
||||
(except in debug mode).
|
||||
@@ -1126,6 +1168,17 @@ all existing leases as they are read from the lease file. Expired
|
||||
leases will be called with "del" and others with "old". When dnsmasq
|
||||
receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old " event.
|
||||
|
||||
|
||||
There are two further actions which may appear as the first argument
|
||||
to the script, "init" and "tftp". More may be added in the future, so
|
||||
scripts should be written to ignore unknown actions. "init" is
|
||||
decsribed below in
|
||||
.B --leasefile-ro
|
||||
The "tftp" action is invoked when a TFTP file transfer completes: the
|
||||
arguments are the file size in bytes, the address to which the file
|
||||
was sent, and the complete pathname of the file.
|
||||
|
||||
.TP
|
||||
.B --dhcp-luascript=<path>
|
||||
Specify a script written in Lua, to be run when leases are created,
|
||||
@@ -1139,11 +1192,13 @@ function, and may provide
|
||||
and
|
||||
.B shutdown
|
||||
functions, which are called, without arguments when dnsmasq starts up
|
||||
and terminates.
|
||||
and terminates. It may also provide a
|
||||
.B tftp
|
||||
function.
|
||||
|
||||
The
|
||||
.B lease
|
||||
method receives the information detailed in
|
||||
function receives the information detailed in
|
||||
.B --dhcp-script.
|
||||
It gets two arguments, firstly the action, which is a string
|
||||
containing, "add", "old" or "del", and secondly a table of tag value
|
||||
@@ -1160,7 +1215,16 @@ for IPv4, and
|
||||
.B client_duid, ip_address
|
||||
and
|
||||
.B hostname
|
||||
for IPv6.
|
||||
for IPv6.
|
||||
|
||||
The
|
||||
.B tftp
|
||||
function is called in the same way as the lease function, and the
|
||||
table holds the tags
|
||||
.B destination_address,
|
||||
.B file_name
|
||||
and
|
||||
.B file_size.
|
||||
.TP
|
||||
.B --dhcp-scriptuser
|
||||
Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag.
|
||||
@@ -1255,13 +1319,17 @@ only a subset of this is needed, and dnsmasq can handle it, using
|
||||
existing DHCP configuration to provide most data. When RA is enabled,
|
||||
dnsmasq will advertise a prefix for each dhcp-range, with default
|
||||
router and recursive DNS server as the relevant link-local address on
|
||||
the machine running dnsmasq. The "managed address" bits are set,
|
||||
except for a dhcp-range which is marked as "ra-only", in which case RA
|
||||
is provided but no DHCPv6 service and the managed address bits are
|
||||
cleared.
|
||||
the machine running dnsmasq. The "managed address" bits are set, and
|
||||
the "use SLAAC" bit is reset, except for a dhcp-range which is
|
||||
marked as "ra-only" or "ra-names", in which case RA is provided but no
|
||||
DHCPv6 service and the managed address bits are
|
||||
cleared and the "use SLAAC" bit set. If the same subnet appears in a
|
||||
normal dhcp-range and an "ra-only" dhcp-range, then the "managed
|
||||
address" bits and the "use SLAAC" bits are all set, allowing SLAAC and
|
||||
DHCP address to co-exist on the same subnet.
|
||||
.B enable-ra
|
||||
enables router advertisement for prefixes where dnsmasq is doing
|
||||
DHCPv6. It is not needed to "ra-only" prefixes. Creating an "ra-only"
|
||||
DHCPv6. It is not needed for "ra-only" prefixes. Creating an "ra-only"
|
||||
prefix and not setting
|
||||
.B enable-ra
|
||||
sends advertisements only to "ra-only" prefixes.
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
+44
-17
@@ -106,16 +106,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 +178,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 +565,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) ?
|
||||
@@ -706,6 +721,10 @@ int main (int argc, char **argv)
|
||||
# ifdef HAVE_SCRIPT
|
||||
while (helper_buf_empty() && do_script_run(now));
|
||||
|
||||
# ifdef HAVE_TFTP
|
||||
while (helper_buf_empty() && do_tftp_script_run());
|
||||
# endif
|
||||
|
||||
if (!helper_buf_empty())
|
||||
{
|
||||
FD_SET(daemon->helperfd, &wset);
|
||||
@@ -714,6 +733,11 @@ int main (int argc, char **argv)
|
||||
# else
|
||||
/* need this for other side-effects */
|
||||
while (do_script_run(now));
|
||||
|
||||
# ifdef HAVE_TFTP
|
||||
while (do_tftp_script_run());
|
||||
# endif
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -849,9 +873,17 @@ 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)
|
||||
{
|
||||
/* alarm(0) or alarm(-ve) doesn't do what we want.... */
|
||||
if ((now == 0 || difftime(event, now) <= 0.0))
|
||||
send_event(pipewrite, EVENT_ALARM, 0, NULL);
|
||||
else
|
||||
alarm((unsigned)difftime(event, now));
|
||||
}
|
||||
}
|
||||
|
||||
void send_event(int fd, int event, int data, char *msg)
|
||||
@@ -973,13 +1005,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 +1170,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)
|
||||
|
||||
+66
-10
@@ -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,11 +444,21 @@ 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
|
||||
#define ACTION_OLD 3
|
||||
#define ACTION_ADD 4
|
||||
#define ACTION_TFTP 5
|
||||
|
||||
#define LEASE_NEW 1 /* newly created */
|
||||
#define LEASE_CHANGED 2 /* modified */
|
||||
@@ -445,6 +467,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 +485,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 +637,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 +652,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 +710,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 +756,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 */
|
||||
@@ -769,7 +804,7 @@ extern struct daemon {
|
||||
#endif
|
||||
|
||||
/* TFTP stuff */
|
||||
struct tftp_transfer *tftp_trans;
|
||||
struct tftp_transfer *tftp_trans, *tftp_done_trans;
|
||||
|
||||
/* utility string buffer, hold max sized IP address as string */
|
||||
char *addrbuff;
|
||||
@@ -925,7 +960,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 +969,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 +984,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 +1004,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);
|
||||
@@ -999,11 +1036,14 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
|
||||
#endif
|
||||
|
||||
/* helper.c */
|
||||
#if defined(HAVE_DHCP) && !defined(NO_FORK)
|
||||
#if defined(HAVE_SCRIPT)
|
||||
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
|
||||
void helper_write(void);
|
||||
void queue_script(int action, struct dhcp_lease *lease,
|
||||
char *hostname, time_t now);
|
||||
#ifdef HAVE_TFTP
|
||||
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
|
||||
#endif
|
||||
int helper_buf_empty(void);
|
||||
#endif
|
||||
|
||||
@@ -1011,6 +1051,7 @@ int helper_buf_empty(void);
|
||||
#ifdef HAVE_TFTP
|
||||
void tftp_request(struct listener *listen, time_t now);
|
||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||
int do_tftp_script_run(void);
|
||||
#endif
|
||||
|
||||
/* conntrack.c */
|
||||
@@ -1042,8 +1083,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 +1100,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 +1129,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
|
||||
+269
-196
@@ -192,18 +192,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
#endif
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
|
||||
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
|
||||
|
||||
if (data.action == ACTION_DEL)
|
||||
action_str = "del";
|
||||
else if (data.action == ACTION_ADD)
|
||||
action_str = "add";
|
||||
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
|
||||
action_str = "old";
|
||||
else if (data.action == ACTION_TFTP)
|
||||
{
|
||||
action_str = "tftp";
|
||||
is6 = (data.flags != AF_INET);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
|
||||
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
/* stringify MAC into dhcp_buff */
|
||||
@@ -271,13 +277,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
char *dot;
|
||||
hostname = (char *)buf;
|
||||
hostname[data.hostname_len - 1] = 0;
|
||||
if (!legal_hostname(hostname))
|
||||
hostname = NULL;
|
||||
else if ((dot = strchr(hostname, '.')))
|
||||
if (data.action != ACTION_TFTP)
|
||||
{
|
||||
domain = dot+1;
|
||||
*dot = 0;
|
||||
}
|
||||
if (!legal_hostname(hostname))
|
||||
hostname = NULL;
|
||||
else if ((dot = strchr(hostname, '.')))
|
||||
{
|
||||
domain = dot+1;
|
||||
*dot = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extradata = buf + data.hostname_len;
|
||||
@@ -289,116 +298,141 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
/* file length */
|
||||
if (data.action == ACTION_TFTP)
|
||||
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
|
||||
|
||||
#ifdef HAVE_LUASCRIPT
|
||||
if (daemon->luascript)
|
||||
{
|
||||
lua_getglobal(lua, "lease"); /* function to call */
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
|
||||
if (is6)
|
||||
if (data.action == ACTION_TFTP)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "client_duid");
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "server_duid");
|
||||
lua_pushstring(lua, daemon->dhcp_buff3);
|
||||
lua_setfield(lua, -2, "iaid");
|
||||
lua_getglobal(lua, "tftp");
|
||||
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||
lua_pop(lua, 1); /* tftp function optional */
|
||||
else
|
||||
{
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "destination_address");
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "file_name");
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "file_size");
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
{
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "client_id");
|
||||
}
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
{
|
||||
lua_pushstring(lua, data.interface);
|
||||
lua_setfield(lua, -2, "interface");
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lua_pushnumber(lua, data.length);
|
||||
lua_setfield(lua, -2, "lease_length");
|
||||
#else
|
||||
lua_pushnumber(lua, data.expires);
|
||||
lua_setfield(lua, -2, "lease_expires");
|
||||
#endif
|
||||
|
||||
if (hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "hostname");
|
||||
}
|
||||
|
||||
if (domain)
|
||||
{
|
||||
lua_pushstring(lua, domain);
|
||||
lua_setfield(lua, -2, "domain");
|
||||
}
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
|
||||
if (!is6)
|
||||
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
for (i = 0; i < data.hwaddr_len; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
{
|
||||
lua_getglobal(lua, "lease"); /* function to call */
|
||||
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||
lua_newtable(lua); /* arg2 - data table */
|
||||
|
||||
if (is6)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "client_duid");
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "server_duid");
|
||||
lua_pushstring(lua, daemon->dhcp_buff3);
|
||||
lua_setfield(lua, -2, "iaid");
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
{
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "client_id");
|
||||
}
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
{
|
||||
lua_pushstring(lua, data.interface);
|
||||
lua_setfield(lua, -2, "interface");
|
||||
}
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
lua_pushnumber(lua, data.length);
|
||||
lua_setfield(lua, -2, "lease_length");
|
||||
#else
|
||||
lua_pushnumber(lua, data.expires);
|
||||
lua_setfield(lua, -2, "lease_expires");
|
||||
#endif
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||
|
||||
if (hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "hostname");
|
||||
}
|
||||
|
||||
if (domain)
|
||||
{
|
||||
lua_pushstring(lua, domain);
|
||||
lua_setfield(lua, -2, "domain");
|
||||
}
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
|
||||
if (!is6)
|
||||
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
for (i = 0; i < data.hwaddr_len; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||
}
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "tags");
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
lua_pushnumber(lua, data.remaining_time);
|
||||
lua_setfield(lua, -2, "time_remaining");
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "old_hostname");
|
||||
}
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
}
|
||||
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "ip_address");
|
||||
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
|
||||
buf = grab_extradata_lua(buf, end, "tags");
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
lua_pushnumber(lua, data.remaining_time);
|
||||
lua_setfield(lua, -2, "time_remaining");
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
lua_pushstring(lua, hostname);
|
||||
lua_setfield(lua, -2, "old_hostname");
|
||||
}
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
lua_pushstring(lua, daemon->dhcp_buff);
|
||||
lua_setfield(lua, -2, "mac_address");
|
||||
}
|
||||
|
||||
lua_pushstring(lua, daemon->addrbuff);
|
||||
lua_setfield(lua, -2, "ip_address");
|
||||
|
||||
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -439,81 +473,87 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is6)
|
||||
if (data.action != ACTION_TFTP)
|
||||
{
|
||||
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||
#else
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
if (domain)
|
||||
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
|
||||
if (!is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
{
|
||||
if (data.hwaddr_len != 0)
|
||||
if (is6)
|
||||
{
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
|
||||
for (i = 0; i < data.hwaddr_len - 1; i++)
|
||||
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
|
||||
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
|
||||
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
|
||||
#else
|
||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||
#endif
|
||||
|
||||
if (domain)
|
||||
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||
|
||||
end = extradata + data.ed_len;
|
||||
buf = extradata;
|
||||
|
||||
if (!is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||
#ifdef HAVE_DHCP6
|
||||
else
|
||||
{
|
||||
if (data.hwaddr_len != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
|
||||
for (i = 0; i < data.hwaddr_len - 1; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||
}
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
||||
hostname = NULL;
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||
}
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||
{
|
||||
my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
|
||||
hostname = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
|
||||
|
||||
/* we need to have the event_fd around if exec fails */
|
||||
if ((i = fcntl(event_fd, F_GETFD)) != -1)
|
||||
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
|
||||
@@ -584,11 +624,29 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void buff_alloc(size_t size)
|
||||
{
|
||||
if (size > buf_size)
|
||||
{
|
||||
struct script_data *new;
|
||||
|
||||
/* start with reasonable size, will almost never need extending. */
|
||||
if (size < sizeof(struct script_data) + 200)
|
||||
size = sizeof(struct script_data) + 200;
|
||||
|
||||
if (!(new = whine_malloc(size)))
|
||||
return;
|
||||
if (buf)
|
||||
free(buf);
|
||||
buf = new;
|
||||
buf_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/* pack up lease data into a buffer */
|
||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||
{
|
||||
unsigned char *p;
|
||||
size_t size;
|
||||
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
||||
int fd = daemon->dhcpfd;
|
||||
|
||||
@@ -608,23 +666,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
if (hostname)
|
||||
hostname_len = strlen(hostname) + 1;
|
||||
|
||||
size = sizeof(struct script_data) + clid_len + ed_len + hostname_len;
|
||||
|
||||
if (size > buf_size)
|
||||
{
|
||||
struct script_data *new;
|
||||
|
||||
/* start with reasonable size, will almost never need extending. */
|
||||
if (size < sizeof(struct script_data) + 200)
|
||||
size = sizeof(struct script_data) + 200;
|
||||
|
||||
if (!(new = whine_malloc(size)))
|
||||
return;
|
||||
if (buf)
|
||||
free(buf);
|
||||
buf = new;
|
||||
buf_size = size;
|
||||
}
|
||||
buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
|
||||
|
||||
buf->action = action;
|
||||
buf->flags = lease->flags;
|
||||
@@ -669,6 +711,37 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
bytes_in_buf = p - (unsigned char *)buf;
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* This nastily re-uses DHCP-fields for TFTP stuff */
|
||||
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
|
||||
{
|
||||
unsigned int filename_len;
|
||||
|
||||
/* no script */
|
||||
if (daemon->helperfd == -1)
|
||||
return;
|
||||
|
||||
filename_len = strlen(filename) + 1;
|
||||
buff_alloc(sizeof(struct script_data) + filename_len);
|
||||
memset(buf, 0, sizeof(struct script_data));
|
||||
|
||||
buf->action = ACTION_TFTP;
|
||||
buf->hostname_len = filename_len;
|
||||
buf->hwaddr_len = file_len;
|
||||
|
||||
if ((buf->flags = peer->sa.sa_family) == AF_INET)
|
||||
buf->addr = peer->in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
memcpy(buf->hwaddr, &peer->in6.sin6_addr, IN6ADDRSZ);
|
||||
#endif
|
||||
|
||||
memcpy((unsigned char *)(buf+1), filename, filename_len);
|
||||
|
||||
bytes_in_buf = sizeof(struct script_data) + filename_len;
|
||||
}
|
||||
#endif
|
||||
|
||||
int helper_buf_empty(void)
|
||||
{
|
||||
return bytes_in_buf == 0;
|
||||
|
||||
+131
-23
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
+47
-19
@@ -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,10 +203,10 @@ 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;
|
||||
ra->flags = 0x00;
|
||||
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
|
||||
ra->reachable_time = 0;
|
||||
ra->retrans_time = 0;
|
||||
@@ -227,7 +246,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
|
||||
/* set managed bits unless we're providing only RA on this link */
|
||||
if (parm.managed)
|
||||
ra->flags = 0xc0;
|
||||
ra->flags = 0xc0; /* M flag, managed, O flag, other */
|
||||
|
||||
/* decide where we're sending */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
@@ -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;
|
||||
@@ -274,7 +293,11 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
if (!(context->flags & CONTEXT_RA_ONLY))
|
||||
int do_slaac = 0;
|
||||
|
||||
if (context->flags & CONTEXT_RA_ONLY)
|
||||
do_slaac = 1;
|
||||
else
|
||||
{
|
||||
/* don't do RA for non-ra-only unless --enable-ra is set */
|
||||
if (!option_bool(OPT_RA))
|
||||
@@ -298,6 +321,10 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
is_same_net6(local, &tmp->start6, prefix) &&
|
||||
is_same_net6(local, &tmp->end6, prefix))
|
||||
{
|
||||
/* if any dhcp-range with ra-only on this subnet
|
||||
set the "do_slaac" bit */
|
||||
if (tmp->flags & CONTEXT_RA_ONLY)
|
||||
do_slaac = 1;
|
||||
tmp->flags |= CONTEXT_RA_DONE;
|
||||
context->ra_time = 0;
|
||||
}
|
||||
@@ -316,7 +343,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
opt->len = 4;
|
||||
opt->prefix_len = prefix;
|
||||
/* autonomous only is we're not doing dhcp */
|
||||
opt->flags = (context->flags & CONTEXT_RA_ONLY) ? 0xc0 : 0x00;
|
||||
opt->flags = do_slaac ? 0x40 : 0x00;
|
||||
opt->valid_lifetime = opt->preferred_lifetime = htonl(time);
|
||||
opt->reserved = 0;
|
||||
|
||||
@@ -406,7 +433,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 +453,5 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+5
-5
@@ -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
@@ -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
@@ -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
|
||||
+20
-1
@@ -571,7 +571,9 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
free_transfer(transfer);
|
||||
/* put on queue to be sent to script and deleted */
|
||||
transfer->next = daemon->tftp_done_trans;
|
||||
daemon->tftp_done_trans = transfer;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -709,4 +711,21 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_tftp_script_run(void)
|
||||
{
|
||||
struct tftp_transfer *transfer;
|
||||
|
||||
if ((transfer = daemon->tftp_done_trans))
|
||||
{
|
||||
daemon->tftp_done_trans = transfer->next;
|
||||
#ifdef HAVE_SCRIPT
|
||||
queue_tftp(transfer->file->size, transfer->file->filename, &transfer->peer);
|
||||
#endif
|
||||
free_transfer(transfer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user