Compare commits

...
27 Commits
Author SHA1 Message Date
Simon Kelley c8257540bc "deprecated" lease-time keyword for IPv6 2012-03-28 21:15:41 +01:00
Simon Kelley 2240704863 DHCP start-up logging tweak 2012-03-27 14:42:48 +01:00
Simon Kelley e8ca69ea16 Doc updates for latest RA changes. 2012-03-26 21:23:26 +01:00
Simon Kelley da632e7cc1 Comment typo. 2012-03-26 11:14:05 +01:00
Simon Kelley 30cd96663f More flexible RA configuration. 2012-03-25 20:44:38 +01:00
Simon Kelley 7dbe98147d tweak ra timer code to avoid missing events. 2012-03-25 14:49:54 +01:00
Simon Kelley 5d71d83420 Listen on ICMP6 file decriptor even when on ra-only only in use. 2012-03-24 14:40:42 +00:00
Simon Kelley 38a59a9ff7 debian changelog untangle. 2012-03-23 10:08:12 +00:00
Simon Kelley 4b028ad612 Merge branch 'bind' 2012-03-23 10:02:30 +00:00
Simon Kelley 442560beb4 Debian changelog for preivious fix. 2012-03-23 10:01:13 +00:00
Simon Kelley 7d2b5c9583 Fix crash in DHCPINFORM without valid --dhcp-range. 2012-03-23 10:00:02 +00:00
Simon Kelley 29689cfa5a Handle errors when sending ICMP6 pings better. 2012-03-22 14:01:00 +00:00
Simon Kelley 52d4abf2f9 Make --listen-address work for all 127.0.0.0/8 addresses. 2012-03-21 21:39:48 +00:00
Simon Kelley a953096485 Send "FTP transfer complete" events to the DHCP lease script. 2012-03-20 22:07:35 +00:00
Simon Kelley 884a6dfe6d RA managed-bit and use-SLAAC bit tweaks. 2012-03-20 16:20:22 +00:00
Simon Kelley 0068301d24 Conditional compilation tweak. 2012-03-19 20:29:55 +00:00
Simon Kelley 353ae4d270 Check assumed SLAAC addresses by pinging them. 2012-03-19 20:07:51 +00:00
Simon Kelley e759d426fa --host-record support 2012-03-16 13:18:57 +00:00
Simon Kelley 40ef23b547 Move DHCP option stuff to dhcp-common.c 2012-03-13 21:59:28 +00:00
Simon Kelley f5e8562f96 More DHCP-option logging tweaks. 2012-03-13 14:22:30 +00:00
Simon Kelley 1567feae3c Log vendor class for DHCPv6 2012-03-12 22:15:35 +00:00
Simon Kelley daf061c9de randomise DHCPv6 lease renewal intervals 2012-03-12 21:57:18 +00:00
Simon Kelley d0e2c6c9ab decode DHCPv4 T1, T2 and lease-time options better. 2012-03-12 21:44:14 +00:00
Simon Kelley 8643ec7fea Update CHANGLEOG 2012-03-12 20:04:14 +00:00
Simon Kelley 5cfea3d402 Tidy last commit. 2012-03-12 17:28:27 +00:00
Simon Kelley 6c8f21e4a4 More useful DHCPv6 packet logging. 2012-03-12 15:06:55 +00:00
Simon Kelley 1d0f91c4a9 Don't trust the port in the source address of requests.
At least one client gets it wrong: always send to the client port for
clients, and the server port for relays.
2012-03-12 11:56:22 +00:00
27 changed files with 1676 additions and 914 deletions

No files matched your search

+58
View File
@@ -9,6 +9,64 @@ version 2.61
Add --dhcp-duid to allow DUID-EN uids to be used. 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 version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf Fix compilation problem in Mac OS X Lion. Thanks to Olaf
+1 -1
View File
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \ 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 \ 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 \ 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 \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h dns-protocol.h radv-protocol.h
+1 -1
View File
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \ rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c radv.c slaac.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
+10
View File
@@ -34,11 +34,21 @@ if [ ${DNSMASQ_OLD_HOSTNAME} ] && [ ${action} = old ] ; then
hostname=${DNSMASQ_OLD_HOSTNAME} hostname=${DNSMASQ_OLD_HOSTNAME}
fi 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. # action init is not relevant, and will only be seen when leasefile-ro is set.
if [ ${action} = init ] ; then if [ ${action} = init ] ; then
exit 0 exit 0
fi fi
# action tftp is not relevant.
if [ ${action} = tftp ] ; then
exit 0
fi
if [ ${hostname} ]; then if [ ${hostname} ]; then
ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE}) ports=$(sed -n -e "/^${hostname}\ .*/ s/^.* //p" ${PORTSFILE})
+7
View File
@@ -3,9 +3,16 @@ dnsmasq (2.61-1) unstable; urgency=low
* New upstream. * New upstream.
* Provide "dump-stats" initscript method. (closes: #654656) * Provide "dump-stats" initscript method. (closes: #654656)
* Add (empty) build-indep and build-arch rules targets. * 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 -- 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 dnsmasq (2.60-1) unstable; urgency=low
* New upstream. * New upstream.
+1 -1
View File
@@ -3,7 +3,7 @@ Section: net
Priority: optional Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61) Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
Maintainer: Simon Kelley <simon@thekelleys.org.uk> Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Standards-Version: 3.9.2 Standards-Version: 3.9.3
Package: dnsmasq Package: dnsmasq
Architecture: all Architecture: all
+20 -2
View File
@@ -169,14 +169,32 @@
# hosts. Use the DHCPv4 lease to derive the name, network segment and # hosts. Use the DHCPv4 lease to derive the name, network segment and
# MAC address and assume that the host will also have an # MAC address and assume that the host will also have an
# IPv6 address calculated using the SLAAC alogrithm. # 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 #dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet. # Do Router Advertisements, BUT NOT DHCP for this subnet.
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.) # Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
#dhcp-range=1234::, ra-only, 48h #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 # Supply parameters for specified hosts using DHCP. There are lots
# of valid alternatives, so we will give examples of each. Note that # 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 # IP addresses DO NOT have to be in the range given above, they just
+90 -33
View File
@@ -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, order. More than one SRV record for a given service/domain is allowed,
all that match are returned. all that match are returned.
.TP .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>] .B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings, 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 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 included and configured. This option cannot be combined with
--query-port. --query-port.
.TP .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 .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 Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given <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, 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, or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
the default lease time is one hour. The the default lease time is one hour. The
minimum lease time is two minutes. This minimum lease time is two minutes. For IPv6 ranges, the lease time
option may be repeated, with different addresses, to enable DHCP 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, service to more than one network. For directly connected networks (ie,
networks on which the machine running dnsmasq has an interface) the networks on which the machine running dnsmasq has an interface) the
netmask is optional: dnsmasq will determine it from the interface 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 a tag to matching it. Only one tag may be set, but more than one tag
may be matched. may be matched.
The end address may be replaced by the keyword The optional <mode> keyword may be
.B static .B static
which tells dnsmasq to enable DHCP for the network specified, but not which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses: only hosts which have static to dynamically allocate IP addresses: only hosts which have static
@@ -540,34 +560,50 @@ addresses given via
.B dhcp-host .B dhcp-host
or from /etc/ethers will be served. or from /etc/ethers will be served.
The end address may be replaced by Fot IPv4, the <mode> may be
the keyword
.B proxy .B proxy
in which case dnsmasq will provide proxy-DHCP on the specified in which case dnsmasq will provide proxy-DHCP on the specified
subnet. (See subnet. (See
.B pxe-prompt .B pxe-prompt
and and
.B pxe-service .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 .B ra-only
which tells dnsmasq to offer Router Advertisement only on this subnet, tells dnsmasq to offer Router Advertisement only on this subnet,
and not DHCP. This applies to IPv6 only, see and not DHCP.
.B enable-ra
for details. Instead, the keyword .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 .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 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 segment and MAC address and assumes that the host will also have an
IPv6 address calculated using the SLAAC alogrithm, on the same network 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 address. Note that this is only happens for directly-connected
networks, (not one doing DHCP via a relay) and it will generate an networks, (not one doing DHCP via a relay) and it will not work
erroneous AAAA record if a host is using privacy extensions or does if a host is using privacy extensions.
not support IPv6. Use with care. .B ra-names
can be combined with
.B ra-stateless
and
.B slaac.
The interface:<interface name> section is not normally used. See the The interface:<interface name> section is not normally used. See the
NOTES section for details of this. 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. string of hex octets unique to a particular device.
.TP .TP
.B \-6 --dhcp-script=<path> .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> executable specified by this option is run. <path>
must be an absolute pathname, no PATH search occurs. must be an absolute pathname, no PATH search occurs.
The arguments to the process The arguments to the process
@@ -1103,6 +1140,8 @@ is known.
DNSMASQ_TAGS contains all the tags set during the DNSMASQ_TAGS contains all the tags set during the
DHCP transaction, separated by spaces. DHCP transaction, separated by spaces.
DNSMASQ_LOG_DHCP is set if --log-dhcp is in effect.
For IPv4 only: For IPv4 only:
DNSMASQ_CLIENT_ID if the host provided a client-id. 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 since these data are not held in dnsmasq's lease
database. database.
All file descriptors are All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode). (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 leases will be called with "del" and others with "old". When dnsmasq
receives a HUP signal, the script will be invoked for existing leases receives a HUP signal, the script will be invoked for existing leases
with an "old " event. 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 .TP
.B --dhcp-luascript=<path> .B --dhcp-luascript=<path>
Specify a script written in Lua, to be run when leases are created, Specify a script written in Lua, to be run when leases are created,
@@ -1160,11 +1212,13 @@ function, and may provide
and and
.B shutdown .B shutdown
functions, which are called, without arguments when dnsmasq starts up functions, which are called, without arguments when dnsmasq starts up
and terminates. and terminates. It may also provide a
.B tftp
function.
The The
.B lease .B lease
method receives the information detailed in function receives the information detailed in
.B --dhcp-script. .B --dhcp-script.
It gets two arguments, firstly the action, which is a string It gets two arguments, firstly the action, which is a string
containing, "add", "old" or "del", and secondly a table of tag value containing, "add", "old" or "del", and secondly a table of tag value
@@ -1182,6 +1236,15 @@ for IPv4, and
and and
.B hostname .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 .TP
.B --dhcp-scriptuser .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. 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, existing DHCP configuration to provide most data. When RA is enabled,
dnsmasq will advertise a prefix for each dhcp-range, with default dnsmasq will advertise a prefix for each dhcp-range, with default
router and recursive DNS server as the relevant link-local address on router and recursive DNS server as the relevant link-local address on
the machine running dnsmasq. The "managed address" bits are set, the machine running dnsmasq. By default, he "managed address" bits are set, and
except for a dhcp-range which is marked as "ra-only", in which case RA the "use SLAAC" bit is reset. This can be changed for individual
is provided but no DHCPv6 service and the managed address bits are subnets with the mode keywords described in
cleared. .B --dhcp-range.
.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.
.TP .TP
.B --enable-tftp[=<interface>] .B --enable-tftp[=<interface>]
Enable the TFTP server function. This is deliberately limited to that Enable the TFTP server function. This is deliberately limited to that
+41 -22
View File
@@ -634,10 +634,11 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
return NULL; return NULL;
} }
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, 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; int i, nameexists = 0;
struct cname *a; struct cname *a;
unsigned int j; 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; j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
for (lookup = rhash[j]; lookup; lookup = lookup->next) 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) memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{ {
flags &= ~F_REVERSE; cache->flags &= ~F_REVERSE;
break; break;
} }
@@ -684,7 +685,6 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
rhash[j] = cache; rhash[j] = cache;
} }
cache->flags = flags;
cache->uid = index; cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen); memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache); 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. */ /* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists) if (!nameexists)
for (a = daemon->cnames; a; a = a->next) 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 = whine_malloc(sizeof(struct crec))))
{ {
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME; 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++; lineno++;
#ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0) if (inet_pton(AF_INET, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ; addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4); domain_suffix = get_domain(addr.addr.addr4);
} }
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, token, &addr) > 0) else if (inet_pton(AF_INET6, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ; addrlen = IN6ADDRSZ;
domain_suffix = get_domain6(&addr.addr.addr6); 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 #endif
else else
{ {
@@ -830,13 +823,15 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
strcat(cache->name.sname, "."); strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix); 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++; name_count++;
} }
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME))) if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{ {
strcpy(cache->name.sname, canon); 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++; name_count++;
} }
free(canon); free(canon);
@@ -860,6 +855,8 @@ void cache_reload(void)
struct crec *cache, **up, *tmp; struct crec *cache, **up, *tmp;
int revhashsz, i, total_size = daemon->cachesize; int revhashsz, i, total_size = daemon->cachesize;
struct hostsfile *ah; struct hostsfile *ah;
struct host_record *hr;
struct name_list *nl;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
@@ -886,6 +883,34 @@ void cache_reload(void)
up = &cache->hash_next; 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 (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
{ {
if (daemon->cachesize > 0) if (daemon->cachesize > 0)
@@ -893,12 +918,6 @@ void cache_reload(void)
return; 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)) if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz); total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
+1 -1
View File
@@ -167,7 +167,7 @@ HAVE_SOLARIS_NETWORK
define exactly one of these to alter interaction with kernel networking. define exactly one of these to alter interaction with kernel networking.
HAVE_GETOPT_LONG HAVE_GETOPT_LONG
defined when GNU-sty;e getopt_long available. defined when GNU-style getopt_long available.
HAVE_ARC4RANDOM HAVE_ARC4RANDOM
defined if arc4random() available to get better security from DNS spoofs defined if arc4random() available to get better security from DNS spoofs
+301
View File
@@ -444,4 +444,305 @@ void join_multicast(void)
} }
#endif #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 #endif
+1 -1
View File
@@ -299,7 +299,7 @@ void dhcp_packet(time_t now, int pxe_fd)
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz, iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); now, unicast_dest, &is_inform, pxe_fd, iface_addr);
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns(0);
if (iov.iov_len == 0) if (iov.iov_len == 0)
return; return;
+19 -10
View File
@@ -75,6 +75,7 @@ void dhcp6_packet(time_t now)
ssize_t sz; ssize_t sz;
struct ifreq ifr; struct ifreq ifr;
struct iname *tmp; struct iname *tmp;
unsigned short port;
msg.msg_control = control_u.control6; msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u); msg.msg_controllen = sizeof(control_u);
@@ -84,7 +85,7 @@ void dhcp6_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet; msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1; 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; return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) 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 */ lease_prune(NULL, now); /* lose any expired leases */
sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now); sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns(0);
if (sz != 0) /* The port in the source address of the original request should
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) == -1 && 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()); retry_send());
}
} }
static int complete_context6(struct in6_addr *local, int prefix, 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 (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current) 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; continue;
else if (!match_netid(c->filter, netids, pass)) else if (!match_netid(c->filter, netids, pass))
continue; continue;
@@ -273,9 +282,9 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
start = addr6part(&tmp->start6); start = addr6part(&tmp->start6);
end = addr6part(&tmp->end6); end = addr6part(&tmp->end6);
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) && if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
is_same_net6(&context->start6, taddr, context->prefix) && is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
is_same_net6(&context->end6, taddr, context->prefix) && is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
addr >= start && addr >= start &&
addr <= end && addr <= end &&
match_netid(tmp->filter, netids, 1)) match_netid(tmp->filter, netids, 1))
+84 -46
View File
@@ -209,13 +209,6 @@ int main (int argc, char **argv)
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used) if (if_tmp->name && !if_tmp->used)
die(_("unknown interface %s"), if_tmp->name, EC_BADNET); 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 else
create_wildcard_listeners(); create_wildcard_listeners();
@@ -537,7 +530,7 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled")); my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6) if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
{ {
struct dhcp_context *dhcp_tmp; struct dhcp_context *dhcp_tmp;
int family = AF_INET; int family = AF_INET;
@@ -556,23 +549,50 @@ int main (int argc, char **argv)
{ {
start = &dhcp_tmp->start6; start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6; end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
} }
#endif #endif
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time); if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
inet_ntop(family, start, daemon->dhcp_buff, 256); strcpy(daemon->namebuff, _("prefix deprecated"));
inet_ntop(family, end, daemon->dhcp_buff3, 256); else
my_syslog(MS_DHCP | LOG_INFO, {
(dhcp_tmp->flags & CONTEXT_STATIC) ? char *p = daemon->namebuff;
_("DHCP, static leases only on %.0s%s, lease time %s") : p += sprintf(p, _("lease time "));
(dhcp_tmp->flags & CONTEXT_RA_NAME) ? prettyprint_time(p, dhcp_tmp->lease_time);
_("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") : if (daemon->dhcp_buff)
(dhcp_tmp->flags & CONTEXT_PROXY) ? inet_ntop(family, start, daemon->dhcp_buff, 256);
_("DHCP, proxy on subnet %.0s%s%.0s") : if (daemon->dhcp_buff3)
_("DHCP, IP range %s -- %s, lease time %s"), inet_ntop(family, end, daemon->dhcp_buff3, 256);
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2); 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 #ifdef HAVE_DHCP6
@@ -700,12 +720,12 @@ int main (int argc, char **argv)
{ {
FD_SET(daemon->dhcp6fd, &rset); FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd); bump_maxfd(daemon->dhcp6fd, &maxfd);
}
if (daemon->ra_contexts) if (daemon->ra_contexts)
{ {
FD_SET(daemon->icmp6fd, &rset); FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd); bump_maxfd(daemon->icmp6fd, &maxfd);
}
} }
#endif #endif
@@ -721,6 +741,10 @@ int main (int argc, char **argv)
# ifdef HAVE_SCRIPT # ifdef HAVE_SCRIPT
while (helper_buf_empty() && do_script_run(now)); while (helper_buf_empty() && do_script_run(now));
# ifdef HAVE_TFTP
while (helper_buf_empty() && do_tftp_script_run());
# endif
if (!helper_buf_empty()) if (!helper_buf_empty())
{ {
FD_SET(daemon->helperfd, &wset); FD_SET(daemon->helperfd, &wset);
@@ -729,6 +753,11 @@ int main (int argc, char **argv)
# else # else
/* need this for other side-effects */ /* need this for other side-effects */
while (do_script_run(now)); while (do_script_run(now));
# ifdef HAVE_TFTP
while (do_tftp_script_run());
# endif
# endif # 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) 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 #ifdef HAVE_DHCP6
else if (daemon->ra_contexts) else if (daemon->ra_contexts)
{ /* Not doing DHCP, so no lease system, manage alarms for ra only */
/* Not doing DHCP, so no lease system, manage send_alarm(periodic_ra(now), now);
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
#endif #endif
#endif #endif
break; break;
@@ -1158,7 +1190,7 @@ void clear_cache_and_reload(time_t now)
check_dhcp_hosts(0); check_dhcp_hosts(0);
lease_update_from_configs(); lease_update_from_configs();
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns(1);
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (daemon->ra_contexts) else if (daemon->ra_contexts)
@@ -1272,18 +1304,19 @@ static void check_dns_listeners(fd_set *set, time_t now)
int confd; int confd;
struct irec *iface = NULL; struct irec *iface = NULL;
pid_t p; 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; continue;
if (option_bool(OPT_NOWILD)) if (option_bool(OPT_NOWILD))
iface = listener->iface; iface = listener->iface; /* May be NULL */
else else
{ {
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
/* Check for allowed interfaces when binding the wildcard address: /* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as 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 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 too, for localisation. */
/* interface may be new since startup */ /* interface may be new since startup */
if (enumerate_interfaces() && if (enumerate_interfaces())
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr)) if (sockaddr_isequal(&iface->addr, &tcp_addr))
break; break;
} }
if (!iface) if (!iface && !option_bool(OPT_NOWILD))
{ {
shutdown(confd, SHUT_RDWR); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);
@@ -1324,6 +1356,12 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff; unsigned char *buff;
struct server *s; struct server *s;
int flags; int flags;
struct in_addr netmask;
if (iface)
netmask = iface->netmask;
else
netmask.s_addr = 0;
#ifndef NO_FORK #ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
@@ -1342,7 +1380,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1) if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); 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); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);
+75 -28
View File
@@ -274,6 +274,18 @@ struct cname {
struct cname *next; 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 { struct interface_name {
char *name; /* domain name */ char *name; /* domain name */
char *intr; /* interface name */ char *intr; /* interface name */
@@ -383,7 +395,7 @@ struct irec {
struct listener { struct listener {
int fd, tcpfd, tftpfd, family; 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; struct listener *next;
}; };
@@ -432,11 +444,21 @@ struct frec {
struct frec *next; 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 */ /* actions in the daemon->helper RPC */
#define ACTION_DEL 1 #define ACTION_DEL 1
#define ACTION_OLD_HOSTNAME 2 #define ACTION_OLD_HOSTNAME 2
#define ACTION_OLD 3 #define ACTION_OLD 3
#define ACTION_ADD 4 #define ACTION_ADD 4
#define ACTION_TFTP 5
#define LEASE_NEW 1 /* newly created */ #define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */ #define LEASE_CHANGED 2 /* modified */
@@ -445,6 +467,7 @@ struct frec {
#define LEASE_USED 16 /* used this DHCPv6 transaction */ #define LEASE_USED 16 /* used this DHCPv6 transaction */
#define LEASE_NA 32 /* IPv6 no-temporary lease */ #define LEASE_NA 32 /* IPv6 no-temporary lease */
#define LEASE_TA 64 /* IPv6 temporary lease */ #define LEASE_TA 64 /* IPv6 temporary lease */
#define LEASE_HAVE_HWADDR 128 /* Have set hwaddress */
struct dhcp_lease { struct dhcp_lease {
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
@@ -462,6 +485,14 @@ struct dhcp_lease {
unsigned char *extradata; unsigned char *extradata;
unsigned int extradata_len, extradata_size; unsigned int extradata_len, extradata_size;
int last_interface; 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; struct dhcp_lease *next;
}; };
@@ -606,7 +637,7 @@ struct dhcp_context {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */ struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6; struct in6_addr local6;
int prefix; int prefix, if_index;
time_t ra_time; time_t ra_time;
#endif #endif
int flags; int flags;
@@ -615,13 +646,16 @@ struct dhcp_context {
struct dhcp_context *next, *current; struct dhcp_context *next, *current;
}; };
#define CONTEXT_STATIC 1 #define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2 #define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4 #define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8 #define CONTEXT_PROXY 8
#define CONTEXT_RA_ONLY 16 #define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32 #define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64 #define CONTEXT_RA_NAME 64
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
#define CONTEXT_DEPRECATE 512
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
@@ -630,13 +664,6 @@ struct ping_result {
struct ping_result *next; struct ping_result *next;
}; };
struct subnet_map {
int iface;
struct in6_addr subnet;
struct subnet_map *next;
};
struct tftp_file { struct tftp_file {
int refcount, fd; int refcount, fd;
off_t size; off_t size;
@@ -686,6 +713,7 @@ extern struct daemon {
struct naptr *naptr; struct naptr *naptr;
struct txt_record *txt; struct txt_record *txt;
struct ptr_record *ptr; struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail;
struct cname *cnames; struct cname *cnames;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
@@ -779,7 +807,7 @@ extern struct daemon {
#endif #endif
/* TFTP stuff */ /* 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 */ /* utility string buffer, hold max sized IP address as string */
char *addrbuff; char *addrbuff;
@@ -886,9 +914,9 @@ unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask); union mysockaddr *local_addr, struct in_addr netmask);
void server_gone(struct server *server); void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait); 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, union mysockaddr *to, struct all_addr *source,
unsigned int iface); unsigned int iface, int *errp);
/* network.c */ /* network.c */
int indextoname(int fd, int index, char *name); int indextoname(int fd, int index, char *name);
@@ -935,7 +963,7 @@ char *host_from_dns(struct in_addr addr);
/* lease.c */ /* lease.c */
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
void lease_update_file(time_t now); void lease_update_file(time_t now);
void lease_update_dns(); void lease_update_dns(int force);
void lease_init(time_t now); void lease_init(time_t now);
struct dhcp_lease *lease4_allocate(struct in_addr addr); struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6 #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); int lease_type, int iaid, struct in6_addr *addr);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 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); u64 lease_find_max_addr6(struct dhcp_context *context);
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface);
#endif #endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, 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_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_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, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
unsigned char *clid, int clid_len); unsigned char *clid, int clid_len);
struct dhcp_lease *lease_find_by_addr(struct in_addr addr); 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 make_icmp_sock(void);
int icmp_ping(struct in_addr addr); int icmp_ping(struct in_addr addr);
#endif #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 send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now); void clear_cache_and_reload(time_t now);
void poll_resolv(int force, int do_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 #endif
/* helper.c */ /* 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); int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void); void helper_write(void);
void queue_script(int action, struct dhcp_lease *lease, void queue_script(int action, struct dhcp_lease *lease,
char *hostname, time_t now); 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); int helper_buf_empty(void);
#endif #endif
@@ -1022,6 +1054,7 @@ int helper_buf_empty(void);
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
void tftp_request(struct listener *listen, time_t now); void tftp_request(struct listener *listen, time_t now);
void check_tftp_listeners(fd_set *rset, time_t now); void check_tftp_listeners(fd_set *rset, time_t now);
int do_tftp_script_run(void);
#endif #endif
/* conntrack.c */ /* conntrack.c */
@@ -1053,8 +1086,8 @@ void make_duid(time_t now);
/* rfc3315.c */ /* rfc3315.c */
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, 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); struct in6_addr *fallback, size_t sz, int is_multicast, time_t now);
#endif #endif
/* dhcp-common.c */ /* 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); int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
void dhcp_update_configs(struct dhcp_config *configs); void dhcp_update_configs(struct dhcp_config *configs);
void check_dhcp_hosts(int fatal); 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 # ifdef HAVE_DHCP6
void display_opts6(void);
void join_multicast(void); void join_multicast(void);
# endif # endif
#endif #endif
@@ -1093,6 +1132,14 @@ void put_opt6_string(char *s);
void ra_init(time_t now); void ra_init(time_t now);
void icmp6_packet(void); void icmp6_packet(void);
time_t periodic_ra(time_t now); time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now); void ra_start_unsolicted(time_t now, struct dhcp_context *context);
struct subnet_map *build_subnet_map(void); #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 #endif
+15 -8
View File
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
/* Send a UDP packet with its source address set as "source" /* Send a UDP packet with its source address set as "source"
unless nowild is true, when we just send it with the kernel default */ 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, int send_from(int fd, int nowild, char *packet, size_t len,
union mysockaddr *to, struct all_addr *source, union mysockaddr *to, struct all_addr *source,
unsigned int iface) unsigned int iface, int *errp)
{ {
struct msghdr msg; struct msghdr msg;
struct iovec iov[1]; struct iovec iov[1];
@@ -110,8 +110,15 @@ void send_from(int fd, int nowild, char *packet, size_t len,
if (retry_send()) if (retry_send())
goto retry; 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, 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) if (udpfd != -1)
{ {
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl); 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; return 0;
@@ -621,7 +628,7 @@ void reply_query(int fd, int family, time_t now)
header->id = htons(forward->orig_id); header->id = htons(forward->orig_id);
header->hb4 |= HB4_RA; /* recursion if available */ header->hb4 |= HB4_RA; /* recursion if available */
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn, 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 */ free_frec(forward); /* cancel */
} }
@@ -660,7 +667,7 @@ void receive_query(struct listener *listen, time_t now)
/* packet buffer overwritten */ /* packet buffer overwritten */
daemon->srv_save = NULL; 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; dst_addr_4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask; netmask = listen->iface->netmask;
@@ -816,7 +823,7 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1) if (m >= 1)
{ {
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header, 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++; daemon->local_answer++;
} }
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index, else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
+241 -168
View File
@@ -193,16 +193,22 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
_exit(0); _exit(0);
} }
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
if (data.action == ACTION_DEL) if (data.action == ACTION_DEL)
action_str = "del"; action_str = "del";
else if (data.action == ACTION_ADD) else if (data.action == ACTION_ADD)
action_str = "add"; action_str = "add";
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME) else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
action_str = "old"; action_str = "old";
else if (data.action == ACTION_TFTP)
{
action_str = "tftp";
is6 = (data.flags != AF_INET);
}
else else
continue; continue;
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
if (!is6) if (!is6)
{ {
@@ -271,12 +277,15 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *dot; char *dot;
hostname = (char *)buf; hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0; hostname[data.hostname_len - 1] = 0;
if (!legal_hostname(hostname)) if (data.action != ACTION_TFTP)
hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{ {
domain = dot+1; if (!legal_hostname(hostname))
*dot = 0; hostname = NULL;
else if ((dot = strchr(hostname, '.')))
{
domain = dot+1;
*dot = 0;
}
} }
} }
@@ -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); inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
#endif #endif
/* file length */
if (data.action == ACTION_TFTP)
sprintf(daemon->dhcp_buff, "%u", data.hwaddr_len);
#ifdef HAVE_LUASCRIPT #ifdef HAVE_LUASCRIPT
if (daemon->luascript) if (daemon->luascript)
{ {
lua_getglobal(lua, "lease"); /* function to call */ if (data.action == ACTION_TFTP)
lua_pushstring(lua, action_str); /* arg1 - action */
lua_newtable(lua); /* arg2 - data table */
if (is6)
{ {
lua_pushstring(lua, daemon->dhcp_buff); lua_getglobal(lua, "tftp");
lua_setfield(lua, -2, "client_duid"); if (lua_type(lua, -1) != LUA_TFUNCTION)
lua_pushstring(lua, daemon->packet); lua_pop(lua, 1); /* tftp function optional */
lua_setfield(lua, -2, "server_duid"); else
lua_pushstring(lua, daemon->dhcp_buff3); {
lua_setfield(lua, -2, "iaid"); 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 */
}
} }
else
if (!is6 && data.clid_len != 0)
{ {
lua_pushstring(lua, daemon->packet); lua_getglobal(lua, "lease"); /* function to call */
lua_setfield(lua, -2, "client_id"); lua_pushstring(lua, action_str); /* arg1 - action */
} lua_newtable(lua); /* arg2 - data table */
if (strlen(data.interface) != 0) if (is6)
{ {
lua_pushstring(lua, data.interface); lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "interface"); 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 #ifdef HAVE_BROKEN_RTC
lua_pushnumber(lua, data.length); lua_pushnumber(lua, data.length);
lua_setfield(lua, -2, "lease_length"); lua_setfield(lua, -2, "lease_length");
#else #else
lua_pushnumber(lua, data.expires); lua_pushnumber(lua, data.expires);
lua_setfield(lua, -2, "lease_expires"); lua_setfield(lua, -2, "lease_expires");
#endif #endif
if (hostname) if (hostname)
{ {
lua_pushstring(lua, hostname); lua_pushstring(lua, hostname);
lua_setfield(lua, -2, "hostname"); lua_setfield(lua, -2, "hostname");
} }
if (domain) if (domain)
{ {
lua_pushstring(lua, domain); lua_pushstring(lua, domain);
lua_setfield(lua, -2, "domain"); lua_setfield(lua, -2, "domain");
} }
end = extradata + data.ed_len; end = extradata + data.ed_len;
buf = extradata; buf = extradata;
if (!is6) if (!is6)
buf = grab_extradata_lua(buf, end, "vendor_class"); buf = grab_extradata_lua(buf, end, "vendor_class");
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else else
for (i = 0; i < data.hwaddr_len; i++) for (i = 0; i < data.hwaddr_len; i++)
{ {
sprintf(daemon->dhcp_buff2, "vendor_class%i", i); sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
} }
#endif #endif
buf = grab_extradata_lua(buf, end, "supplied_hostname"); buf = grab_extradata_lua(buf, end, "supplied_hostname");
if (!is6) if (!is6)
{ {
buf = grab_extradata_lua(buf, end, "cpewan_oui"); buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial"); buf = grab_extradata_lua(buf, end, "cpewan_serial");
buf = grab_extradata_lua(buf, end, "cpewan_class"); 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 #endif
@@ -439,80 +473,86 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue; continue;
} }
if (is6) if (data.action != ACTION_TFTP)
{ {
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err); if (is6)
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err); {
} my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
my_setenv("DNSMASQ_SERVER_DUID", daemon->packet, &err);
}
if (!is6 && data.clid_len != 0) if (!is6 && data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err); my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
if (strlen(data.interface) != 0) if (strlen(data.interface) != 0)
my_setenv("DNSMASQ_INTERFACE", data.interface, &err); my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err); my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
#else #else
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err); my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
#endif #endif
if (domain) if (domain)
my_setenv("DNSMASQ_DOMAIN", domain, &err); my_setenv("DNSMASQ_DOMAIN", domain, &err);
end = extradata + data.ed_len; end = extradata + data.ed_len;
buf = extradata; buf = extradata;
if (!is6) if (!is6)
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err); buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else else
{
if (data.hwaddr_len != 0)
{ {
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err); if (data.hwaddr_len != 0)
for (i = 0; i < data.hwaddr_len - 1; i++)
{ {
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i); buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &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 #endif
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err); buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
if (!is6) if (!is6)
{ {
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err); 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_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &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_TAGS", &err); if (option_bool(OPT_LOG_OPTS))
my_setenv("DNSMASQ_LOG_DHCP", "1", &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;
}
/* we need to have the event_fd around if exec fails */ /* we need to have the event_fd around if exec fails */
if ((i = fcntl(event_fd, F_GETFD)) != -1) if ((i = fcntl(event_fd, F_GETFD)) != -1)
@@ -584,11 +624,29 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
} }
#endif #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 */ /* pack up lease data into a buffer */
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now) void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
{ {
unsigned char *p; unsigned char *p;
size_t size;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0; unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd; int fd = daemon->dhcpfd;
@@ -608,23 +666,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
if (hostname) if (hostname)
hostname_len = strlen(hostname) + 1; hostname_len = strlen(hostname) + 1;
size = sizeof(struct script_data) + clid_len + ed_len + hostname_len; buff_alloc(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;
}
buf->action = action; buf->action = action;
buf->flags = lease->flags; 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; 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) int helper_buf_empty(void)
{ {
return bytes_in_buf == 0; return bytes_in_buf == 0;
+68 -52
View File
@@ -97,7 +97,8 @@ void lease_init(time_t now)
if (hw_type == 0 && hw_len != 0) if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER; 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) if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL); 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))) 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) if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL); 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; next_event = 0;
#ifdef HAVE_DHCP6 #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) 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 #endif
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
@@ -326,8 +334,7 @@ void lease_update_file(time_t now)
(unsigned int)difftime(next_event, now)); (unsigned int)difftime(next_event, now));
} }
if (next_event != 0) send_alarm(next_event, now);
alarm((unsigned)difftime(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) for (lease = leases; lease; lease = lease->next)
if (!(lease->flags & (LEASE_TA | LEASE_NA))) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net(local, lease->addr, netmask)) if (is_same_net(local, lease->addr, netmask))
lease->last_interface = if_index; lease_set_interface(lease, if_index, *((time_t *)vparam));
return 1; return 1;
} }
@@ -353,17 +360,22 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
(void) scope; (void)scope;
(void) vparam;
(void)dad; (void)dad;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA))) if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix)) 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; return 1;
} }
void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface)
{
slaac_ping_reply(sender, packet, interface, leases);
}
#endif #endif
@@ -373,9 +385,13 @@ static int find_interface_v6(struct in6_addr *local, int prefix,
start-time. */ start-time. */
void lease_find_interfaces(time_t now) void lease_find_interfaces(time_t now)
{ {
iface_enumerate(AF_INET, NULL, find_interface_v4);
#ifdef HAVE_DHCP6 #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 we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (!daemon->duid && daemon->dhcp6) 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; 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(); cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
@@ -409,41 +421,15 @@ void lease_update_dns(void)
prot = AF_INET6; prot = AF_INET6;
else if (lease->hostname || lease->fqdn) else if (lease->hostname || lease->fqdn)
{ {
struct subnet_map *map; struct slaac_address *slaac;
for (map = subnets; map; map = map->next)
if (lease->last_interface == map->iface) 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) 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) 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 #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, 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 || if (hw_len != lease->hwaddr_len ||
hw_type != lease->hwaddr_type || hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0)) (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->hwaddr_type = hw_type;
lease->flags |= LEASE_CHANGED; lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */ file_dirty = 1; /* run script on change */
#ifdef HAVE_DHCP6
change = 1;
#endif
} }
/* only update clid when one is available, stops packets /* 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); free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len))) if (!(lease->clid = whine_malloc(clid_len)))
return; return;
#ifdef HAVE_DHCP6
change = 1;
#endif
} }
else if (memcmp(lease->clid, clid, clid_len) != 0) else if (memcmp(lease->clid, clid, clid_len) != 0)
{ {
lease->flags |= LEASE_AUX_CHANGED; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1; file_dirty = 1;
#ifdef HAVE_DHCP6
change = 1;
#endif
} }
lease->clid_len = clid_len; lease->clid_len = clid_len;
memcpy(lease->clid, clid, 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) 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 */ 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) if (lease->last_interface == interface)
return; return;
lease->last_interface = interface; lease->last_interface = interface;
lease->flags |= LEASE_CHANGED; lease->flags |= LEASE_CHANGED;
#ifdef HAVE_DHCP6
slaac_add_addrs(lease, now);
#endif
} }
void rerun_scripts(void) void rerun_scripts(void)
@@ -919,6 +927,14 @@ int do_script_run(time_t now)
} }
else 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); kill_name(lease);
#ifdef HAVE_SCRIPT #ifdef HAVE_SCRIPT
queue_script(ACTION_DEL, lease, lease->old_hostname, now); queue_script(ACTION_DEL, lease, lease->old_hostname, now);
+3 -2
View File
@@ -345,10 +345,11 @@ static void nl_routechange(struct nlmsghdr *h)
/* force RAs to sync new network and pick up new interfaces. */ /* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts) 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 /* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */ iface_enumerate and can't re-enter it now */
send_alarm(); send_alarm(0, 0);
} }
#endif #endif
+20
View File
@@ -511,6 +511,7 @@ void create_bound_listeners(int dienow)
{ {
struct listener *new; struct listener *new;
struct irec *iface; struct irec *iface;
struct iname *if_tmp;
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
if (!iface->done && !iface->dad && if (!iface->done && !iface->dad &&
@@ -521,6 +522,25 @@ void create_bound_listeners(int dienow)
daemon->listeners = new; daemon->listeners = new;
iface->done = 1; 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) int is_dad_listeners(void)
+105 -341
View File
@@ -116,6 +116,7 @@ struct myoption {
#define LOPT_LUASCRIPT 305 #define LOPT_LUASCRIPT 305
#define LOPT_RA 306 #define LOPT_RA 306
#define LOPT_DUID 307 #define LOPT_DUID 307
#define LOPT_HOST_REC 308
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -237,6 +238,7 @@ static const struct myoption opts[] =
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT }, { "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
{ "enable-ra", 0, 0, LOPT_RA }, { "enable-ra", 0, 0, LOPT_RA },
{ "dhcp-duid", 1, 0, LOPT_DUID }, { "dhcp-duid", 1, 0, LOPT_DUID },
{ "host-record", 1, 0, LOPT_HOST_REC },
{ NULL, 0, 0, 0 } { 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_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_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_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 } { 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 (opt_len != 0 && 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 /* 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 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 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 #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) 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)); struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
char lenchar = 0, *cp; 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; char *comma = NULL, *problem = NULL;
struct dhcp_netid *np = NULL; struct dhcp_netid *np = NULL;
u16 opt_len = 0; u16 opt_len = 0;
@@ -897,14 +644,8 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (strstr(arg, "option:") == arg) if (strstr(arg, "option:") == arg)
{ {
for (i = 0; opttab[i].name; i++) new->opt = lookup_dhcp_opt(AF_INET, arg+7);
if (!(opttab[i].size & OT_INTERNAL) && opt_len = lookup_dhcp_len(AF_INET, new->opt);
strcasecmp(opttab[i].name, arg+7) == 0)
{
new->opt = opttab[i].val;
opt_len = opttab[i].size;
break;
}
/* option:<optname> must follow tag and vendor string. */ /* option:<optname> must follow tag and vendor string. */
break; break;
} }
@@ -921,14 +662,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
opt_len = 0; opt_len = 0;
} }
else else
for (i = 0; opttab6[i].name; i++) {
if (!(opttab6[i].size & OT_INTERNAL) && new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
strcasecmp(opttab6[i].name, arg+8) == 0) opt_len = lookup_dhcp_len(AF_INET6, new->opt);
{ }
new->opt = opttab6[i].val;
opt_len = opttab6[i].size;
break;
}
/* option6:<opt>|<optname> must follow tag and vendor string. */ /* option6:<opt>|<optname> must follow tag and vendor string. */
is6 = 1; is6 = 1;
break; break;
@@ -977,27 +714,13 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (opt_len == 0 && if (opt_len == 0 &&
!(new->flags & DHOPT_RFC3925)) !(new->flags & DHOPT_RFC3925))
for (i = 0; opttab6[i].name; i++) opt_len = lookup_dhcp_len(AF_INET6 ,new->opt);
if (new->opt == opttab6[i].val)
{
opt_len = opttab6[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
} }
else else
#endif #endif
if (opt_len == 0 && if (opt_len == 0 &&
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925))) !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
for (i = 0; opttab[i].name; i++) opt_len = lookup_dhcp_len(AF_INET ,new->opt);
if (new->opt == opttab[i].val)
{
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
/* option may be missing with rfc3925 match */ /* option may be missing with rfc3925 match */
if (new->opt == 0) if (new->opt == 0)
@@ -1262,10 +985,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
else if (comma && (opt_len & OT_CSTRING)) else if (comma && (opt_len & OT_CSTRING))
{ {
/* length fields are two bytes so need 16 bits for each string */ /* length fields are two bytes so need 16 bits for each string */
int commas = 1; int i, commas = 1;
unsigned char *p, *newp; unsigned char *p, *newp;
for(i = 0; comma[i]; i++) for (i = 0; comma[i]; i++)
if (comma[i] == ',') if (comma[i] == ',')
commas++; commas++;
@@ -1290,10 +1013,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
} }
else if (comma && (opt_len & OT_RFC1035_NAME)) else if (comma && (opt_len & OT_RFC1035_NAME))
{ {
int commas = 1; int i, commas = 1;
unsigned char *p, *newp; unsigned char *p, *newp;
for(i = 0; comma[i]; i++) for (i = 0; comma[i]; i++)
if (comma[i] == ',') if (comma[i] == ',')
commas++; commas++;
@@ -2236,7 +1959,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
case 'F': /* --dhcp-range */ case 'F': /* --dhcp-range */
{ {
int k, leasepos = 2; 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)); struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
memset (new, 0, sizeof(*new)); 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]))) if (!(a[k] = split(a[k-1])))
break; break;
@@ -2297,17 +2020,12 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{ {
new->next = daemon->dhcp; new->next = daemon->dhcp;
daemon->dhcp = new; daemon->dhcp = new;
new->end = new->start;
if (strcmp(a[1], "static") == 0) if (strcmp(a[1], "static") == 0)
{ new->flags |= CONTEXT_STATIC;
new->end = new->start;
new->flags |= CONTEXT_STATIC;
}
else if (strcmp(a[1], "proxy") == 0) else if (strcmp(a[1], "proxy") == 0)
{ new->flags |= CONTEXT_PROXY;
new->end = new->start; else if (!inet_pton(AF_INET, a[1], &new->end))
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?'; option = '?';
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr)) 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)) else if (inet_pton(AF_INET6, a[0], &new->start6))
{ {
new->prefix = 64; /* default */ new->prefix = 64; /* default */
new->end6 = new->start6;
if (strcmp(a[1], "static") == 0) for (leasepos = 1; leasepos < k; leasepos++)
{ {
memcpy(&new->end6, &new->start6, IN6ADDRSZ); if (strcmp(a[leasepos], "static") == 0)
new->flags |= CONTEXT_STATIC; 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;
} }
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) if (new->flags & CONTEXT_DHCP)
{
new->next = daemon->ra_contexts;
daemon->ra_contexts = new;
}
else
{ {
new->next = daemon->dhcp6; new->next = daemon->dhcp6;
daemon->dhcp6 = new; daemon->dhcp6 = new;
} }
else
{
new->next = daemon->ra_contexts;
daemon->ra_contexts = new;
}
/* bare integer < 128 is prefix value */ /* bare integer < 128 is prefix value */
if (option != '?' && k >= 3) if (option != '?' && leasepos < k)
{ {
int pref; int pref;
for (cp = a[2]; *cp; cp++) for (cp = a[leasepos]; *cp; cp++)
if (!(*cp >= '0' && *cp <= '9')) if (!(*cp >= '0' && *cp <= '9'))
break; break;
if (!*cp && (pref = atoi(a[2])) <= 128) if (!*cp && (pref = atoi(a[leasepos])) <= 128)
{ {
new->prefix = pref; new->prefix = pref;
leasepos = 3; leasepos++;
if ((new->flags & CONTEXT_RA_ONLY) && new->prefix != 64) if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) &&
new->prefix != 64)
problem = _("prefix must be exactly 64 for RA subnets"); problem = _("prefix must be exactly 64 for RA subnets");
else if (new->prefix < 64) else if (new->prefix < 64)
problem = _("prefix must be at least 64"); problem = _("prefix must be at least 64");
} }
} }
if (!problem && !is_same_net6(&new->start6, &new->end6, new->prefix)) if (!problem && !is_same_net6(&new->start6, &new->end6, new->prefix))
problem = _("inconsistent DHCPv6 range"); problem = _("inconsistent DHCPv6 range");
else if (addr6part(&new->start6) > addr6part(&new->end6)) 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 #endif
if (k >= leasepos+1) if (leasepos < k)
{ {
if (strcmp(a[leasepos], "infinite") == 0) if (strcmp(a[leasepos], "infinite") == 0)
new->lease_time = 0xffffffff; new->lease_time = 0xffffffff;
else if (strcmp(a[leasepos], "deprecated") == 0)
new->flags |= CONTEXT_DEPRECATE;
else else
{ {
int fac = 1; 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; break;
} }
@@ -3310,6 +3021,59 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
break; 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: default:
return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)"); return _("unsupported option (check that dnsmasq was compiled with DHCP/TFTP/DBus support)");
+7 -3
View File
@@ -17,6 +17,13 @@
#define ALL_HOSTS "FF02::1" #define ALL_HOSTS "FF02::1"
#define ALL_ROUTERS "FF02::2" #define ALL_ROUTERS "FF02::2"
struct ping_packet {
u8 type, code;
u16 checksum;
u16 identifier;
u16 sequence_no;
};
struct ra_packet { struct ra_packet {
u8 type, code; u8 type, code;
u16 checksum; u16 checksum;
@@ -32,9 +39,6 @@ struct prefix_opt {
struct in6_addr prefix; struct in6_addr prefix;
}; };
#define ICMP6_ROUTER_SOLICIT 133
#define ICMP6_ROUTER_ADVERT 134
#define ICMP6_OPT_SOURCE_MAC 1 #define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3 #define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5 #define ICMP6_OPT_MTU 5
+96 -129
View File
@@ -27,7 +27,7 @@
#include <netinet/icmp6.h> #include <netinet/icmp6.h>
struct ra_param { struct ra_param {
int ind, managed, found_context, first; int ind, managed, other, found_context, first;
char *if_name; char *if_name;
struct in6_addr link_local; struct in6_addr link_local;
}; };
@@ -55,13 +55,20 @@ void ra_init(time_t now)
#endif #endif
int val = 255; /* radvd uses this value */ int val = 255; /* radvd uses this value */
socklen_t len = sizeof(int); socklen_t len = sizeof(int);
struct dhcp_context *context;
/* ensure this is around even if we're not doing DHCPv6 */ /* ensure this is around even if we're not doing DHCPv6 */
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet)); 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_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &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 || if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) || getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
@@ -77,21 +84,21 @@ void ra_init(time_t now)
daemon->icmp6fd = fd; 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 some/all soon. some ra_times will end up zeroed
/* init timers so that we do ra's for all soon. some ra_times will end up zeroed
if it's not appropriate to advertise those contexts. if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */ and pick up new interfaces */
/* range 0 - 5 */ if (context)
for (context = daemon->ra_contexts; context; context = context->next) context->ra_time = now;
context->ra_time = now + (rand16()/13000); 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. */ /* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now; ra_short_period_start = now;
@@ -158,7 +165,19 @@ void icmp6_packet(void)
p = (unsigned char *)daemon->outpacket.iov_base; 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; return;
/* look for link-layer address option for logging */ /* look for link-layer address option for logging */
@@ -184,16 +203,17 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
save_counter(0); save_counter(0);
ra = expand(sizeof(struct ra_packet)); ra = expand(sizeof(struct ra_packet));
ra->type = ICMP6_ROUTER_ADVERT; ra->type = ND_ROUTER_ADVERT;
ra->code = 0; ra->code = 0;
ra->hop_limit = hop_limit; ra->hop_limit = hop_limit;
ra->flags = 0; ra->flags = 0x00;
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/ ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
ra->reachable_time = 0; ra->reachable_time = 0;
ra->retrans_time = 0; ra->retrans_time = 0;
parm.ind = iface; parm.ind = iface;
parm.managed = 0; parm.managed = 0;
parm.other = 0;
parm.found_context = 0; parm.found_context = 0;
parm.if_name = iface_name; parm.if_name = iface_name;
parm.first = 1; parm.first = 1;
@@ -227,7 +247,9 @@ 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 */ /* set managed bits unless we're providing only RA on this link */
if (parm.managed) 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 */ /* decide where we're sending */
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
@@ -238,7 +260,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
addr.sin6_port = htons(IPPROTO_ICMPV6); addr.sin6_port = htons(IPPROTO_ICMPV6);
if (dest) if (dest)
{ {
memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr)); addr.sin6_addr = *dest;
if (IN6_IS_ADDR_LINKLOCAL(dest) || if (IN6_IS_ADDR_LINKLOCAL(dest) ||
IN6_IS_ADDR_MC_LINKLOCAL(dest)) IN6_IS_ADDR_MC_LINKLOCAL(dest))
addr.sin6_scope_id = iface; 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); inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0), 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, static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam) int scope, int if_index, int dad, void *vparam)
{ {
struct dhcp_context *context, *tmp; struct dhcp_context *context;
struct ra_param *param = vparam; struct ra_param *param = vparam;
struct prefix_opt *opt;
(void)scope; /* warning */ (void)scope; /* warning */
(void)dad; (void)dad;
@@ -269,64 +290,78 @@ static int add_prefixes(struct in6_addr *local, int prefix,
!IN6_IS_ADDR_LINKLOCAL(local) && !IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(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) for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix && if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, 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 */ /* don't do RA for non-ra-only unless --enable-ra is set */
if (!option_bool(OPT_RA)) if (!option_bool(OPT_RA))
continue; continue;
param->managed = 1; param->managed = 1;
param->other = 1;
} }
if (context->flags & CONTEXT_RA_DONE) /* find floor time */
continue; 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) if (!param->first)
context->ra_time = 0; context->ra_time = 0;
param->first = 0; param->first = 0;
param->found_context = 1; param->found_context = 1;
if (context->flags & CONTEXT_RA_DONE)
continue;
context->flags |= CONTEXT_RA_DONE; context->flags |= CONTEXT_RA_DONE;
addr = &context->start6;
/* 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);
}
} }
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; 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) for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
if (context->ra_time != 0) if (context->ra_time != 0)
{ {
if (difftime(context->ra_time, now) < 0.0) if (difftime(context->ra_time, now) <= 0.0)
break; /* overdue */ break; /* overdue */
if (next_event == 0 || difftime(next_event, context->ra_time + 2) > 0.0) if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
next_event = context->ra_time + 2; next_event = context->ra_time;
} }
/* none overdue */ /* none overdue */
@@ -406,7 +441,7 @@ static int iface_search(struct in6_addr *local, int prefix,
if (prefix == context->prefix && if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, 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 /* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface 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 */ 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 #endif
+7 -6
View File
@@ -483,14 +483,14 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
{ {
logaddr = &mess->yiaddr; 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) if (hostname)
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain); lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
/* infinite lease unless nailed in dhcp-host line. */ /* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease, lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
now); now);
lease_set_interface(lease, int_index); lease_set_interface(lease, int_index, now);
clear_packet(mess, end); clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), 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)); 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 all the netids in the ignore_name list are present, ignore client-supplied name */
if (!hostname_auth) 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_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
lease_set_expires(lease, time, now); lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index); lease_set_interface(lease, int_index, now);
if (override.s_addr != 0) if (override.s_addr != 0)
lease->override = override; lease->override = override;
@@ -1387,7 +1387,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else else
time = (unsigned int)difftime(lease->expires, now); time = (unsigned int)difftime(lease->expires, now);
option_put(mess, end, OPTION_LEASE_TIME, 4, time); 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), 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; struct dhcp_netid_list *id_list;
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */ /* 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); tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
/* logging */ /* logging */
+108 -46
View File
@@ -23,6 +23,7 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
int interface, char *iface_name, struct in6_addr *fallback, void *inbuff, size_t sz, int is_unicast, time_t now); 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, 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); 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 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); static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
@@ -34,11 +35,17 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)])) #define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, 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 in6_addr *fallback, size_t sz, int is_unicast, time_t now)
{ {
struct dhcp_netid *relay_tags = NULL; struct dhcp_netid *relay_tags = NULL;
struct dhcp_vendor *vendor; 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 */ /* Mark these so we only match each at most once, to avoid tangled linked lists */
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next) for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
@@ -47,7 +54,7 @@ size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name
save_counter(0); save_counter(0);
if (dhcp6_maybe_relay(NULL, &relay_tags, context, interface, iface_name, fallback, daemon->dhcp_packet.iov_base, sz, is_unicast, now)) 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; 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. /* 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. 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 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) while (1)
{ {
struct in6_addr alloced_addr, *addrp = NULL; struct in6_addr alloced_addr, *addrp = NULL;
u32 preferred_time = 0; u32 requested_time = 0;
struct dhcp_lease *lease = NULL; struct dhcp_lease *lease = NULL;
if (ia_option) if (ia_option)
{ {
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); 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) && if (!address6_available(context, req_addr, tags) &&
(!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0)) (!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 (ia_option)
{ {
if (preferred_time < 120u ) if (requested_time < 120u )
preferred_time = 120u; /* sanity */ requested_time = 120u; /* sanity */
if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time)) if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = preferred_time; lease_time = requested_time;
} }
if (lease_time < min_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) if (lease)
{ {
lease_set_expires(lease, lease_time, now); lease_set_expires(lease, lease_time, now);
lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len); lease_set_hwaddr(lease, NULL, clid, 0, iaid, clid_len, now);
lease_set_interface(lease, interface); lease_set_interface(lease, interface, now);
if (hostname && ia_type == OPTION6_IA_NA) if (hostname && ia_type == OPTION6_IA_NA)
{ {
char *addr_domain = get_domain6(addrp); 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); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(addrp, sizeof(*addrp)); put_opt6(addrp, sizeof(*addrp));
put_opt6_long(lease_time); /* preferred lifetime */
put_opt6_long(lease_time); put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
put_opt6_long(lease_time); /* valid lifetime */
end_opt6(o1); end_opt6(o1);
log6_packet( make_lease ? "DHCPREPLY" : "DHCPADVERTISE", log6_packet( make_lease ? "DHCPREPLY" : "DHCPADVERTISE",
@@ -764,9 +775,14 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
end_opt6(o); end_opt6(o);
o = new_opt6(OPTION6_PREFERENCE); if (address_assigned)
put_opt6_char(0); {
end_opt6(o); /* 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; break;
} }
@@ -827,7 +843,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{ {
struct dhcp_lease *lease = NULL; struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0); 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; unsigned int lease_time;
struct dhcp_context *this_context; struct dhcp_context *this_context;
struct dhcp_config *valid_config = config; struct dhcp_config *valid_config = config;
@@ -858,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) || if (!address6_available(context, req_addr, tagif) ||
!(this_context = narrow_context6(context, req_addr, tagif))) !(this_context = narrow_context6(context, req_addr, tagif)))
lease_time = 0; {
lease_time = 0;
this_context = NULL;
}
else else
{ {
/* get tags from context if we've not used it before */ /* get tags from context if we've not used it before */
@@ -880,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; lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time;
if (preferred_time < 120u ) if (requested_time < 120u )
preferred_time = 120u; /* sanity */ requested_time = 120u; /* sanity */
if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time)) if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
lease_time = preferred_time; lease_time = requested_time;
lease_set_expires(lease, lease_time, now); lease_set_expires(lease, lease_time, now);
if (ia_type == OPTION6_IA_NA && hostname) if (ia_type == OPTION6_IA_NA && hostname)
@@ -902,17 +921,23 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o1 = new_opt6(OPTION6_IAADDR); o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr)); put_opt6(req_addr, sizeof(*req_addr));
put_opt6_long(lease_time); /* preferred lifetime */
put_opt6_long(lease_time); put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
put_opt6_long(lease_time); /* valid lifetime */
end_opt6(o1); end_opt6(o1);
} }
if (t1cntr != 0) if (t1cntr != 0)
{ {
/* go back an fill in fields in IA_NA option */ /* 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); 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(t1);
put_opt6_long(t2); put_opt6_long(t2);
save_counter(sav); save_counter(sav);
@@ -1323,29 +1348,66 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
log_tags(tagif, xid); log_tags(tagif, xid);
if (option_bool(OPT_LOG_OPTS)) if (option_bool(OPT_LOG_OPTS))
{ log6_opts(0, xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
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);
}
}
return 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) static void log6_packet(char *type, unsigned char *clid, int clid_len, struct in6_addr *addr, int xid, char *iface, char *string)
+250
View File
@@ -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
+46 -13
View File
@@ -57,7 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
int mtuflag = IP_PMTUDISC_DONT; int mtuflag = IP_PMTUDISC_DONT;
#endif #endif
char namebuff[IF_NAMESIZE]; char namebuff[IF_NAMESIZE];
char *name; char *name = NULL;
char *prefix = daemon->tftp_prefix; char *prefix = daemon->tftp_prefix;
struct tftp_prefix *pref; struct tftp_prefix *pref;
struct interface_list *ir; struct interface_list *ir;
@@ -95,9 +95,20 @@ void tftp_request(struct listener *listen, time_t now)
if (option_bool(OPT_NOWILD)) if (option_bool(OPT_NOWILD))
{ {
addr = listen->iface->addr; if (listen->iface)
mtu = listen->iface->mtu; {
name = listen->iface->name; 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 else
{ {
@@ -211,15 +222,18 @@ void tftp_request(struct listener *listen, time_t now)
mtu = ifr.ifr_mtu; mtu = ifr.ifr_mtu;
} }
/* check for per-interface prefix */ if (name)
for (pref = daemon->if_prefix; pref; pref = pref->next) {
if (strcmp(pref->interface, name) == 0) /* check for per-interface prefix */
prefix = pref->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. */ /* wierd TFTP interfaces disable special options. */
for (ir = daemon->tftp_interfaces; ir; ir = ir->next) for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
if (strcmp(ir->interface, name) == 0) if (strcmp(ir->interface, name) == 0)
special = 1; special = 1;
}
if (listen->family == AF_INET) 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); my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
/* unlink */ /* unlink */
*up = tmp; *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; 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 #endif