mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8257540bc | ||
|
|
2240704863 | ||
|
|
e8ca69ea16 | ||
|
|
da632e7cc1 | ||
|
|
30cd96663f | ||
|
|
7dbe98147d | ||
|
|
5d71d83420 | ||
|
|
38a59a9ff7 | ||
|
|
4b028ad612 | ||
|
|
442560beb4 | ||
|
|
7d2b5c9583 | ||
|
|
29689cfa5a | ||
|
|
52d4abf2f9 | ||
|
|
a953096485 | ||
|
|
884a6dfe6d | ||
|
|
0068301d24 | ||
|
|
353ae4d270 | ||
|
|
e759d426fa | ||
|
|
40ef23b547 | ||
|
|
f5e8562f96 | ||
|
|
1567feae3c | ||
|
|
daf061c9de | ||
|
|
d0e2c6c9ab | ||
|
|
8643ec7fea | ||
|
|
5cfea3d402 | ||
|
|
6c8f21e4a4 | ||
|
|
1d0f91c4a9 | ||
|
|
2a82db4caf |
No files matched your search
@@ -9,7 +9,65 @@ version 2.61
|
||||
|
||||
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.
|
||||
|
||||
Arrange that addresses specified with --listen-address
|
||||
work even if there is no interface carrying the
|
||||
address. This is chiefly useful for IPv4 loopback
|
||||
addresses, where any address in 127.0.0.0/8 is a valid
|
||||
loopback address, but normally only 127.0.0.1 appears on
|
||||
the lo interface. Thanks to Mathieu Trudel-Lapierre for
|
||||
the idea and initial patch.
|
||||
|
||||
Fix crash, introduced in 2.60, when a DHCPINFORM is
|
||||
received from a network which has no valid dhcp-range.
|
||||
Thanks to Stephane Glondu for the bug report.
|
||||
|
||||
Add a new DHCP lease time keyword, "deprecated" for
|
||||
--dhcp-range. This is only valid for IPv6, and sets the
|
||||
preffered lease time for both DHCP and RA to zero. The
|
||||
effect is that clients can continue to use the address
|
||||
for existing connections, but new connections will use
|
||||
other addresses, if they exist. This makes hitless
|
||||
renumbering at least possible.
|
||||
|
||||
Fix bug in address6_available() which caused DHCPv6 lease
|
||||
aquistion to fail of more than one dhcp-range in use.
|
||||
|
||||
|
||||
|
||||
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
+8
-1
@@ -3,9 +3,16 @@ 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-2) unstable; urgency=high
|
||||
|
||||
* Fix DHCPv4 segfault. (closes: #665008)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 23 Mar 2012 09:37:23 +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
|
||||
|
||||
+20
-2
@@ -169,14 +169,32 @@
|
||||
# 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
|
||||
|
||||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||
#dhcp-range=1234::2, 1234::500, slaac
|
||||
|
||||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||
# not get addresses from DHCP, but they will get other configuration information.
|
||||
# They will use SLAAC for addresses.
|
||||
#dhcp-range=1234::, ra-stateless
|
||||
|
||||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||
# from DHCPv4 leases.
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overriden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
|
||||
+91
-34
@@ -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
|
||||
@@ -494,9 +510,9 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>,<end-IPv6addr>[,<prefix-len>][,<lease time>]
|
||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>[,<end-IPv6addr>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -506,8 +522,12 @@ options. If the lease time is given, then leases
|
||||
will be given for that length of time. The lease time is in seconds,
|
||||
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
|
||||
the default lease time is one hour. The
|
||||
minimum lease time is two minutes. This
|
||||
option may be repeated, with different addresses, to enable DHCP
|
||||
minimum lease time is two minutes. For IPv6 ranges, the lease time
|
||||
maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
|
||||
lease or router advertisement to zero, which causes clients to use
|
||||
other addresses, if available, for new connections as a prelude to renumbering.
|
||||
|
||||
This option may be repeated, with different addresses, to enable DHCP
|
||||
service to more than one network. For directly connected networks (ie,
|
||||
networks on which the machine running dnsmasq has an interface) the
|
||||
netmask is optional: dnsmasq will determine it from the interface
|
||||
@@ -532,7 +552,7 @@ When it is prefixed with 'tag:' instead, then its meaning changes from setting
|
||||
a tag to matching it. Only one tag may be set, but more than one tag
|
||||
may be matched.
|
||||
|
||||
The end address may be replaced by the keyword
|
||||
The optional <mode> keyword may be
|
||||
.B static
|
||||
which tells dnsmasq to enable DHCP for the network specified, but not
|
||||
to dynamically allocate IP addresses: only hosts which have static
|
||||
@@ -540,34 +560,50 @@ addresses given via
|
||||
.B dhcp-host
|
||||
or from /etc/ethers will be served.
|
||||
|
||||
The end address may be replaced by
|
||||
the keyword
|
||||
Fot IPv4, the <mode> may be
|
||||
.B proxy
|
||||
in which case dnsmasq will provide proxy-DHCP on the specified
|
||||
subnet. (See
|
||||
.B pxe-prompt
|
||||
and
|
||||
.B pxe-service
|
||||
for details, applies to IPv4 only.)
|
||||
for details.)
|
||||
|
||||
For IPv6, the mode may be some combination of
|
||||
.B ra-only, slaac, ra-names, ra-stateless.
|
||||
|
||||
The end address may be replaced by
|
||||
the keyword
|
||||
.B ra-only
|
||||
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. Instead, the keyword
|
||||
tells dnsmasq to offer Router Advertisement only on this subnet,
|
||||
and not DHCP.
|
||||
|
||||
.B slaac
|
||||
tells dnsmasq to offer Router Advertisement on this subnet and to set
|
||||
the A bit in the router advertisement, so that the client will use
|
||||
SLAAC addresses. When used with a DHCP range or static DHCP address
|
||||
this results in the client having both a DHCP-assigned and a SLAAC
|
||||
address.
|
||||
|
||||
.B ra-stateless
|
||||
sends router advertisements with the O and A bits set, and provides a
|
||||
stateless DHCP service. The client will use a SLAAC address, and use
|
||||
DHCP for other configuration information.
|
||||
|
||||
.B ra-names
|
||||
may be used. This does the same at ra-only, but also enables a mode
|
||||
enables a mode
|
||||
which gives DNS names to dual-stack hosts which do SLAAC for
|
||||
IPv6. Dnsmasq uses the hosts IPv4 lease to derive the name, network
|
||||
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. An AAAA record is added to the DNS for this IPv6
|
||||
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 generate an
|
||||
erroneous AAAA record if a host is using privacy extensions or does
|
||||
not support IPv6. Use with care.
|
||||
networks, (not one doing DHCP via a relay) and it will not work
|
||||
if a host is using privacy extensions.
|
||||
.B ra-names
|
||||
can be combined with
|
||||
.B ra-stateless
|
||||
and
|
||||
.B slaac.
|
||||
|
||||
The interface:<interface name> section is not normally used. See the
|
||||
NOTES section for details of this.
|
||||
@@ -1053,7 +1089,8 @@ 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
|
||||
@@ -1103,6 +1140,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.
|
||||
@@ -1129,6 +1168,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).
|
||||
@@ -1147,6 +1188,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,
|
||||
@@ -1160,11 +1212,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
|
||||
@@ -1181,7 +1235,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.
|
||||
@@ -1276,16 +1339,10 @@ 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.
|
||||
.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"
|
||||
prefix and not setting
|
||||
.B enable-ra
|
||||
sends advertisements only to "ra-only" prefixes.
|
||||
the machine running dnsmasq. By default, he "managed address" bits are set, and
|
||||
the "use SLAAC" bit is reset. This can be changed for individual
|
||||
subnets with the mode keywords described in
|
||||
.B --dhcp-range.
|
||||
.TP
|
||||
.B --enable-tftp[=<interface>]
|
||||
Enable the TFTP server function. This is deliberately limited to that
|
||||
|
||||
+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);
|
||||
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ HAVE_SOLARIS_NETWORK
|
||||
define exactly one of these to alter interaction with kernel networking.
|
||||
|
||||
HAVE_GETOPT_LONG
|
||||
defined when GNU-sty;e getopt_long available.
|
||||
defined when GNU-style getopt_long available.
|
||||
|
||||
HAVE_ARC4RANDOM
|
||||
defined if arc4random() available to get better security from DNS spoofs
|
||||
|
||||
@@ -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;
|
||||
|
||||
+19
-10
@@ -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,
|
||||
@@ -220,7 +229,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
@@ -273,9 +282,9 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
start = addr6part(&tmp->start6);
|
||||
end = addr6part(&tmp->end6);
|
||||
|
||||
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
|
||||
is_same_net6(&context->start6, taddr, context->prefix) &&
|
||||
is_same_net6(&context->end6, taddr, context->prefix) &&
|
||||
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
|
||||
is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
|
||||
+88
-50
@@ -209,13 +209,6 @@ int main (int argc, char **argv)
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
||||
|
||||
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
if (!if_tmp->used)
|
||||
{
|
||||
prettyprint_addr(&if_tmp->addr, daemon->namebuff);
|
||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else
|
||||
create_wildcard_listeners();
|
||||
@@ -537,7 +530,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp || daemon->dhcp6)
|
||||
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
|
||||
{
|
||||
struct dhcp_context *dhcp_tmp;
|
||||
int family = AF_INET;
|
||||
@@ -550,29 +543,56 @@ int main (int argc, char **argv)
|
||||
{
|
||||
void *start = &dhcp_tmp->start;
|
||||
void *end = &dhcp_tmp->end;
|
||||
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (family == AF_INET6)
|
||||
{
|
||||
start = &dhcp_tmp->start6;
|
||||
end = &dhcp_tmp->end6;
|
||||
struct in6_addr subnet = dhcp_tmp->start6;
|
||||
setaddr6part(&subnet, 0);
|
||||
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
|
||||
}
|
||||
#endif
|
||||
|
||||
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
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) ?
|
||||
_("DHCP, proxy on subnet %.0s%s%.0s") :
|
||||
_("DHCP, IP range %s -- %s, lease time %s"),
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
|
||||
if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
strcpy(daemon->namebuff, _("prefix deprecated"));
|
||||
else
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("lease time "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time);
|
||||
}
|
||||
|
||||
if (daemon->dhcp_buff)
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
if (daemon->dhcp_buff3)
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
my_syslog(MS_DHCP | LOG_INFO,
|
||||
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
|
||||
_("stateless DHCPv6 on %s%.0s%.0s") :
|
||||
(dhcp_tmp->flags & CONTEXT_STATIC) ?
|
||||
_("DHCP, static leases only on %.0s%s, %s") :
|
||||
(dhcp_tmp->flags & CONTEXT_PROXY) ?
|
||||
_("DHCP, proxy on subnet %.0s%s%.0s") :
|
||||
_("DHCP, IP range %s -- %s, %s"),
|
||||
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
|
||||
|
||||
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
|
||||
daemon->addrbuff);
|
||||
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
|
||||
{
|
||||
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
|
||||
{
|
||||
char *p = daemon->namebuff;
|
||||
p += sprintf(p, _("prefix valid "));
|
||||
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
|
||||
}
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
|
||||
daemon->addrbuff, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -700,12 +720,12 @@ int main (int argc, char **argv)
|
||||
{
|
||||
FD_SET(daemon->dhcp6fd, &rset);
|
||||
bump_maxfd(daemon->dhcp6fd, &maxfd);
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
}
|
||||
}
|
||||
|
||||
if (daemon->ra_contexts)
|
||||
{
|
||||
FD_SET(daemon->icmp6fd, &rset);
|
||||
bump_maxfd(daemon->icmp6fd, &maxfd);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -721,6 +741,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);
|
||||
@@ -729,6 +753,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
|
||||
|
||||
@@ -864,9 +893,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)
|
||||
@@ -988,13 +1025,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;
|
||||
@@ -1158,7 +1190,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)
|
||||
@@ -1272,18 +1304,19 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
int confd;
|
||||
struct irec *iface = NULL;
|
||||
pid_t p;
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
|
||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd == -1)
|
||||
if (confd == -1 ||
|
||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
continue;
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface;
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
@@ -1291,14 +1324,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
interface too, for localisation. */
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (enumerate_interfaces() &&
|
||||
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
|
||||
if (enumerate_interfaces())
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!iface)
|
||||
if (!iface && !option_bool(OPT_NOWILD))
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1324,7 +1356,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
unsigned char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
|
||||
struct in_addr netmask;
|
||||
|
||||
if (iface)
|
||||
netmask = iface->netmask;
|
||||
else
|
||||
netmask.s_addr = 0;
|
||||
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
@@ -1342,7 +1380,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
|
||||
buff = tcp_request(confd, now, &tcp_addr, netmask);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
|
||||
+75
-28
@@ -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 */
|
||||
@@ -383,7 +395,7 @@ struct irec {
|
||||
|
||||
struct listener {
|
||||
int fd, tcpfd, tftpfd, family;
|
||||
struct irec *iface; /* only valid for non-wildcard */
|
||||
struct irec *iface; /* only sometimes valid for non-wildcard */
|
||||
struct listener *next;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -615,13 +646,16 @@ struct dhcp_context {
|
||||
struct dhcp_context *next, *current;
|
||||
};
|
||||
|
||||
#define CONTEXT_STATIC 1
|
||||
#define CONTEXT_NETMASK 2
|
||||
#define CONTEXT_BRDCAST 4
|
||||
#define CONTEXT_PROXY 8
|
||||
#define CONTEXT_RA_ONLY 16
|
||||
#define CONTEXT_RA_DONE 32
|
||||
#define CONTEXT_RA_NAME 64
|
||||
#define CONTEXT_STATIC 1
|
||||
#define CONTEXT_NETMASK 2
|
||||
#define CONTEXT_BRDCAST 4
|
||||
#define CONTEXT_PROXY 8
|
||||
#define CONTEXT_RA_ONLY 16
|
||||
#define CONTEXT_RA_DONE 32
|
||||
#define CONTEXT_RA_NAME 64
|
||||
#define CONTEXT_RA_STATELESS 128
|
||||
#define CONTEXT_DHCP 256
|
||||
#define CONTEXT_DEPRECATE 512
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -630,13 +664,6 @@ struct ping_result {
|
||||
struct ping_result *next;
|
||||
};
|
||||
|
||||
struct subnet_map {
|
||||
int iface;
|
||||
struct in6_addr subnet;
|
||||
struct subnet_map *next;
|
||||
};
|
||||
|
||||
|
||||
struct tftp_file {
|
||||
int refcount, fd;
|
||||
off_t size;
|
||||
@@ -686,6 +713,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;
|
||||
@@ -779,7 +807,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;
|
||||
@@ -886,9 +914,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
unsigned int iface, int *errp);
|
||||
|
||||
/* network.c */
|
||||
int indextoname(int fd, int index, char *name);
|
||||
@@ -935,7 +963,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
|
||||
@@ -944,12 +972,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);
|
||||
@@ -978,7 +1007,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);
|
||||
@@ -1010,11 +1039,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
|
||||
|
||||
@@ -1022,6 +1054,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 */
|
||||
@@ -1053,8 +1086,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 */
|
||||
@@ -1070,7 +1103,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
|
||||
@@ -1093,6 +1132,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);
|
||||
struct subnet_map *build_subnet_map(void);
|
||||
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
|
||||
+15
-8
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
|
||||
|
||||
/* Send a UDP packet with its source address set as "source"
|
||||
unless nowild is true, when we just send it with the kernel default */
|
||||
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface)
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface, int *errp)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov[1];
|
||||
@@ -110,8 +110,15 @@ void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
if (retry_send())
|
||||
goto retry;
|
||||
|
||||
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||
if (errp)
|
||||
*errp = errno;
|
||||
else
|
||||
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||
@@ -432,7 +439,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -621,7 +628,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->id = htons(forward->orig_id);
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
&forward->source, &forward->dest, forward->iface, NULL);
|
||||
}
|
||||
free_frec(forward); /* cancel */
|
||||
}
|
||||
@@ -660,7 +667,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -816,7 +823,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
||||
m, &source_addr, &dst_addr, if_index);
|
||||
m, &source_addr, &dst_addr, if_index, NULL);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
|
||||
|
||||
+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;
|
||||
|
||||
+70
-54
@@ -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);
|
||||
@@ -306,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)
|
||||
@@ -326,8 +334,7 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +349,7 @@ static int find_interface_v4(struct in_addr local, int if_index,
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
if (is_same_net(local, lease->addr, netmask))
|
||||
lease->last_interface = if_index;
|
||||
lease_set_interface(lease, if_index, *((time_t *)vparam));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -353,17 +360,22 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void) scope;
|
||||
(void) vparam;
|
||||
(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->last_interface = if_index;
|
||||
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
|
||||
|
||||
|
||||
@@ -373,9 +385,13 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
|
||||
start-time. */
|
||||
void lease_find_interfaces(time_t now)
|
||||
{
|
||||
iface_enumerate(AF_INET, NULL, find_interface_v4);
|
||||
#ifdef HAVE_DHCP6
|
||||
iface_enumerate(AF_INET6, NULL, find_interface_v6);
|
||||
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)
|
||||
@@ -388,16 +404,12 @@ void lease_find_interfaces(time_t now)
|
||||
|
||||
|
||||
|
||||
void lease_update_dns(void)
|
||||
void lease_update_dns(int force)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (daemon->port != 0 && dns_dirty)
|
||||
if (daemon->port != 0 && (dns_dirty || force))
|
||||
{
|
||||
#ifdef HAVE_DHCP6
|
||||
struct subnet_map *subnets = build_subnet_map();
|
||||
#endif
|
||||
|
||||
cache_unhash_dhcp();
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
@@ -409,41 +421,15 @@ void lease_update_dns(void)
|
||||
prot = AF_INET6;
|
||||
else if (lease->hostname || lease->fqdn)
|
||||
{
|
||||
struct subnet_map *map;
|
||||
for (map = subnets; map; map = map->next)
|
||||
if (lease->last_interface == map->iface)
|
||||
struct slaac_address *slaac;
|
||||
|
||||
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
|
||||
if (slaac->backoff == 0)
|
||||
{
|
||||
struct in6_addr addr = map->subnet;
|
||||
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;
|
||||
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&addr, lease->expires);
|
||||
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 *)&addr, lease->expires);
|
||||
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&slaac->addr, lease->expires);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -713,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))
|
||||
@@ -725,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
|
||||
@@ -742,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)
|
||||
@@ -870,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)
|
||||
@@ -919,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
|
||||
|
||||
|
||||
@@ -511,6 +511,7 @@ void create_bound_listeners(int dienow)
|
||||
{
|
||||
struct listener *new;
|
||||
struct irec *iface;
|
||||
struct iname *if_tmp;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (!iface->done && !iface->dad &&
|
||||
@@ -521,6 +522,25 @@ void create_bound_listeners(int dienow)
|
||||
daemon->listeners = new;
|
||||
iface->done = 1;
|
||||
}
|
||||
|
||||
/* Check for --listen-address options that haven't been used because there's
|
||||
no interface with a matching address. These may be valid: eg it's possible
|
||||
to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
|
||||
|
||||
If the address isn't valid the bind() will fail and we'll die().
|
||||
|
||||
The resulting listeners have the ->iface field NULL, and this has to be
|
||||
handled by the DNS and TFTP code. It disables --localise-queries processing
|
||||
(no netmask) and some MTU login the tftp code. */
|
||||
|
||||
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
|
||||
if (!if_tmp->used &&
|
||||
(new = create_listeners(&if_tmp->addr, 1, dienow)))
|
||||
{
|
||||
new->iface = NULL;
|
||||
new->next = daemon->listeners;
|
||||
daemon->listeners = new;
|
||||
}
|
||||
}
|
||||
|
||||
int is_dad_listeners(void)
|
||||
|
||||
+110
-346
@@ -116,6 +116,7 @@ struct myoption {
|
||||
#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[] =
|
||||
@@ -237,6 +238,7 @@ static const struct myoption opts[] =
|
||||
{ "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 }
|
||||
};
|
||||
|
||||
@@ -365,242 +367,10 @@ static struct {
|
||||
{ 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
|
||||
@@ -823,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)
|
||||
{
|
||||
@@ -868,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;
|
||||
@@ -897,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;
|
||||
}
|
||||
@@ -921,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;
|
||||
@@ -977,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");
|
||||
@@ -1262,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++;
|
||||
|
||||
@@ -1290,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++;
|
||||
|
||||
@@ -2236,7 +1959,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
case 'F': /* --dhcp-range */
|
||||
{
|
||||
int k, leasepos = 2;
|
||||
char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||
char *cp, *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
|
||||
|
||||
memset (new, 0, sizeof(*new));
|
||||
@@ -2287,7 +2010,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 1; k < 5; k++)
|
||||
for (k = 1; k < 7; k++)
|
||||
if (!(a[k] = split(a[k-1])))
|
||||
break;
|
||||
|
||||
@@ -2297,17 +2020,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
{
|
||||
new->next = daemon->dhcp;
|
||||
daemon->dhcp = new;
|
||||
new->end = new->start;
|
||||
if (strcmp(a[1], "static") == 0)
|
||||
{
|
||||
new->end = new->start;
|
||||
new->flags |= CONTEXT_STATIC;
|
||||
}
|
||||
new->flags |= CONTEXT_STATIC;
|
||||
else if (strcmp(a[1], "proxy") == 0)
|
||||
{
|
||||
new->end = new->start;
|
||||
new->flags |= CONTEXT_PROXY;
|
||||
}
|
||||
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
|
||||
new->flags |= CONTEXT_PROXY;
|
||||
else if (!inet_pton(AF_INET, a[1], &new->end))
|
||||
option = '?';
|
||||
|
||||
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
|
||||
@@ -2337,53 +2055,54 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
else if (inet_pton(AF_INET6, a[0], &new->start6))
|
||||
{
|
||||
new->prefix = 64; /* default */
|
||||
new->end6 = new->start6;
|
||||
|
||||
for (leasepos = 1; leasepos < k; leasepos++)
|
||||
{
|
||||
if (strcmp(a[leasepos], "static") == 0)
|
||||
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
|
||||
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
|
||||
new->flags |= CONTEXT_RA_ONLY;
|
||||
else if (strcmp(a[leasepos], "ra-names") == 0)
|
||||
new->flags |= CONTEXT_RA_NAME;
|
||||
else if (strcmp(a[leasepos], "ra-stateless") == 0)
|
||||
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP;
|
||||
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
|
||||
new->flags |= CONTEXT_DHCP;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(a[1], "static") == 0)
|
||||
{
|
||||
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
|
||||
new->flags |= CONTEXT_STATIC;
|
||||
}
|
||||
else if (strcmp(a[1], "ra-only") == 0)
|
||||
{
|
||||
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 = '?';
|
||||
|
||||
if (new->flags & CONTEXT_RA_ONLY)
|
||||
{
|
||||
new->next = daemon->ra_contexts;
|
||||
daemon->ra_contexts = new;
|
||||
}
|
||||
else
|
||||
if (new->flags & CONTEXT_DHCP)
|
||||
{
|
||||
new->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = new;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
new->next = daemon->ra_contexts;
|
||||
daemon->ra_contexts = new;
|
||||
}
|
||||
|
||||
/* bare integer < 128 is prefix value */
|
||||
if (option != '?' && k >= 3)
|
||||
if (option != '?' && leasepos < k)
|
||||
{
|
||||
int pref;
|
||||
for (cp = a[2]; *cp; cp++)
|
||||
for (cp = a[leasepos]; *cp; cp++)
|
||||
if (!(*cp >= '0' && *cp <= '9'))
|
||||
break;
|
||||
if (!*cp && (pref = atoi(a[2])) <= 128)
|
||||
if (!*cp && (pref = atoi(a[leasepos])) <= 128)
|
||||
{
|
||||
new->prefix = pref;
|
||||
leasepos = 3;
|
||||
if ((new->flags & CONTEXT_RA_ONLY) && new->prefix != 64)
|
||||
leasepos++;
|
||||
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) &&
|
||||
new->prefix != 64)
|
||||
problem = _("prefix must be exactly 64 for RA subnets");
|
||||
else if (new->prefix < 64)
|
||||
problem = _("prefix must be at least 64");
|
||||
}
|
||||
}
|
||||
|
||||
if (!problem && !is_same_net6(&new->start6, &new->end6, new->prefix))
|
||||
problem = _("inconsistent DHCPv6 range");
|
||||
else if (addr6part(&new->start6) > addr6part(&new->end6))
|
||||
@@ -2395,10 +2114,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (k >= leasepos+1)
|
||||
if (leasepos < k)
|
||||
{
|
||||
if (strcmp(a[leasepos], "infinite") == 0)
|
||||
new->lease_time = 0xffffffff;
|
||||
else if (strcmp(a[leasepos], "deprecated") == 0)
|
||||
new->flags |= CONTEXT_DEPRECATE;
|
||||
else
|
||||
{
|
||||
int fac = 1;
|
||||
@@ -2431,16 +2152,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
/* lifetimes must be min 2 hrs, by RFC 2462.
|
||||
This gets enforced in radv.c for DHCP ranges
|
||||
which are legitimately less. */
|
||||
if ((new->flags & CONTEXT_RA_ONLY) &&
|
||||
new->lease_time < 7200)
|
||||
new->lease_time = 7200;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3310,6 +3021,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
|
||||
|
||||
+100
-133
@@ -27,7 +27,7 @@
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
struct ra_param {
|
||||
int ind, managed, found_context, first;
|
||||
int ind, managed, other, found_context, first;
|
||||
char *if_name;
|
||||
struct in6_addr link_local;
|
||||
};
|
||||
@@ -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 */
|
||||
@@ -180,20 +199,21 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in6 addr;
|
||||
struct dhcp_context *context;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
parm.ind = iface;
|
||||
parm.managed = 0;
|
||||
parm.other = 0;
|
||||
parm.found_context = 0;
|
||||
parm.if_name = iface_name;
|
||||
parm.first = 1;
|
||||
@@ -227,8 +247,10 @@ 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 |= 0x80; /* M flag, managed, */
|
||||
if (parm.other)
|
||||
ra->flags |= 0x40; /* O flag, other */
|
||||
|
||||
/* decide where we're sending */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
@@ -238,7 +260,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;
|
||||
@@ -247,16 +269,15 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
|
||||
inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
|
||||
|
||||
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
|
||||
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface, NULL);
|
||||
|
||||
}
|
||||
|
||||
static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context, *tmp;
|
||||
struct dhcp_context *context;
|
||||
struct ra_param *param = vparam;
|
||||
struct prefix_opt *opt;
|
||||
|
||||
(void)scope; /* warning */
|
||||
(void)dad;
|
||||
@@ -269,64 +290,78 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
!IN6_IS_ADDR_LINKLOCAL(local) &&
|
||||
!IN6_IS_ADDR_MULTICAST(local))
|
||||
{
|
||||
int do_slaac = 0;
|
||||
int deprecate = 0;
|
||||
unsigned int time = 0xffffffff;
|
||||
struct in6_addr *addr = NULL;
|
||||
struct prefix_opt *opt;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if (prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
if (!(context->flags & CONTEXT_RA_ONLY))
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
{
|
||||
do_slaac = 1;
|
||||
if (context->flags & CONTEXT_RA_STATELESS)
|
||||
param->other = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* don't do RA for non-ra-only unless --enable-ra is set */
|
||||
if (!option_bool(OPT_RA))
|
||||
continue;
|
||||
param->managed = 1;
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_RA_DONE)
|
||||
continue;
|
||||
/* find floor time */
|
||||
if (time > context->lease_time)
|
||||
time = context->lease_time;
|
||||
|
||||
/* subsequent prefixes on the same interface don't need timers */
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
deprecate = 1;
|
||||
|
||||
/* subsequent prefixes on the same interface
|
||||
and subsequent instances of this prefix don't need timers */
|
||||
if (!param->first)
|
||||
context->ra_time = 0;
|
||||
param->first = 0;
|
||||
param->found_context = 1;
|
||||
|
||||
if (context->flags & CONTEXT_RA_DONE)
|
||||
continue;
|
||||
|
||||
context->flags |= CONTEXT_RA_DONE;
|
||||
|
||||
/* mark this subnet and duplicates: as done. */
|
||||
for (tmp = context->next; tmp; tmp = tmp->next)
|
||||
if (tmp->prefix == prefix &&
|
||||
is_same_net6(local, &tmp->start6, prefix) &&
|
||||
is_same_net6(local, &tmp->end6, prefix))
|
||||
{
|
||||
tmp->flags |= CONTEXT_RA_DONE;
|
||||
context->ra_time = 0;
|
||||
}
|
||||
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
u64 addrpart = addr6part(&context->start6);
|
||||
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
|
||||
unsigned int time = context->lease_time;
|
||||
|
||||
/* lifetimes must be min 2 hrs, by RFC 2462 */
|
||||
if (time < 7200)
|
||||
time = 7200;
|
||||
|
||||
opt->type = ICMP6_OPT_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->valid_lifetime = opt->preferred_lifetime = htonl(time);
|
||||
opt->reserved = 0;
|
||||
|
||||
opt->prefix = context->start6;
|
||||
setaddr6part(&opt->prefix, addrpart & ~mask);
|
||||
|
||||
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
}
|
||||
addr = &context->start6;
|
||||
}
|
||||
|
||||
if (addr && (opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
|
||||
|
||||
/* lifetimes must be min 2 hrs, by RFC 2462 */
|
||||
if (time < 7200)
|
||||
time = 7200;
|
||||
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = prefix;
|
||||
/* autonomous only is we're not doing dhcp */
|
||||
opt->flags = do_slaac ? 0x40 : 0x00;
|
||||
opt->valid_lifetime = htonl(time);
|
||||
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
|
||||
opt->reserved = 0;
|
||||
|
||||
opt->prefix = *addr;
|
||||
setaddr6part(&opt->prefix, addrpart & ~mask);
|
||||
|
||||
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@@ -368,11 +403,11 @@ time_t periodic_ra(time_t now)
|
||||
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
|
||||
if (context->ra_time != 0)
|
||||
{
|
||||
if (difftime(context->ra_time, now) < 0.0)
|
||||
if (difftime(context->ra_time, now) <= 0.0)
|
||||
break; /* overdue */
|
||||
|
||||
if (next_event == 0 || difftime(next_event, context->ra_time + 2) > 0.0)
|
||||
next_event = context->ra_time + 2;
|
||||
if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
|
||||
next_event = context->ra_time;
|
||||
}
|
||||
|
||||
/* none overdue */
|
||||
@@ -406,7 +441,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,73 +461,5 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
static int add_subnet(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int dad, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct subnet_map **subnets = vparam;
|
||||
struct subnet_map *map;
|
||||
|
||||
(void)scope;
|
||||
(void)dad;
|
||||
|
||||
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))
|
||||
{
|
||||
for (map = *subnets; map; map = map->next)
|
||||
if (map->iface == 0 ||
|
||||
(map->iface == if_index && is_same_net6(local, &map->subnet, prefix)))
|
||||
break;
|
||||
|
||||
/* It's there already */
|
||||
if (map && map->iface != 0)
|
||||
continue;
|
||||
|
||||
if (!map && (map = whine_malloc(sizeof(struct subnet_map))))
|
||||
{
|
||||
map->next = *subnets;
|
||||
*subnets = map;
|
||||
}
|
||||
|
||||
if (map)
|
||||
{
|
||||
map->iface = if_index;
|
||||
map->subnet = *local;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
struct subnet_map *build_subnet_map(void)
|
||||
{
|
||||
struct subnet_map *map;
|
||||
struct dhcp_context *context;
|
||||
static struct subnet_map *subnets = NULL;
|
||||
|
||||
for (context = daemon->ra_contexts; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
break;
|
||||
|
||||
/* no ra-names, no need to go further. */
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
/* mark unused */
|
||||
for (map = subnets; map; map = map->next)
|
||||
map->iface = 0;
|
||||
|
||||
if (iface_enumerate(AF_INET6, &subnets, add_subnet))
|
||||
return subnets;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
+7
-6
@@ -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),
|
||||
@@ -2095,7 +2095,8 @@ static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_netid_list *id_list;
|
||||
|
||||
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
|
||||
context->netid.next = NULL;
|
||||
if (context)
|
||||
context->netid.next = NULL;
|
||||
tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
|
||||
|
||||
/* logging */
|
||||
|
||||
+111
-45
@@ -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
|
||||
@@ -503,13 +513,13 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
while (1)
|
||||
{
|
||||
struct in6_addr alloced_addr, *addrp = NULL;
|
||||
u32 preferred_time = 0;
|
||||
u32 requested_time = 0;
|
||||
struct dhcp_lease *lease = NULL;
|
||||
|
||||
if (ia_option)
|
||||
{
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
preferred_time = opt6_uint(ia_option, 16, 4);
|
||||
requested_time = opt6_uint(ia_option, 16, 4);
|
||||
|
||||
if (!address6_available(context, req_addr, tags) &&
|
||||
(!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0))
|
||||
@@ -611,10 +621,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
if (ia_option)
|
||||
{
|
||||
if (preferred_time < 120u )
|
||||
preferred_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time))
|
||||
lease_time = preferred_time;
|
||||
if (requested_time < 120u )
|
||||
requested_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
|
||||
lease_time = requested_time;
|
||||
}
|
||||
|
||||
if (lease_time < min_time)
|
||||
@@ -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);
|
||||
@@ -720,8 +730,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(addrp, sizeof(*addrp));
|
||||
put_opt6_long(lease_time);
|
||||
put_opt6_long(lease_time);
|
||||
/* preferred lifetime */
|
||||
put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
|
||||
put_opt6_long(lease_time); /* valid lifetime */
|
||||
end_opt6(o1);
|
||||
|
||||
log6_packet( make_lease ? "DHCPREPLY" : "DHCPADVERTISE",
|
||||
@@ -763,6 +774,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;
|
||||
}
|
||||
@@ -823,7 +843,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
struct dhcp_lease *lease = NULL;
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
u32 preferred_time = opt6_uint(ia_option, 16, 4);
|
||||
u32 requested_time = opt6_uint(ia_option, 16, 4);
|
||||
unsigned int lease_time;
|
||||
struct dhcp_context *this_context;
|
||||
struct dhcp_config *valid_config = config;
|
||||
@@ -854,7 +874,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
if (!address6_available(context, req_addr, tagif) ||
|
||||
!(this_context = narrow_context6(context, req_addr, tagif)))
|
||||
lease_time = 0;
|
||||
{
|
||||
lease_time = 0;
|
||||
this_context = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get tags from context if we've not used it before */
|
||||
@@ -876,10 +899,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time;
|
||||
|
||||
if (preferred_time < 120u )
|
||||
preferred_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time))
|
||||
lease_time = preferred_time;
|
||||
if (requested_time < 120u )
|
||||
requested_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
|
||||
lease_time = requested_time;
|
||||
|
||||
lease_set_expires(lease, lease_time, now);
|
||||
if (ia_type == OPTION6_IA_NA && hostname)
|
||||
@@ -898,17 +921,23 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(req_addr, sizeof(*req_addr));
|
||||
put_opt6_long(lease_time);
|
||||
put_opt6_long(lease_time);
|
||||
/* preferred lifetime */
|
||||
put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
|
||||
put_opt6_long(lease_time); /* valid lifetime */
|
||||
end_opt6(o1);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1319,31 +1348,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 */
|
||||
|
||||
+250
@@ -0,0 +1,250 @@
|
||||
/* 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 or given up? */
|
||||
if (slaac->backoff == 0 || slaac->ping_time == 0)
|
||||
continue;
|
||||
|
||||
if (difftime(slaac->ping_time, now) <= 0.0)
|
||||
{
|
||||
struct ping_packet *ping;
|
||||
struct sockaddr_in6 addr;
|
||||
int err;
|
||||
|
||||
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;
|
||||
|
||||
if (send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
|
||||
(union mysockaddr *)&addr, (struct all_addr *)&slaac->local,
|
||||
lease->last_interface, &err))
|
||||
{
|
||||
slaac->ping_time += (1 << (slaac->backoff - 1)) + (rand16()/21785); /* 0 - 3 */
|
||||
if (slaac->backoff > 4)
|
||||
slaac->ping_time += rand16()/4000; /* 0 - 15 */
|
||||
if (slaac->backoff < 12)
|
||||
slaac->backoff++;
|
||||
}
|
||||
else if (err == EHOSTUNREACH)
|
||||
slaac->ping_time = 0; /* Give up */
|
||||
}
|
||||
|
||||
if (slaac->ping_time != 0 &&
|
||||
(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
|
||||
+47
-14
@@ -57,7 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int mtuflag = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
char namebuff[IF_NAMESIZE];
|
||||
char *name;
|
||||
char *name = NULL;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
struct interface_list *ir;
|
||||
@@ -95,9 +95,20 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
if (listen->iface)
|
||||
{
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we're listening on an address that doesn't appear on an interface,
|
||||
ask the kernel what the socket is bound to */
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -211,15 +222,18 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
mtu = ifr.ifr_mtu;
|
||||
}
|
||||
|
||||
/* check for per-interface prefix */
|
||||
for (pref = daemon->if_prefix; pref; pref = pref->next)
|
||||
if (strcmp(pref->interface, name) == 0)
|
||||
prefix = pref->prefix;
|
||||
|
||||
/* wierd TFTP interfaces disable special options. */
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, name) == 0)
|
||||
special = 1;
|
||||
if (name)
|
||||
{
|
||||
/* check for per-interface prefix */
|
||||
for (pref = daemon->if_prefix; pref; pref = pref->next)
|
||||
if (strcmp(pref->interface, name) == 0)
|
||||
prefix = pref->prefix;
|
||||
|
||||
/* wierd TFTP interfaces disable special options. */
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, name) == 0)
|
||||
special = 1;
|
||||
}
|
||||
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
@@ -571,7 +585,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 +725,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