mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
63
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef1a94abaa | ||
|
|
d9fb0be8c7 | ||
|
|
3f3adae6bc | ||
|
|
1ecbaaa382 | ||
|
|
d859ca2f9b | ||
|
|
b4b9308079 | ||
|
|
e2ba0df2d4 | ||
|
|
921360ce62 | ||
|
|
429805dbbc | ||
|
|
0da5e8979b | ||
|
|
baa80ae512 | ||
|
|
3e8ed78bf1 | ||
|
|
48493329d6 | ||
|
|
76dd75de77 | ||
|
|
63fd27e35f | ||
|
|
115ac3e4d7 | ||
|
|
cfcad42ff1 | ||
|
|
3f2873d42c | ||
|
|
ab915f837c | ||
|
|
ddd9a6b499 | ||
|
|
7abb69b5dc | ||
|
|
d5052fb24f | ||
|
|
b5a7ff42bb | ||
|
|
48fd1c4dd6 | ||
|
|
2bb73af7d1 | ||
|
|
86e92f9983 | ||
|
|
1c10b9de11 | ||
|
|
a66d36ea11 | ||
|
|
aa63a21ce0 | ||
|
|
797a7afba4 | ||
|
|
4b5ea12e90 | ||
|
|
2b6390fdc9 | ||
|
|
bd08ae67f9 | ||
|
|
4582c0efe7 | ||
|
|
834f36fe6d | ||
|
|
6f130def07 | ||
|
|
3931a7bd85 | ||
|
|
d9ee9c0872 | ||
|
|
0b0a73c1c9 | ||
|
|
81925ab73a | ||
|
|
9de1aa9b7f | ||
|
|
6f9aaa93e9 | ||
|
|
7e5664bdbc | ||
|
|
83f28bef6c | ||
|
|
96c727fda6 | ||
|
|
49dc570a72 | ||
|
|
cd1e04a234 | ||
|
|
27cb314e54 | ||
|
|
56a1142f03 | ||
|
|
5b37aa8c19 | ||
|
|
8ac9787350 | ||
|
|
9f9bd08af8 | ||
|
|
4c985dac39 | ||
|
|
3d77c0460d | ||
|
|
3ddad24608 | ||
|
|
6e37ab595c | ||
|
|
a1a79edaea | ||
|
|
49333cbdbe | ||
|
|
de92b479d9 | ||
|
|
0f128eb58c | ||
|
|
c630924d66 | ||
|
|
ff59fc82b3 | ||
|
|
52a1ae72f0 |
No files matched your search
@@ -1,3 +1,85 @@
|
||||
version 2.67
|
||||
Fix crash if upstream server returns SERVFAIL when
|
||||
--conntrack in use. Thanks to Giacomo Tazzari for finding
|
||||
this and supplying the patch.
|
||||
|
||||
Repair regression in 2.64. That release stopped sending
|
||||
lease-time information in the reply to DHCPINFORM
|
||||
requests, on the correct grounds that it was a standards
|
||||
violation. However, this broke the dnsmasq-specific
|
||||
dhcp_lease_time utility. Now, DHCPINFORM returns
|
||||
lease-time only if it's specifically requested
|
||||
(maintaining standards) and the dhcp_lease_time utility
|
||||
has been taught to ask for it (restoring functionality).
|
||||
|
||||
Fix --dhcp-match, --dhcp-vendorclass and --dhcp-userclass
|
||||
to work with BOOTP and well as DHCP. Thanks to Peter
|
||||
Korsgaard for spotting the problem.
|
||||
|
||||
Add --synth-domain. Thanks to Vishvananda Ishaya for
|
||||
suggesting this.
|
||||
|
||||
Fix failure to compile ipset.c if old kernel headers are
|
||||
in use. Thanks to Eugene Rudoy for pointing this out.
|
||||
|
||||
Handle IPv4 interface-address labels in Linux. These are
|
||||
often used to emulate the old IP-alias addresses. Before,
|
||||
using --interface=eth0 would service all the addresses of
|
||||
eth0, including ones configured as aliases, which appear
|
||||
in ifconfig as eth0:0. Now, only addresses with the label
|
||||
eth0 are active. This is not backwards compatible: if you
|
||||
want to continue to bind the aliases too, you need to add
|
||||
eg. --interface=eth0:0 to the config.
|
||||
|
||||
Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket
|
||||
operation on non-socket" error on startup with
|
||||
configurations which have exactly one --interface option
|
||||
and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
|
||||
bug report.
|
||||
|
||||
Generalise --interface-name to cope with IPv6 addresses
|
||||
and multiple addresses per interface per address family.
|
||||
|
||||
Fix option parsing for --dhcp-host, which was generating a
|
||||
spurious error when all seven possible items were
|
||||
included. Thanks to Zhiqiang Wang for the bug report.
|
||||
|
||||
Remove restriction on prefix-length in --auth-zone. Thanks
|
||||
to Toke Hoiland-Jorgensen for suggesting this.
|
||||
|
||||
Log when the maximum number of concurrent DNS queries is
|
||||
reached. Thanks to Marcelo Salhab Brogliato for the patch.
|
||||
|
||||
If wildcards are used in --interface, don't assume that
|
||||
there will only ever be one available interface for DHCP
|
||||
just because there is one at start-up. More may appear, so
|
||||
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
|
||||
report.
|
||||
|
||||
Increase timeout/number of retries in TFTP to accomodate
|
||||
AudioCodes Voice Gateways doing streaming writes to flash.
|
||||
Thanks to Damian Kaczkowski for spotting the problem.
|
||||
|
||||
Allow hostnames to start with a number, as allowed in
|
||||
RFC-1123. Thanks to Kyle Mestery for the patch.
|
||||
|
||||
Fixes to DHCP FQDN option handling: don't terminate FQDN
|
||||
if domain not known and allow a FQDN option with blank
|
||||
name to request that a FQDN option is returned in the
|
||||
reply. Thanks to Roy Marples for the patch.
|
||||
|
||||
Make --clear-on-reload apply to setting upstream servers
|
||||
via DBus too.
|
||||
|
||||
When the address which triggered the construction of an
|
||||
advertised IPv6 prefix disappears, continue to advertise
|
||||
the prefix for up to 2 hours, with the preferred lifetime
|
||||
set to zero. This satisfies RFC 6204 4.3 L-13 and makes
|
||||
things work better if a prefix disappears without being
|
||||
deprecated first. Thanks to Uwe Schindler for persuasively
|
||||
arguing for this.
|
||||
|
||||
|
||||
version 2.66
|
||||
Add the ability to act as an authoritative DNS
|
||||
server. Dnsmasq can now answer queries from the wider 'net
|
||||
@@ -33,7 +115,7 @@ version 2.66
|
||||
|
||||
Add DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBCRIBER_ID,
|
||||
DNSMASQ_REMOTE_ID variables to the environment of the
|
||||
lease-change script (and the correponding Lua). These hold
|
||||
lease-change script (and the corresponding Lua). These hold
|
||||
information inserted into the DHCP request by a DHCP relay
|
||||
agent. Thanks to Lakefield Communications for providing a
|
||||
bounty for this addition.
|
||||
@@ -47,9 +129,25 @@ version 2.66
|
||||
patch.
|
||||
|
||||
Don't erroneously reject some option names in --dhcp-match
|
||||
options. Thnaks to Benedikt Hochstrasser for the bug report.
|
||||
options. Thanks to Benedikt Hochstrasser for the bug report.
|
||||
|
||||
Allow a trailing '*' wildcard in all interface-name
|
||||
configurations. Thanks to Christian Parpart for the patch.
|
||||
|
||||
Handle the situation where libc headers define
|
||||
SO_REUSEPORT, but the kernel in use doesn't, to cope with
|
||||
the introduction of this option to Linux. Thanks to Rich
|
||||
Felker for the bug report.
|
||||
|
||||
Update Polish translation. Thanks to Jan Psota.
|
||||
|
||||
Fix crash if the configured DHCP lease limit is
|
||||
reached. Regression occurred in 2.61. Thanks to Tsachi for
|
||||
the bug report.
|
||||
|
||||
Update the French translation. Thanks to Gildas le Nadan.
|
||||
|
||||
|
||||
version 2.65
|
||||
Fix regression which broke forwarding of queries sent via
|
||||
TCP which are not for A and AAAA and which were directed to
|
||||
|
||||
@@ -22,7 +22,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
|
||||
now uses a new, randomly selected, port for each query. The old
|
||||
default behaviour (use one port allocated by the OS) is available by
|
||||
setting --query-port=0, and setting the query port to a positive
|
||||
value is still works. You should think hard and know what you are
|
||||
value still works. You should think hard and know what you are
|
||||
doing before using either of these options.
|
||||
|
||||
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
||||
@@ -112,7 +112,7 @@ A: Resolver code sometime does strange things when given names without
|
||||
hostname will fix things. (ie "ping myhost" fails, but "ping
|
||||
myhost." works. The solution is to make sure that all your hosts
|
||||
have a domain set ("domain" in resolv.conf, or set a domain in
|
||||
your DHCP server, see below fr Windows XP and Mac OS X).
|
||||
your DHCP server, see below for Windows XP and Mac OS X).
|
||||
Any domain will do, but "localnet" is traditional. Now when you
|
||||
resolve "myhost" the resolver will attempt to look up
|
||||
"myhost.localnet" so you need to have dnsmasq reply to that name.
|
||||
|
||||
@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
|
||||
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o
|
||||
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o domain.o
|
||||
|
||||
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
|
||||
dns-protocol.h radv-protocol.h
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c \
|
||||
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
|
||||
radv.c slaac.c auth.c ipset.c
|
||||
radv.c slaac.c auth.c ipset.c domain.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
|
||||
@@ -12,9 +12,11 @@ If an error occurs or no lease exists for the given address,
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||
Requires dnsmasq 2.67 or later and may not work with other DHCP servers.
|
||||
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
The address argument is a dotted-quad IP addresses and mandatory.
|
||||
.SH LIMITATIONS
|
||||
Only works with IPv4 addresses and DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
nothing is sent to stdout a message is sent to stderr and a
|
||||
non-zero error code is returned.
|
||||
|
||||
Requires dnsmasq 2.40 or later.
|
||||
This version requires dnsmasq 2.67 or later.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -46,6 +46,7 @@
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_END 255
|
||||
#define DHCPINFORM 8
|
||||
#define DHCP_SERVER_PORT 67
|
||||
@@ -167,6 +168,12 @@ int main(int argc, char **argv)
|
||||
*(p++) = 1;
|
||||
*(p++) = DHCPINFORM;
|
||||
|
||||
/* Explicity request the lease time, it won't be sent otherwise:
|
||||
this is a dnsmasq extension, not standard. */
|
||||
*(p++) = OPTION_REQUESTED_OPTIONS;
|
||||
*(p++) = 1;
|
||||
*(p++) = OPTION_LEASE_TIME;
|
||||
|
||||
*(p++) = OPTION_END;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
|
||||
@@ -27,6 +27,8 @@ for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||
The client-id is optional. If it is "*" then it treated as being missing.
|
||||
.SH NOTES
|
||||
MUST be run as root - will fail otherwise.
|
||||
.SH LIMITATIONS
|
||||
Only usable on IPv4 DHCP leases.
|
||||
.SH SEE ALSO
|
||||
.BR dnsmasq (8)
|
||||
.SH AUTHOR
|
||||
|
||||
Vendored
+18
@@ -1,3 +1,21 @@
|
||||
dnsmasq (2.67-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:50:22 +0000
|
||||
|
||||
dnsmasq (2.66-3) unstable; urgency=low
|
||||
|
||||
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
|
||||
|
||||
dnsmasq (2.66-2) unstable; urgency=low
|
||||
|
||||
* Fix error on startup with some configs. (closes: #709010)
|
||||
|
||||
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
|
||||
|
||||
dnsmasq (2.66-1) unstable; urgency=low
|
||||
|
||||
* New upstream.
|
||||
|
||||
Vendored
+27
-12
@@ -1,16 +1,14 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
#
|
||||
# Script to update the resolver list for dnsmasq
|
||||
#
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||
# If dnsmasq is installed then we go ahead and update
|
||||
# the resolver list in case dnsmasq is started later.
|
||||
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
|
||||
# If dnsmasq is installed then we go ahead and update the resolver list
|
||||
# in case dnsmasq is started later.
|
||||
#
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||
# Assumption: On entry, PWD contains the resolv.conf-type files.
|
||||
#
|
||||
# Requires bash because it uses a non-POSIX printf extension.
|
||||
#
|
||||
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||
# This file is part of the dnsmasq package.
|
||||
#
|
||||
|
||||
set -e
|
||||
@@ -18,6 +16,8 @@ set -e
|
||||
RUN_DIR="/var/run/dnsmasq"
|
||||
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||
MY_RECORD_NAME="lo.dnsmasq"
|
||||
DNSCRYPT_RECORD_NAME="lo.dnscrypt"
|
||||
|
||||
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||
@@ -27,7 +27,7 @@ PATH=/bin:/sbin
|
||||
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||
|
||||
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||
# Doesn't work properly if an argument itself contain whitespace
|
||||
# Doesn't work properly if an argument itself contains whitespace
|
||||
uniquify()
|
||||
{
|
||||
RSLT=""
|
||||
@@ -45,7 +45,22 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||
RSLVCNFFILES=""
|
||||
for F in $(/lib/resolvconf/list-records) ; do
|
||||
case "$F" in
|
||||
"$MY_RECORD_NAME")
|
||||
# Omit
|
||||
;;
|
||||
"$DNSCRYPT_RECORD_NAME")
|
||||
# Dnscrypt, I only have eyes for you
|
||||
RSLVCNFFILES="$DNSCRYPT_RECORD_NAME"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
NMSRVRS=""
|
||||
if [ "$RSLVCNFFILES" ] ; then
|
||||
@@ -56,8 +71,8 @@ fi
|
||||
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||
# within one second of the previous one then dnsmasq may fail to notice the
|
||||
# more recent change. To work around this problem we sleep here to ensure
|
||||
# that the new mtime is different.
|
||||
# more recent change. To work around this problem we sleep one second here
|
||||
# if necessary in order to ensure that the new mtime is different.
|
||||
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
Vendored
+2
-4
@@ -33,10 +33,8 @@ ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
|
||||
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||
COPTS += -DHAVE_IPSET
|
||||
endif
|
||||
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
|
||||
COPTS += -DNO_IPSET
|
||||
endif
|
||||
|
||||
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
|
||||
|
||||
+87
-29
@@ -22,7 +22,10 @@ send any desired set of DHCP options, including vendor-encapsulated
|
||||
options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. The PXE support is full featured, and includes a proxy mode which supplies PXE information to clients whilst DHCP address allocation is done by another server.
|
||||
.PP
|
||||
The dnsmasq DHCPv6 server provides the same set of features as the DHCPv4 server, and in addition, it includes router advertisements and a neat feature which allows nameing for clients which use DHCPv4 and RA only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
|
||||
The dnsmasq DHCPv6 server provides the same set of features as the
|
||||
DHCPv4 server, and in addition, it includes router advertisements and
|
||||
a neat feature which allows nameing for clients which use DHCPv4 and
|
||||
stateless autoconfiguration only for IPv6 configuration. There is support for doing address allocation (both DHCPv6 and RA) from subnets which are dynamically delegated via DHCPv6 prefix delegation.
|
||||
.PP
|
||||
Dnsmasq is coded with small embedded systems in mind. It aims for the smallest possible memory footprint compatible with the supported functions, and allows uneeded functions to be omitted from the compiled binary.
|
||||
.SH OPTIONS
|
||||
@@ -171,7 +174,12 @@ options. IP alias interfaces (eg "eth1:0") cannot be used with
|
||||
.B --interface
|
||||
or
|
||||
.B --except-interface
|
||||
options, use --listen-address instead.
|
||||
options, use --listen-address instead. A simple wildcard, consisting
|
||||
of a trailing '*', can be used in
|
||||
.B \--interface
|
||||
and
|
||||
.B \--except-interface
|
||||
options.
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Do not listen on the specified interface. Note that the order of
|
||||
@@ -184,7 +192,7 @@ options does not matter and that
|
||||
options always override the others.
|
||||
.TP
|
||||
.B --auth-server=<domain>,<interface>|<ip-address>
|
||||
Enable DNS authoritative mode for queries arriving at an interface or address. Note that the the interface or address
|
||||
Enable DNS authoritative mode for queries arriving at an interface or address. Note that the interface or address
|
||||
need not be mentioned in
|
||||
.B --interface
|
||||
or
|
||||
@@ -330,7 +338,8 @@ by '/', like the --server syntax, eg.
|
||||
Don't poll /etc/resolv.conf for changes.
|
||||
.TP
|
||||
.B --clear-on-reload
|
||||
Whenever /etc/resolv.conf is re-read, clear the DNS cache.
|
||||
Whenever /etc/resolv.conf is re-read or the upstream servers are set
|
||||
via DBus, clear the DNS cache.
|
||||
This is useful when new nameservers may have different
|
||||
data than that held in cache.
|
||||
.TP
|
||||
@@ -511,6 +520,22 @@ the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.TP
|
||||
.B --synth-domain=<domain>,<address range>[,<prefix>]
|
||||
Create artificial A/AAAA and PTR records for an address range. The
|
||||
records use the address, with periods (or colons for IPv6) replaced
|
||||
with dashes.
|
||||
|
||||
An example should make this clearer.
|
||||
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
|
||||
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
|
||||
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
|
||||
but IPv6 addresses may start with '::'
|
||||
but DNS labels may not start with '-' so in this case if no prefix is
|
||||
configured a zero is added in front of the label. ::1 becomes 0--1.
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask>
|
||||
.TP
|
||||
.B --add-mac
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
@@ -548,12 +573,18 @@ If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.TP
|
||||
.B --auth-zone=<domain>[,<subnet>[,<subnet>.....]]
|
||||
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
|
||||
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
|
||||
will be served, except that A and AAAA records must be in one of the
|
||||
specified subnets, or in a subnet corresponding to a contructed DHCP
|
||||
range. The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries.
|
||||
will be served. A and AAAA records must be in one of the
|
||||
specified subnets, or in a subnet corresponding to a constructed DHCP
|
||||
range. (This can be overridden with
|
||||
.B constructor-noauth:
|
||||
) The subnet(s) are also used to define in-addr.arpa and
|
||||
ipv6.arpa domains which are served for reverse-DNS queries. If not
|
||||
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
|
||||
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
|
||||
unless you are familiar with RFC 2317 and have arranged the
|
||||
in-addr.arpa delegation accordingly.
|
||||
.TP
|
||||
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
|
||||
Specify fields in the SOA record associated with authoritative
|
||||
@@ -563,12 +594,12 @@ zones. Note that this is optional, all the values are set to sane defaults.
|
||||
Specify any secondary servers for a zone for which dnsmasq is
|
||||
authoritative. These servers must be configured to get zone data from
|
||||
dnsmasq by zone transfer, and answer queries for the same
|
||||
authoritative zones and dnsmasq.
|
||||
authoritative zones as dnsmasq.
|
||||
.TP
|
||||
.B --auth-peer=<ip-address>[,<ip-address>[,<ip-address>...]]
|
||||
Specify the addresses of secondary servers which are allowed to
|
||||
initiate zone transfer (AXFR) requests for zones for which dnsmasq is
|
||||
authoritative. If this option is not given, then AXFR requests wil be
|
||||
authoritative. If this option is not given, then AXFR requests will be
|
||||
accepted from any secondary.
|
||||
.TP
|
||||
.B --conntrack
|
||||
@@ -581,9 +612,9 @@ compiled in and the kernel must have conntrack support
|
||||
included and configured. This option cannot be combined with
|
||||
--query-port.
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-addr>[,<end-addr>][,<mode>][,<netmask>[,<broadcast>]][,<lease time>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>[,<end-IPv6addr>|constuctor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
.B \-F, --dhcp-range=[tag:<tag>[,tag:<tag>],][set:<tag>,]<start-IPv6addr>[,<end-IPv6addr>|constructor:<interface>][,<mode>][,<prefix-len>][,<lease time>]
|
||||
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -619,9 +650,24 @@ IPv6 (only) supports another type of range. In this, the start address and optio
|
||||
.B constructor:<interface>.
|
||||
This forms a template which describes how to create ranges, based on the addresses assigned to the interface. For instance
|
||||
|
||||
.B --dhcp-range=::1,::4,constructor:eth0
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
will look for addreses of the form <network>::1 on eth0 and then create a range from <network>::1 to <network>::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard.
|
||||
will look for addresses of the form <network>::1 or <network>:400 on
|
||||
eth0 and then create a range from <network>::1 to <network>::400. If
|
||||
the interface is assigned more than one network, then the
|
||||
corresponding ranges will be automatically created, and then
|
||||
deprecated and finally removed again as the address is deprecated and
|
||||
then deleted. The interface name may have a final "*" wildcard. Note
|
||||
that just any address on eth0 will not do: the non-prefix part must be
|
||||
equal either the start or end address given in the dhcp-range. This is
|
||||
to prevent prefixes becoming perpetual if the interface
|
||||
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
|
||||
|
||||
There is a variant of the constructor: syntax using the keyword
|
||||
.B constructor-noauth.
|
||||
See
|
||||
.B --auth-zone
|
||||
for an explanation of this.
|
||||
|
||||
The optional
|
||||
.B set:<tag>
|
||||
@@ -725,7 +771,7 @@ may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
IPv6 addresses may contain only the host-identifier part:
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
in which case thay act as wildcards in constructed dhcp ranges, with
|
||||
in which case they act as wildcards in constructed dhcp ranges, with
|
||||
the appropriate network part inserted.
|
||||
Note that in IPv6 DHCP, the hardware address is not normally
|
||||
available, so a client must be identified by client-id (called client
|
||||
@@ -754,7 +800,7 @@ This is
|
||||
useful when there is another DHCP server on the network which should
|
||||
be used by some machines.
|
||||
|
||||
The set:<tag> contruct sets the tag
|
||||
The set:<tag> construct sets the tag
|
||||
whenever this dhcp-host directive is in use. This can be used to
|
||||
selectively send DHCP options just for this host. More than one tag
|
||||
can be set in a dhcp-host directive (but not in other places where
|
||||
@@ -969,7 +1015,7 @@ agent ID and one provided by a relay agent, the tag is set.
|
||||
(IPv4 only) A normal DHCP relay agent is only used to forward the initial parts of
|
||||
a DHCP interaction to the DHCP server. Once a client is configured, it
|
||||
communicates directly with the server. This is undesirable if the
|
||||
relay agent is addding extra information to the DHCP packets, such as
|
||||
relay agent is adding extra information to the DHCP packets, such as
|
||||
that used by
|
||||
.B dhcp-circuitid
|
||||
and
|
||||
@@ -986,7 +1032,7 @@ relays at those addresses are affected.
|
||||
Without a value, set the tag if the client sends a DHCP
|
||||
option of the given number or name. When a value is given, set the tag only if
|
||||
the option is sent and matches the value. The value may be of the form
|
||||
"01:ff:*:02" in which case the value must match (apart from widcards)
|
||||
"01:ff:*:02" in which case the value must match (apart from wildcards)
|
||||
but the option sent may have unmatched data past the end of the
|
||||
value. The value may also be of the same form as in
|
||||
.B dhcp-option
|
||||
@@ -999,7 +1045,7 @@ will set the tag "efi-ia32" if the the number 6 appears in the list of
|
||||
architectures sent by the client in option 93. (See RFC 4578 for
|
||||
details.) If the value is a string, substring matching is used.
|
||||
|
||||
The special form with vi-encap:<enterpise number> matches against
|
||||
The special form with vi-encap:<enterprise number> matches against
|
||||
vendor-identifying vendor classes for the specified enterprise. Please
|
||||
see RFC 3925 for more details of these rare and interesting beasts.
|
||||
.TP
|
||||
@@ -1027,7 +1073,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
|
||||
.TP
|
||||
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
|
||||
(IPv4 only) Generate a name for DHCP clients which do not otherwise have one,
|
||||
using the MAC address expressed in hex, seperated by dashes. Note that
|
||||
using the MAC address expressed in hex, separated by dashes. Note that
|
||||
if a host provides a name, it will be used by preference to this,
|
||||
unless
|
||||
.B --dhcp-ignore-names
|
||||
@@ -1104,7 +1150,7 @@ timeout has elapsed with no keyboard input, the first available menu
|
||||
option will be automatically executed. If the timeout is zero then the first available menu
|
||||
item will be executed immediately. If
|
||||
.B pxe-prompt
|
||||
is ommitted the system will wait for user input if there are multiple
|
||||
is omitted the system will wait for user input if there are multiple
|
||||
items in the menu, but boot immediately if
|
||||
there is only one. See
|
||||
.B pxe-service
|
||||
@@ -1403,7 +1449,7 @@ In the default mode, dnsmasq inserts the unqualified names of
|
||||
DHCP clients into the DNS. For this reason, the names must be unique,
|
||||
even if two clients which have the same name are in different
|
||||
domains. If a second DHCP client appears which has the same name as an
|
||||
existing client, the name is transfered to the new client. If
|
||||
existing client, the name is transferred to the new client. If
|
||||
.B --dhcp-fqdn
|
||||
is set, this behaviour changes: the unqualified name is no longer
|
||||
put in the DNS, only the qualified name. Two DHCP clients with the
|
||||
@@ -1657,7 +1703,7 @@ used to allocate the address, one from any matching
|
||||
The tag "bootp" is set for BOOTP requests, and a tag whose name is the
|
||||
name of the interface on which the request arrived is also set.
|
||||
|
||||
Any configuration lines which includes one or more tag:<tag> contructs
|
||||
Any configuration lines which include one or more tag:<tag> constructs
|
||||
will only be valid if all that tags are matched in the set derived
|
||||
above. Typically this is dhcp-option.
|
||||
.B dhcp-option
|
||||
@@ -1715,7 +1761,7 @@ Configuring dnsmasq to act as an authoritative DNS server is
|
||||
complicated by the fact that it involves configuration of external DNS
|
||||
servers to provide delegation. We will walk through three scenarios of
|
||||
increasing complexity. Prerequisites for all of these scenarios
|
||||
are a globally accesible IP address, an A or AAAA record pointing to that address,
|
||||
are a globally accessible IP address, an A or AAAA record pointing to that address,
|
||||
and an external DNS server capable of doing delegation of the zone in
|
||||
question. For the first part of this explanation, we will call the A (or AAAA) record
|
||||
for the globally accessible address server.example.com, and the zone
|
||||
@@ -1753,7 +1799,7 @@ we have
|
||||
.fi
|
||||
|
||||
.nf
|
||||
our.zone.com A 192.0.43.10
|
||||
our.zone.com A 1.2.3.4
|
||||
our.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
@@ -1766,11 +1812,23 @@ record. If the external address is static, this can be done with an
|
||||
.B /etc/hosts
|
||||
entry or
|
||||
.B --host-record.
|
||||
If the external address is dynamic,
|
||||
then it must be done using something like
|
||||
|
||||
.nf
|
||||
.B --interface-name=our.zone.com,eth0
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B host-record=our.zone.com,1.2.3.4
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
If the external address is dynamic, the address
|
||||
associated with our.zone.com must be derived from the address of the
|
||||
relevant interface. This is done using
|
||||
.B interface-name
|
||||
Something like:
|
||||
|
||||
.nf
|
||||
.B auth-server=our.zone.com,eth0
|
||||
.B interface-name=our.zone.com,eth0
|
||||
.B auth-zone=our.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
Our final configuration builds on that above, but also adds a
|
||||
|
||||
+294
-19
@@ -6,24 +6,40 @@ Dnsmasq \- Un serveur DHCP et cache DNS poids-plume.
|
||||
.I [OPTION]...
|
||||
.SH "DESCRIPTION"
|
||||
.BR dnsmasq
|
||||
est un serveur DHCP et DNS à faible empreinte mémoire. Il offre à la fois les
|
||||
services DNS et DHCP pour un réseau local (LAN).
|
||||
est un serveur à faible empreinte mémoire faisant DNS, TFTP, PXE, annonces de
|
||||
routeurs et DHCP. Il offre à la fois les services DNS et DHCP pour un réseau
|
||||
local (LAN).
|
||||
.PP
|
||||
Dnsmasq accepte les requêtes DNS et y réponds soit en utilisant un petit cache
|
||||
local, soit en effectuant une requête à un serveur DNS récursif externe (par
|
||||
exemple celui de votre fournisseur d'accès internet). Il charge le contenu du
|
||||
fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
|
||||
globaux soient tout de même résolus, et assure également la résolution de nom
|
||||
pour les hôtes présents dans le service DHCP.
|
||||
pour les hôtes présents dans le service DHCP. Il peut aussi agir en temps que
|
||||
serveur DNS faisant autorité pour un ou plusieurs domaines, permettant à des
|
||||
noms locaux d'apparaitre dans le DNS global.
|
||||
.PP
|
||||
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
|
||||
réseaux multiples. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
|
||||
peut être configuré pour envoyer n'importe quel option DHCP.
|
||||
réseaux multiples. Il fournit par défaut un jeu raisonnable de paramètres DHCP,
|
||||
et peut être configuré pour fournir n'importe quelle option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. Le
|
||||
support PXE est complet, et comprend un mode proxy permettant de fournir des
|
||||
informations PXE aux clients alors que l'allocation DHCP est effectuée par un
|
||||
autre serveur.
|
||||
.PP
|
||||
Dnsmasq supporte IPv6 et contient un démon minimaliste capable de faire des
|
||||
annonces routeurs ("router-advertisements").
|
||||
Le serveur DHCPv6 de dnsmasq possède non seulement les mêmes fonctionalités
|
||||
que le serveur DHCPv4, mais aussi le support des annonces de routeurs ainsi
|
||||
qu'une fonctionalité permettant l'addition de ressources AAAA pour des
|
||||
clients utilisant DHCPv4 et la configuration IPv6 sans état (stateless
|
||||
autoconfiguration).
|
||||
Il inclut le support d'allocations d'adresses (à la fois en DHCPv6 et en
|
||||
annonces de routeurs - RA) pour des sous-réseaux dynamiquement délégués via
|
||||
une délégation de préfixe DHCPv6.
|
||||
.PP
|
||||
Dnsmasq est developpé pour de petits systèmes embarqués. It tends à avoir
|
||||
l'empreinte mémoire la plus faible possible pour les fonctions supportées,
|
||||
et permet d'exclure les fonctions inutiles du binaire compilé.
|
||||
.SH OPTIONS
|
||||
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
|
||||
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
@@ -76,9 +92,16 @@ l'absence d'enregistrement SOA.
|
||||
.TP
|
||||
.B --max-ttl=<durée>
|
||||
Définie la valeur de TTL maximum qui sera fournie aux clients. La valeur maximum
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de TTL
|
||||
si cette dernière est supérieure. La valeur réelle de TTL est cependant conservée dans
|
||||
le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
de TTL spécifiée sera fournie aux clients en remplacement de la vraie valeur de
|
||||
TTL si cette dernière est supérieure. La valeur réelle de TTL est cependant
|
||||
conservée dans le cache afin d'éviter de saturer les serveurs DNS en amont.
|
||||
.TP
|
||||
.B --max-cache-ttl=<durée>
|
||||
Définie la valeur de TTL maximum pour les entrées dans le cache
|
||||
.TP
|
||||
.B --auth-ttl=<durée>
|
||||
Définie la valeur de TTL retournée pour les réponses du serveur faisant
|
||||
autorité.
|
||||
.TP
|
||||
.B \-k, --keep-in-foreground
|
||||
Ne pas aller en tâche de fond au lancement, mais en dehors de cela, fonctionner
|
||||
@@ -90,7 +113,10 @@ Mode debug (déverminage) : ne pas aller en tâche de fond, ne pas écrire de
|
||||
fichier pid, ne pas changer d'identifiant utilisateur, générer un état complet
|
||||
du cache lors de la réception d'un signal SIGUSR1, envoyer les logs sur la
|
||||
sortie standard d'erreur ("stderr") de même que dans le syslog, ne pas créer de
|
||||
processus fils pour traiter les requêtes TCP.
|
||||
processus fils pour traiter les requêtes TCP. A noter que cette option est à
|
||||
user pour du déverminage seulement : pour empêcher dnsmasq se fonctionner en
|
||||
mode démon en production, utiliser
|
||||
.B -k.
|
||||
.TP
|
||||
.B \-q, --log-queries
|
||||
Enregistrer les résultats des requêtes DNS traitées par Dnsmasq dans un fichier
|
||||
@@ -185,7 +211,11 @@ ni
|
||||
.B \--except-interface.
|
||||
Utiliser l'option
|
||||
.B --listen-address
|
||||
à la place.
|
||||
à la place. Un simple joker, consistant d'un '*' final, peut-être utilisé dans
|
||||
les options
|
||||
.B \--interface
|
||||
et
|
||||
.B \--except-interface
|
||||
.TP
|
||||
.B \-I, --except-interface=<interface name>
|
||||
Ne pas écouter sur l'interface spécifiée. Notez que l'ordre dans lesquelles les
|
||||
@@ -198,6 +228,21 @@ et
|
||||
sont fournies n'importe pas, et que l'option
|
||||
.B --except-interface
|
||||
l'emporte toujours sur les autres.
|
||||
.TP
|
||||
.B --auth-server=<domaine>,<interface>|<addresse IP>
|
||||
Active le mode DNS faisant autorité pour les requêtes arrivant sur cette
|
||||
interface ou sur cette adresse. Noter que l'interface ou l'adresse n'ont
|
||||
pas besoin d'être mentionées ni dans
|
||||
.B --interface
|
||||
ni dans
|
||||
.B --listen-address
|
||||
En effet,
|
||||
.B --auth-server
|
||||
va passer outre ceux-ci et fournir un service DNS différent sur l'interface
|
||||
spécifiée. La valeur de <domaine> est l'enregistrement de type "colle"
|
||||
("glue record"). Il doit correspondre dans le service DNS global avec un
|
||||
enregistrement de type A et/ou AAAA pointant sur l'adresse sur laquelle dnsmasq
|
||||
écoute pour le mode DNS faisant autorité.
|
||||
.TP
|
||||
.B \-2, --no-dhcp-interface=<nom d'interface>
|
||||
Ne pas fournir de service DHCP sur l'interface spécifiée, mais fournir tout de
|
||||
@@ -312,11 +357,14 @@ Ne pas lire le contenu du fichier /etc/resolv.conf. N'obtenir l'adresse des
|
||||
serveurs de nom amont que depuis la ligne de commande ou le fichier de
|
||||
configuration de Dnsmasq.
|
||||
.TP
|
||||
.B \-1, --enable-dbus
|
||||
.B \-1, --enable-dbus[=<nom de service>]
|
||||
Autoriser la mise à jour de la configuration de Dnsmasq par le biais d'appel de
|
||||
méthodes DBus. Il est possible par ce biais de mettre à jour l'adresse de
|
||||
serveurs DNS amont (et les domaines correspondants) et de vider le cache. Cette
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus.
|
||||
option nécessite que Dnsmasq soit compilé avec le support DBus. Si un nom de
|
||||
service est fourni, dnsmasq fourni un service à ce nom, plutôt qu'avec la
|
||||
valeur par défaut :
|
||||
.B uk.org.thekelleys.dnsmasq
|
||||
.TP
|
||||
.B \-o, --strict-order
|
||||
Par défaut, Dnsmasq envoie les requêtes à n'importe lequel des serveurs amonts
|
||||
@@ -455,6 +503,12 @@ n'ayant de réponse ni dans /etc/hosts, ni dans les baux DHCP, et n'étant pas
|
||||
transmise à un serveur spécifique par le biais d'une directive
|
||||
.B --server.
|
||||
.TP
|
||||
.B --ipset=/<domaine>/[domaine/]<ipset>[,<ipset>]
|
||||
Obtient les adresses IP des domaines spécifiés et les place dans les groupes
|
||||
d'IP netfilter (ipset) indiqués. Domaines et sous-domaines sont résolus de la
|
||||
même façon que pour --address. Ces groupes d'IP doivent déjà exister. Voir
|
||||
ipset(8) pour plus de détails.
|
||||
.TP
|
||||
.B \-m, --mx-host=<nom de l'hôte>[[,<nom du MX>],<préference>]
|
||||
Spécifie un enregistrement de type MX pour <nom de l'hôte> retournant le nom
|
||||
donné dans <nom du MX> (s'il est présent), ou sinon le nom spécifié dans
|
||||
@@ -611,6 +665,34 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.TP
|
||||
.B --auth-zone=<domaine>[,<sous-réseau>[,<sous-réseau>.....]]
|
||||
Définie une zone DNS pour laquelle dnsmasq agit en temps que serveur faisant
|
||||
autorité. Les enregistrements DNS définis localement et correspondant à ce
|
||||
domaine seront fournis, à ceci près que les enregistrements A et AAAA doivent
|
||||
se situer dans l'un des sous-réseaux précisés si ceux-ci sont définis, ou dans
|
||||
un réseau correspondant à une plage DHCP. Le ou les sous-réseaux sont également
|
||||
utilisé pour définir les domaines in-addr.arpa et ipv6.arpa servant à
|
||||
l'interrogation DNS inverse. Dans le cas d'IPv4, la longueur du masque de
|
||||
réseau doit être de 8, 16 ou 24.
|
||||
.TP
|
||||
.B --auth-soa=<numéro de série>[,<mainteneur de zone (hostmaster)>[,<rafraichissement>[,<nombre de réessais>[,<expiration>]]]]
|
||||
Spécifie les champs de l'enregistrement de type SOA (Start Of Authority)
|
||||
associé à une zone pour laquelle le serveur fait autorité. A noter que cela est
|
||||
optionnel, les valeurs par défaut devant convenir à la majorité des cas.
|
||||
.TP
|
||||
.B --auth-sec-servers=<domaine>[,<domaine>[,<domaine>...]]
|
||||
Spécifie un ou plusieurs serveur de nom secondaires pour une zone pour
|
||||
laquelle dnsmasq fait autorité. Ces serveurs doivent-être configurés pour
|
||||
récupérer auprès de dnsmasq les informations liées à la zone au travers d'un
|
||||
transfert de zone, et répondre aux requêtes pour toutes les zones pour
|
||||
lesquelles dnsmasq fait autorité.
|
||||
.TP
|
||||
.B --auth-peer=<adresse IP>[,<adresse IP>[,<adresse IP>...]]
|
||||
Spécifie la ou les adresses de serveurs secondaires autorisés à initier des
|
||||
requêtes de transfert de zone (AXFR) pour les zones pour lesquelles
|
||||
dnsmasq fait autorité. Si cette option n'est pas fournie, les requêtes AXFR
|
||||
seront acceptées pour tous les serveurs secondaires.
|
||||
.TP
|
||||
.B --conntrack
|
||||
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||
@@ -623,7 +705,8 @@ configuré pour cela. Cette option ne peut pas être combinée avec
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>[,<adresse de fin>][,<mode>][,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||
.TP
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
.B \-F, --dhcp-range=[tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>[,<adresse IPv6 de fin>|constructor:<interface>][,<mode>][,<longueur de préfixe>][,<durée de bail>]
|
||||
|
||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||
statiquement dans l'option
|
||||
@@ -663,6 +746,22 @@ d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
|
||||
configuration de l'interface. La taille minimale pour la longueur de préfixe
|
||||
est 64.
|
||||
|
||||
Pour IPv6 (et IPv6 uniquement), il est possible de définir les plages d'une
|
||||
autre façon. Dans ce cas, l'adresse de départ et l'adresse de fin optionnelle
|
||||
contiennent uniquement la partie réseau (par exemple ::1) et sont suivies par
|
||||
.B constructor:<interface>.
|
||||
Cela forme un modèle décrivant comment construire la plage, à partir des
|
||||
adresses assignées à l'interface. Par exemple
|
||||
|
||||
.B --dhcp-range=::1,::400,constructor:eth0
|
||||
|
||||
provoque la recherche d'adresses de la forme <réseau>::1 sur eth0 et crée une
|
||||
plage allant de <réseau>::1 à <réseau>:400. Si une interface est assignée à
|
||||
plus d'un réseau, les plages correspondantes seront automatiquement créées,
|
||||
rendues obsolètes puis supprimées lorsque l'adress est rendue obsolète puis
|
||||
supprimée. Le nom de l'interface peut être spécifié avec un caractère joker '*'
|
||||
final.
|
||||
|
||||
L'identifiant de label optionnel
|
||||
.B set:<label>
|
||||
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
|
||||
@@ -677,7 +776,13 @@ Le mot clef optionnel <mode> peut être égal à
|
||||
spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
|
||||
les hôtes possédant des adresses IP statiques fournies via
|
||||
.B dhcp-host
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP.
|
||||
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. Il est
|
||||
possible d'activer un mode "fourre-tout" en définissant un réseau statique
|
||||
comportant uniquement des zéros, c'est à dire :
|
||||
.B --dhcp=range=::,static
|
||||
Cela permet de retourner des réponses à tous les paquets de type
|
||||
Information-request (requête d'information) en mode DHCPv6 sans état sur le
|
||||
sous-réseau configuré.
|
||||
|
||||
Pour IPv4, le <mode> peut est égal à
|
||||
.B proxy
|
||||
@@ -762,6 +867,10 @@ Un seul
|
||||
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
|
||||
Les adresses IPv6 doivent-être mises entre crochets comme suit :
|
||||
.B --dhcp-host=laptop,[1234::56]
|
||||
Les adresses IPv6 peuvent ne contenir que la partie identifiant de client :
|
||||
.B --dhcp-host=laptop,[::56]
|
||||
Dans ce cas, lorsque des plages dhcp sont définies automatiquement par le biais
|
||||
de constructeurs, la partie réseau correspondante est rajoutée à l'adresse.
|
||||
A noter que pour le DHCP IPv6, l'adresse matérielle n'est en principe pas
|
||||
disponible, aussi un client doit-être identifié par un identifiant de client
|
||||
(appellé "DUID client") ou un nom d'hôte.
|
||||
@@ -1204,14 +1313,16 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
|
||||
Dnsmasq.
|
||||
.TP
|
||||
.B \-K, --dhcp-authoritative
|
||||
(IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
|
||||
serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
|
||||
Doit être spécifié lorsque dnsmasq est réellement le seul serveur DHCP
|
||||
sur le réseau. Pour DHCPv4, cela change le comportement par défaut qui est
|
||||
celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
|
||||
inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
|
||||
nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
|
||||
temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
|
||||
sa base de données contenant les baux sans que les clients n'aient besoin de
|
||||
redemander un bail, si celle-ci est perdue.
|
||||
Dans le cas de DHCPv6, cela positionne la priorité des réponses à 255 (le
|
||||
maximum) au lieu de 0 (le minimum).
|
||||
.TP
|
||||
.B --dhcp-alternate-port[=<port serveur>[,<port client>]]
|
||||
(IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
|
||||
@@ -1319,6 +1430,9 @@ Pour IPv4 seulement :
|
||||
|
||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||
|
||||
DNSMASQ_CIRCUIT_ID, DNSMASQ_SUBSCRIBER_ID, DNSMASQ_REMOTE_ID si un relai DHCP a
|
||||
rajouté l'une de ces options.
|
||||
|
||||
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
|
||||
|
||||
Pour IPv6 seulement :
|
||||
@@ -1847,6 +1961,167 @@ supprime la nécessité des associations statiques). Le paramètre
|
||||
que le label "bootp", permettant un certain contrôle sur les options retournées
|
||||
aux différentes classes d'hôtes.
|
||||
|
||||
|
||||
.SH CONFIGURATION EN TEMPS QUE SERVEUR FAISANT AUTORITÉ
|
||||
.PP
|
||||
Configurer dnsmasq pour agir en temps que serveur DNS faisant autorité est
|
||||
compliqué par le fait que cela implique la configuration de serveurs DNS
|
||||
externes pour mettre en place la délégation. Seront présentés ci-dessous trois
|
||||
scénarios de complexité croissante. Le pré-requis pour chacun de ces scénarios
|
||||
est l'existence d'une adresse IP globalement disponible, d'un enregistrement de
|
||||
type A ou AAAA pointant vers cette adresse, ainsi que d'un serveur DNS externe
|
||||
capable d'effectuer la délégation de la zone en question. Pour la première
|
||||
partie de ces explications, nous allons appeller serveur.exemple.com
|
||||
l'enregistrement A (ou AAAA) de l'adresse globalement accessible, et
|
||||
notre.zone.com la zone pour laquelle dnsmasq fait autorité.
|
||||
|
||||
La configuration la plus simple consiste en deux lignes de configuration,
|
||||
sous la forme :
|
||||
.nf
|
||||
.B auth-server=serveur.exemple.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
ainsi que deux enregistrements dans le DNS externe :
|
||||
|
||||
.nf
|
||||
serveur.exemple.com A 192.0.43.10
|
||||
notre.zone.com NS serveur.exemple.com
|
||||
.fi
|
||||
|
||||
eth0 est l'interface réseau externe sur laquelle dnsmasq écoute, dont l'adresse
|
||||
IP (globalement accessible) est 192.0.43.10.
|
||||
|
||||
A noter que l'adresse IP externe peut parfaitement être dynamique (par exemple
|
||||
attribuée par un FAI via DHCP ou PPP). Dans ce cas, l'enregistrement de type A
|
||||
doit être lié à cet enregistrement dynamique par l'une ou l'autre des techniques
|
||||
habituelles de système DNS dynamique.
|
||||
|
||||
Un exemple plus complexe mais en pratique plus utile correspond au cas où
|
||||
l'adresse IP globalement accessible se trouve dans la zone pour laquelle
|
||||
dnsmasq fait autorité, le plus souvent à la racine. Dans ce cas nous avons :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
.nf
|
||||
notre.zone.com A 1.2.3.4
|
||||
notre.zone.com NS our.zone.com
|
||||
.fi
|
||||
|
||||
L'enregistrement A pour notre.zone.com est dorénavant un enregistrement "colle"
|
||||
qui résoud le problème de poule et d'oeuf consistant à trouver l'adresse IP
|
||||
du serveur de nom pour notre.zone.com lorsque l'enregistrement se trouve dans
|
||||
la zone en question. Il s'agit du seul rôle de cet enregistrement : comme dnsmasq
|
||||
fait désormais autorité pour notre.zone.com, il doit également fournir cet
|
||||
enregistrement. Si l'adresse externe est statique, cela peut-être réalisé par
|
||||
le biais d'une entrée dans
|
||||
.B /etc/hosts
|
||||
ou via un
|
||||
.B --host-record.
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B host-record=notre.zone.com,1.2.3.4
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
Si l'adresse externe est dynamique, l'adresse associée à notre.zone.com doit
|
||||
être dérivée de l'interface correspondante. Cela peut être fait en utilisant
|
||||
.B interface-name
|
||||
Sous la forme :
|
||||
|
||||
.nf
|
||||
.B auth-server=notre.zone.com,eth0
|
||||
.B interface-name=notre.zone.com,eth0
|
||||
.B auth-zone=notre.zone.com,1.2.3.0/24
|
||||
.fi
|
||||
|
||||
La configuration finale rajoute à cette base un serveur DNS secondaire. Il
|
||||
s'agit d'un autre serveur DNS qui apprend les données DNS de la zone en
|
||||
effectuant un transfert de zone, et qui joue le rôle de serveur de secours
|
||||
au cas où le serveur principal devenait inaccessible. La configuration
|
||||
de ce serveur secondaire sort du cadre de cette page de manuel. Les éléments
|
||||
de configuration à rajouter dans dnsmasq sont les simples :
|
||||
|
||||
.nf
|
||||
.B auth-sec-servers=secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
et
|
||||
|
||||
.nf
|
||||
notre.zone.com NS secondaire.monfai.com
|
||||
.fi
|
||||
|
||||
L'addition d'une option auth-sec-servers active les transferts de zone dans
|
||||
dnsmasq, ce qui permet au serveur secondaire de venir collecter les données
|
||||
DNS. Si vous souhaitez restreindre l'accès à ces données à des hôtes
|
||||
spécifiques, vous pouvez le faire via :
|
||||
|
||||
.nf
|
||||
.B auth-peer=<adresse IP du serveur secondaire>
|
||||
.fi
|
||||
|
||||
Dnsmasq joue le rôle de serveur faisant autorité pour les domaines in-addr.arpa
|
||||
et ipv6.arpa associés aux sous-réseaux définis dans la déclaration de zone
|
||||
auth-zone, ce qui fait que les requêtes DNS inversées (de l'adresse vers
|
||||
le nom) peuvent-simplement être configurées avec un enregistrement NS
|
||||
adéquat. Par exemple, comme nous définissons plus haut les adresses
|
||||
1.2.3.0/24 :
|
||||
.nf
|
||||
3.2.1.in-addr.arpa NS notre.zone.com
|
||||
.fi
|
||||
|
||||
Veuillez noter que pour l'instant, les zones inverses ne sont pas
|
||||
disponibles dans les transferts de zone, donc il est inutile de configurer
|
||||
de serveur secondaire pour la résolution inverse.
|
||||
|
||||
.PP
|
||||
Lorsque dnsmasq est configuré en temps que serveur faisant autorité,
|
||||
les données suivantes sont utilisées pour peupler la zone considérée :
|
||||
.PP
|
||||
.B --mx-host, --srv-host, --dns-rr, --txt-record, --naptr-record
|
||||
, pour autant que les noms des enregistrements se trouvent dans la zone en
|
||||
question.
|
||||
.PP
|
||||
.B --cname
|
||||
pour peu que le nom soit dans le domaine. Si la cible du CNAME n'est
|
||||
pas pleinement qualifiée, alors elle est qualifiée avec le nom de la
|
||||
zone pour laquelle le serveur fait autorité.
|
||||
.PP
|
||||
Les adresses IPv4 et IPv6 extraites de /etc/hosts (et
|
||||
.B --addn-hosts
|
||||
) ainsi que les options
|
||||
.B --host-record
|
||||
fournissant des adresses situées dans l'un des sous-réseaux spécifiés dans
|
||||
.B --auth-zone.
|
||||
.PP
|
||||
Adresses spécifiées par
|
||||
.B --interface-name.
|
||||
Dans ce cas, l'adresse n'est pas limitée à l'un des sous-réseaux donné dans
|
||||
.B --auth-zone.
|
||||
|
||||
.PP
|
||||
Les adresses de baux DHCP, si l'adresse est située dans l'un des sous-réseaux de
|
||||
.B --auth-zone
|
||||
OU dans une plage DHCP construite. Dans le mode par défaut, où le bail
|
||||
DHCP a un nom non qualifié, et éventuellement pour un nom qualifié construit
|
||||
via
|
||||
.B --domain
|
||||
, alors le nom dans la zone faisant autorité est construit à partir du nom
|
||||
non qualifié et du nom de domaine de la zone. Cela peut on non être égal
|
||||
celui fourni par
|
||||
.B --domain.
|
||||
Si l'option
|
||||
.B --dhcp-fqdn
|
||||
est fournie, alors les noms pleinemenet qualifiés associés aux baux DHCP
|
||||
sont utilisés, dès lors qu'ils correspondent au nom de domaine associé
|
||||
à la zone.
|
||||
|
||||
|
||||
.SH CODES DE SORTIE
|
||||
.PP
|
||||
0 - Dnsmasq s'est correctement lancé en tâche de fond, ou alors s'est
|
||||
|
||||
+600
-405
File diff suppressed because it is too large.
Load diff
+96
-51
@@ -54,6 +54,7 @@ static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_
|
||||
if (flag & F_IPV6)
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_CONSTRUCTED) &&
|
||||
!(context->flags & CONTEXT_NOAUTH) &&
|
||||
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
|
||||
return 1;
|
||||
#endif
|
||||
@@ -152,32 +153,55 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
auth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag == F_IPV4)
|
||||
{
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
|
||||
intr = NULL;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
if (flag == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (flag == F_IPV6)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intr)
|
||||
{
|
||||
if (in_zone(zone, intr->name, NULL))
|
||||
{
|
||||
found = 1;
|
||||
log_query(flag| F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
|
||||
do {
|
||||
strcpy(name, cache_get_name(crecp));
|
||||
@@ -321,20 +345,37 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
addrlist = intr->addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
addrlist = intr->addr6;
|
||||
#endif
|
||||
nxdomain = 0;
|
||||
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
|
||||
for (; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, flag, &addrlist->addr))
|
||||
{
|
||||
found = 1;
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->auth_ttl, NULL, qtype, C_IN,
|
||||
qtype == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
@@ -356,14 +397,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
goto cname_restart;
|
||||
}
|
||||
|
||||
if (qtype == T_A)
|
||||
flag = F_IPV4;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (qtype == T_AAAA)
|
||||
flag = F_IPV6;
|
||||
#endif
|
||||
|
||||
if (!cut)
|
||||
{
|
||||
nxdomain = 0;
|
||||
@@ -488,10 +521,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
|
||||
char *p = name;
|
||||
|
||||
if (subnet->prefixlen == 24)
|
||||
if (subnet->prefixlen >= 24)
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
if (subnet->prefixlen != 8)
|
||||
if (subnet->prefixlen >= 16 )
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
@@ -634,20 +667,32 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
}
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
|
||||
if (in_zone(zone, intr->name, &cut))
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
|
||||
anscount++;
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, F_IPV4, &addrlist->addr) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (filter_constructed_dhcp(zone, F_IPV6, &addrlist->addr) &&
|
||||
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
|
||||
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
|
||||
anscount++;
|
||||
#endif
|
||||
|
||||
/* restore config data */
|
||||
if (cut)
|
||||
*cut = '.';
|
||||
}
|
||||
|
||||
|
||||
for (a = daemon->cnames; a; a = a->next)
|
||||
if (in_zone(zone, a->alias, &cut))
|
||||
{
|
||||
@@ -721,10 +766,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
|
||||
daemon->soa_retry, daemon->soa_expiry,
|
||||
daemon->auth_ttl))
|
||||
anscount++;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
|
||||
@@ -123,7 +123,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
|
||||
else
|
||||
broadcast.s_addr = 0;
|
||||
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
|
||||
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
|
||||
-32
@@ -971,38 +971,6 @@ void cache_reload(void)
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (c = daemon->cond_domain; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||
{
|
||||
|
||||
+6
-6
@@ -135,12 +135,12 @@ RESOLVFILE
|
||||
#define HAVE_TFTP
|
||||
#define HAVE_SCRIPT
|
||||
#define HAVE_AUTH
|
||||
#define HAVE_IPSET
|
||||
/* #define HAVE_LUASCRIPT */
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
/* #define HAVE_IPSET */
|
||||
|
||||
|
||||
/* Default locations for important system files. */
|
||||
@@ -279,12 +279,12 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||
# define HAVE_IPV6
|
||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||
#elif defined(INET_ADDRSTRLEN)
|
||||
#else
|
||||
# if !defined(INET_ADDRSTRLEN)
|
||||
# define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
# endif
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||
#else
|
||||
# undef HAVE_IPV6
|
||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_AUTH
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_LINUX_NETWORK
|
||||
#if defined(NO_IPSET) || !defined(HAVE_LINUX_NETWORK)
|
||||
#undef HAVE_IPSET
|
||||
#endif
|
||||
|
||||
|
||||
+16
-7
@@ -305,8 +305,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
|
||||
const char *addr_err;
|
||||
char *dup = NULL;
|
||||
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
|
||||
if (!dbus_message_iter_init(message, &iter))
|
||||
{
|
||||
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
|
||||
@@ -478,6 +476,7 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
{
|
||||
char *method = (char *)dbus_message_get_member(message);
|
||||
DBusMessage *reply = NULL;
|
||||
int clear_cache = 0, new_servers = 0;
|
||||
|
||||
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
|
||||
{
|
||||
@@ -501,24 +500,34 @@ DBusHandlerResult message_handler(DBusConnection *connection,
|
||||
}
|
||||
else if (strcmp(method, "SetServers") == 0)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
dbus_read_servers(message);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetServersEx") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 0);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "SetDomainServers") == 0)
|
||||
{
|
||||
reply = dbus_read_servers_ex(message, 1);
|
||||
check_servers();
|
||||
new_servers = 1;
|
||||
}
|
||||
else if (strcmp(method, "ClearCache") == 0)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
clear_cache = 1;
|
||||
else
|
||||
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
|
||||
|
||||
if (new_servers)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
|
||||
check_servers();
|
||||
if (option_bool(OPT_RELOAD))
|
||||
clear_cache = 1;
|
||||
}
|
||||
|
||||
if (clear_cache)
|
||||
clear_cache_and_reload(dnsmasq_time());
|
||||
|
||||
method = user_data; /* no warning */
|
||||
|
||||
|
||||
+30
-17
@@ -91,6 +91,7 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
{
|
||||
struct dhcp_netid *tagif = run_tag_if(tags);
|
||||
struct dhcp_opt *opt;
|
||||
struct dhcp_opt *tmp;
|
||||
|
||||
/* flag options which are valid with the current tag set (sans context tags) */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
@@ -135,7 +136,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||
{
|
||||
struct dhcp_opt *tmp;
|
||||
for (tmp = opts; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||
break;
|
||||
@@ -145,6 +145,13 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||
}
|
||||
|
||||
/* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
|
||||
for (opt = opts; opt; opt = opt->next)
|
||||
if (opt->flags & DHOPT_TAGOK)
|
||||
for (tmp = opt->next; tmp; tmp = tmp->next)
|
||||
if (tmp->opt == opt->opt)
|
||||
tmp->flags &= ~DHOPT_TAGOK;
|
||||
|
||||
return tagif;
|
||||
}
|
||||
|
||||
@@ -340,21 +347,27 @@ void bindtodevice(int fd)
|
||||
to that device. This is for the use case of (eg) OpenStack, which runs a new
|
||||
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
|
||||
individual processes don't always see the packets they should.
|
||||
SO_BINDTODEVICE is only available Linux. */
|
||||
SO_BINDTODEVICE is only available Linux.
|
||||
|
||||
Note that if wildcards are used in --interface, or a configured interface doesn't
|
||||
yet exist, then more interfaces may arrive later, so we can't safely assert there
|
||||
is only one interface and proceed.
|
||||
*/
|
||||
|
||||
struct irec *iface, *found;
|
||||
|
||||
struct iname *if_tmp;
|
||||
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
|
||||
return;
|
||||
|
||||
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dhcp_ok)
|
||||
{
|
||||
if (!found)
|
||||
found = iface;
|
||||
else if (strcmp(found->name, iface->name) != 0)
|
||||
{
|
||||
/* more than one. */
|
||||
found = NULL;
|
||||
break;
|
||||
}
|
||||
return; /* more than one. */
|
||||
}
|
||||
|
||||
if (found)
|
||||
@@ -505,7 +518,7 @@ void display_opts6(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
u16 lookup_dhcp_opt(int prot, char *name)
|
||||
int lookup_dhcp_opt(int prot, char *name)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
@@ -521,10 +534,10 @@ u16 lookup_dhcp_opt(int prot, char *name)
|
||||
if (strcasecmp(t[i].name, name) == 0)
|
||||
return t[i].val;
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
u16 lookup_dhcp_len(int prot, u16 val)
|
||||
int lookup_dhcp_len(int prot, int val)
|
||||
{
|
||||
const struct opttab_t *t;
|
||||
int i;
|
||||
@@ -707,19 +720,19 @@ void log_context(int family, struct dhcp_context *context)
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
if (indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, context->if_index, ifrn_name))
|
||||
sprintf(p, "constructed for %s", ifrn_name);
|
||||
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
|
||||
}
|
||||
else if (context->flags & CONTEXT_TEMPLATE)
|
||||
{
|
||||
template = p;
|
||||
p += sprintf(p, ", ");
|
||||
|
||||
sprintf(p, "template for %s%s", context->template_interface,
|
||||
(context->flags & CONTEXT_WILDCARD) ? "*" : "");
|
||||
sprintf(p, "template for %s", context->template_interface);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
|
||||
if (!(context->flags & CONTEXT_OLD) &&
|
||||
((context->flags & CONTEXT_DHCP) || family == AF_INET))
|
||||
{
|
||||
inet_ntop(family, start, daemon->dhcp_buff, 256);
|
||||
inet_ntop(family, end, daemon->dhcp_buff3, 256);
|
||||
@@ -736,9 +749,9 @@ void log_context(int family, struct dhcp_context *context)
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
|
||||
|
||||
|
||||
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
|
||||
#endif
|
||||
|
||||
+22
-10
@@ -28,9 +28,9 @@ struct match_param {
|
||||
struct in_addr netmask, broadcast, addr;
|
||||
};
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||
|
||||
static int make_fd(int port)
|
||||
@@ -65,14 +65,22 @@ static int make_fd(int port)
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
#else
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -252,7 +260,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
/* unlinked contexts are marked by context->current == context */
|
||||
@@ -279,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
iface_addr = match.addr;
|
||||
/* make sure secondary address gets priority in case
|
||||
there is more than one address on the interface in the same subnet */
|
||||
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
@@ -403,12 +411,14 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
|
||||
/* check against secondary interface addresses */
|
||||
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct match_param *param = vparam;
|
||||
struct iname *tmp;
|
||||
|
||||
(void) label;
|
||||
|
||||
if (if_index == param->ind)
|
||||
{
|
||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||
@@ -436,11 +446,13 @@ static int check_listen_addrs(struct in_addr local, int if_index,
|
||||
|
||||
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
|
||||
|
||||
static int complete_context(struct in_addr local, int if_index,
|
||||
static int complete_context(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_context *context;
|
||||
struct iface_param *param = vparam;
|
||||
|
||||
(void)label;
|
||||
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
{
|
||||
|
||||
@@ -59,6 +59,11 @@
|
||||
#define OPTION6_SUBSCRIBER_ID 38
|
||||
#define OPTION6_FQDN 39
|
||||
|
||||
/* replace this with the real number when allocated.
|
||||
defining this also enables the relevant code. */
|
||||
/* #define OPTION6_PREFIX_CLASS 99 */
|
||||
|
||||
|
||||
#define DHCP6SUCCESS 0
|
||||
#define DHCP6UNSPEC 1
|
||||
#define DHCP6NOADDRS 2
|
||||
|
||||
+91
-52
@@ -48,16 +48,24 @@ void dhcp6_init(void)
|
||||
!set_ipv6pktinfo(fd))
|
||||
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 547. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
Need to set REUSEADDR|REUSEPORT to make this posible.
|
||||
Handle the case that REUSEPORT is defined, but the kernel doesn't
|
||||
support it. This handles the introduction of REUSEPORT on Linux. */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
int rc = -1, porterr = 0;
|
||||
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
#else
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
|
||||
errno != ENOPROTOOPT)
|
||||
porterr = 1;
|
||||
#endif
|
||||
|
||||
if (rc == -1 && !porterr)
|
||||
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
|
||||
|
||||
if (rc == -1)
|
||||
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
@@ -120,11 +128,11 @@ void dhcp6_packet(time_t now)
|
||||
return;
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
return;
|
||||
|
||||
parm.current = NULL;
|
||||
@@ -153,7 +161,7 @@ void dhcp6_packet(time_t now)
|
||||
{
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
break;
|
||||
|
||||
if (!tmp && !parm.addr_match)
|
||||
@@ -212,7 +220,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
if ((context->flags & CONTEXT_DHCP) &&
|
||||
!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
@@ -266,7 +274,7 @@ struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct
|
||||
}
|
||||
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int iaid, struct dhcp_netid *netids, struct in6_addr *ans)
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
|
||||
{
|
||||
/* Find a free address: exclude anything in use and anything allocated to
|
||||
a particular hwaddr/clientid/hostname in our configuration.
|
||||
@@ -286,7 +294,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
|
||||
for (j = iaid, i = 0; i < clid_len; i++)
|
||||
j += clid[i] + (j << 6) + (j << 16) - j;
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
|
||||
continue;
|
||||
@@ -296,7 +304,7 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
|
||||
{
|
||||
if (option_bool(OPT_CONSEC_ADDR))
|
||||
/* seed is largest extant lease addr in this context */
|
||||
start = lease_find_max_addr6(c);
|
||||
start = lease_find_max_addr6(c) + serial;
|
||||
else
|
||||
start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
|
||||
|
||||
@@ -326,13 +334,14 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
|
||||
} while (addr != start);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* can dynamically allocate addr */
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
u64 start, end, addr = addr6part(taddr);
|
||||
struct dhcp_context *tmp;
|
||||
@@ -347,7 +356,7 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@@ -356,44 +365,52 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
|
||||
/* address OK if configured */
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids)
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range)
|
||||
{
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
match_netid(tmp->filter, netids, plain_range))
|
||||
return tmp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
/* expand wildcard on contructed contexts */
|
||||
if ((config->flags & CONFIG_WILDCARD) &&
|
||||
(context->flags & CONTEXT_CONSTRUCTED))
|
||||
if (!config || !(config->flags & CONFIG_ADDR6))
|
||||
return 0;
|
||||
|
||||
if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
|
||||
{
|
||||
u64 addrpart = addr6part(&config->addr6);
|
||||
config->addr6 = context->start6;
|
||||
setaddr6part(&config->addr6, addrpart);
|
||||
*addr = context->start6;
|
||||
setaddr6part(addr, addr6part(&config->addr6));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (is_same_net6(&context->start6, &config->addr6, context->prefix))
|
||||
{
|
||||
*addr = config->addr6;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
|
||||
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
|
||||
{
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix))
|
||||
return 1;
|
||||
if (!(config->flags & CONFIG_ADDR6) ||
|
||||
(config->flags & CONFIG_WILDCARD))
|
||||
|
||||
return 1;
|
||||
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -521,9 +538,9 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
}
|
||||
|
||||
}
|
||||
else if (addr6part(local) == addr6part(&template->start6) &&
|
||||
strncmp(template->template_interface, ifrn_name, strlen(template->template_interface)) == 0 &&
|
||||
(strlen(template->template_interface) == strlen(ifrn_name) || (template->flags & CONTEXT_WILDCARD)))
|
||||
else if ((addr6part(local) == addr6part(&template->start6) ||
|
||||
addr6part(local) == addr6part(&template->end6)) &&
|
||||
wildcard_match(template->template_interface, ifrn_name))
|
||||
{
|
||||
start6 = *local;
|
||||
setaddr6part(&start6, addr6part(&template->start6));
|
||||
@@ -535,7 +552,10 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
|
||||
{
|
||||
context->flags &= ~CONTEXT_GC;
|
||||
int flags = context->flags;
|
||||
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
|
||||
if (flags & CONTEXT_OLD)
|
||||
log_context(AF_INET6, context);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -548,6 +568,7 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
context->flags |= CONTEXT_CONSTRUCTED;
|
||||
context->if_index = if_index;
|
||||
context->local6 = *local;
|
||||
context->saved_valid = 0;
|
||||
|
||||
context->next = daemon->dhcp6;
|
||||
daemon->dhcp6 = context;
|
||||
@@ -570,35 +591,53 @@ static int construct_worker(struct in6_addr *local, int prefix,
|
||||
|
||||
void dhcp_construct_contexts(time_t now)
|
||||
{
|
||||
struct dhcp_context *tmp, *context, **up;
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct cparam param;
|
||||
param.newone = 0;
|
||||
param.newname = 0;
|
||||
param.now = now;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
{
|
||||
context->if_index = 0;
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_CONSTRUCTED)
|
||||
context->flags |= CONTEXT_GC;
|
||||
|
||||
iface_enumerate(AF_INET6, ¶m, construct_worker);
|
||||
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC)
|
||||
tmp = context->next;
|
||||
|
||||
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
|
||||
{
|
||||
*up = context->next;
|
||||
param.newone = 1; /* include deletion */
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
free(context);
|
||||
|
||||
if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
|
||||
option_bool(OPT_RA))
|
||||
{
|
||||
/* previously constructed context has gone. advertise it's demise */
|
||||
context->flags |= CONTEXT_OLD;
|
||||
context->address_lost_time = now;
|
||||
if (context->saved_valid > 7200) /* 2 hours */
|
||||
context->saved_valid = 7200;
|
||||
ra_start_unsolicted(now, context);
|
||||
param.newone = 1; /* include deletion */
|
||||
|
||||
if (context->flags & CONTEXT_RA_NAME)
|
||||
param.newname = 1;
|
||||
|
||||
log_context(AF_INET6, context);
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we were never doing RA for this, so free now */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (param.newone)
|
||||
|
||||
+63
-52
@@ -225,7 +225,7 @@ int main (int argc, char **argv)
|
||||
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
if (!enumerate_interfaces())
|
||||
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
@@ -248,7 +248,7 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->dhcp6)
|
||||
if (daemon->doing_dhcp6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
#endif
|
||||
}
|
||||
@@ -820,12 +820,15 @@ int main (int argc, char **argv)
|
||||
now = dnsmasq_time();
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
|
||||
/* prime. */
|
||||
enumerate_interfaces(1);
|
||||
|
||||
/* Check the interfaces to see if any have exited DAD state
|
||||
and if so, bind the address. */
|
||||
if (is_dad_listeners())
|
||||
{
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||
create_bound_listeners(0);
|
||||
}
|
||||
@@ -1352,63 +1355,71 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
|
||||
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
|
||||
{
|
||||
close(confd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure that the interface list is up-to-date.
|
||||
|
||||
We do this here as we may need the results below, and
|
||||
the DNS code needs them for --interface-name stuff.
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
Multiple calls to enumerate_interfaces() per select loop are
|
||||
inhibited, so calls to it in the child process (which doesn't select())
|
||||
have no effect. This avoids two processes reading from the same
|
||||
netlink fd and screwing the pooch entirely.
|
||||
*/
|
||||
|
||||
/* In full wildcard mode, need to refresh interface list.
|
||||
This happens automagically in CLEVERBIND */
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
struct all_addr addr;
|
||||
addr.addr.addr4 = tcp_addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||
addr.addr.addr6 = tcp_addr.in6.sin6_addr;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == if_index)
|
||||
break;
|
||||
|
||||
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
client_ok = 0;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
{
|
||||
/* Check for allowed interfaces when binding the wildcard address:
|
||||
we do this by looking for an interface with the same address as
|
||||
the local address of the TCP connection, then looking to see if that's
|
||||
an allowed interface. As a side effect, we get the netmask of the
|
||||
interface too, for localisation. */
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
break;
|
||||
|
||||
if (!iface)
|
||||
client_ok = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_ok)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
|
||||
+40
-18
@@ -307,6 +307,13 @@ struct host_record {
|
||||
struct interface_name {
|
||||
char *name; /* domain name */
|
||||
char *intr; /* interface name */
|
||||
struct addrlist {
|
||||
struct all_addr addr;
|
||||
struct addrlist *next;
|
||||
} *addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct addrlist *addr6;
|
||||
#endif
|
||||
struct interface_name *next;
|
||||
};
|
||||
|
||||
@@ -543,6 +550,7 @@ struct dhcp_lease {
|
||||
int backoff; /* zero -> confirmed */
|
||||
struct slaac_address *next;
|
||||
} *slaac_address;
|
||||
int vendorclass_count;
|
||||
#endif
|
||||
struct dhcp_lease *next;
|
||||
};
|
||||
@@ -672,7 +680,7 @@ struct dhcp_bridge {
|
||||
};
|
||||
|
||||
struct cond_domain {
|
||||
char *domain;
|
||||
char *domain, *prefix;
|
||||
struct in_addr start, end;
|
||||
#ifdef HAVE_IPV6
|
||||
struct in6_addr start6, end6;
|
||||
@@ -684,7 +692,7 @@ struct cond_domain {
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class {
|
||||
int class;
|
||||
struct dhcp_netid netid;
|
||||
struct dhcp_netid tag;
|
||||
struct prefix_class *next;
|
||||
};
|
||||
#endif
|
||||
@@ -698,8 +706,8 @@ struct dhcp_context {
|
||||
struct in6_addr start6, end6; /* range of available addresses */
|
||||
struct in6_addr local6;
|
||||
int prefix, if_index;
|
||||
unsigned int valid, preferred;
|
||||
time_t ra_time, ra_short_period_start;
|
||||
unsigned int valid, preferred, saved_valid;
|
||||
time_t ra_time, ra_short_period_start, address_lost_time;
|
||||
char *template_interface;
|
||||
#endif
|
||||
int flags;
|
||||
@@ -721,8 +729,11 @@ struct dhcp_context {
|
||||
#define CONTEXT_CONSTRUCTED 2048
|
||||
#define CONTEXT_GC 4096
|
||||
#define CONTEXT_RA 8192
|
||||
#define CONTEXT_WILDCARD 16384
|
||||
#define CONTEXT_CONF_USED 16384
|
||||
#define CONTEXT_USED 32768
|
||||
#define CONTEXT_NOAUTH 65536
|
||||
#define CONTEXT_OLD 131072
|
||||
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
@@ -788,7 +799,7 @@ extern struct daemon {
|
||||
struct name_list *secondary_forward_server;
|
||||
int group_set, osport;
|
||||
char *domain_suffix;
|
||||
struct cond_domain *cond_domain;
|
||||
struct cond_domain *cond_domain, *synth_domains;
|
||||
char *runfile;
|
||||
char *lease_change_command;
|
||||
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
|
||||
@@ -829,6 +840,9 @@ extern struct daemon {
|
||||
unsigned char *duid_config;
|
||||
char *dbus_name;
|
||||
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *prefix_classes;
|
||||
#endif
|
||||
|
||||
/* globally used stuff for DNS */
|
||||
char *packet; /* packet buffer */
|
||||
@@ -903,15 +917,19 @@ void cache_unhash_dhcp(void);
|
||||
void dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len);
|
||||
void keydata_free(struct keydata *blocks);
|
||||
#endif
|
||||
|
||||
/* domain.c */
|
||||
char *get_domain(struct in_addr addr);
|
||||
#ifdef HAVE_IPV6
|
||||
char *get_domain6(struct in6_addr *addr);
|
||||
#endif
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr);
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
@@ -976,6 +994,8 @@ char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
void bump_maxfd(int fd, int *max);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
|
||||
/* log.c */
|
||||
void die(char *message, char *arg1, int exit_code);
|
||||
int log_start(struct passwd *ent_pw, int errfd);
|
||||
@@ -1014,15 +1034,15 @@ int random_sock(int family);
|
||||
void pre_allocate_sfds(void);
|
||||
int reload_servers(char *fname);
|
||||
void check_servers(void);
|
||||
int enumerate_interfaces();
|
||||
int enumerate_interfaces(int reset);
|
||||
void create_wildcard_listeners(void);
|
||||
void create_bound_listeners(int die);
|
||||
int is_dad_listeners(void);
|
||||
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
|
||||
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
|
||||
int label_exception(int index, int family, struct all_addr *addr);
|
||||
int fix_fd(int fd);
|
||||
int tcp_interface(int fd, int af);
|
||||
struct in_addr get_ifaddr(char *intr);
|
||||
#ifdef HAVE_IPV6
|
||||
int set_ipv6pktinfo(int fd);
|
||||
#endif
|
||||
@@ -1171,14 +1191,16 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||
void dhcp6_init(void);
|
||||
void dhcp6_packet(time_t now);
|
||||
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
|
||||
int iaid, struct dhcp_netid *netids, struct in6_addr *ans);
|
||||
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr);
|
||||
int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans);
|
||||
int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr);
|
||||
struct dhcp_context *address6_available(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_context *address6_valid(struct dhcp_context *context,
|
||||
struct in6_addr *taddr,
|
||||
struct dhcp_netid *netids);
|
||||
struct dhcp_netid *netids,
|
||||
int plain_range);
|
||||
struct dhcp_config *find_config6(struct dhcp_config *configs,
|
||||
struct dhcp_context *context,
|
||||
unsigned char *duid, int duid_len,
|
||||
@@ -1208,8 +1230,8 @@ void log_tags(struct dhcp_netid *netid, u32 xid);
|
||||
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
void dhcp_update_configs(struct dhcp_config *configs);
|
||||
void display_opts(void);
|
||||
u16 lookup_dhcp_opt(int prot, char *name);
|
||||
u16 lookup_dhcp_len(int prot, u16 val);
|
||||
int lookup_dhcp_opt(int prot, char *name);
|
||||
int lookup_dhcp_len(int prot, int val);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2013 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"
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
|
||||
#endif
|
||||
|
||||
|
||||
int is_name_synthetic(int flags, char *name, struct all_addr *addr)
|
||||
{
|
||||
char *p;
|
||||
struct cond_domain *c = NULL;
|
||||
int prot = AF_INET;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flags & F_IPV6)
|
||||
prot = AF_INET6;
|
||||
#endif
|
||||
|
||||
for (c = daemon->synth_domains; c; c = c->next)
|
||||
{
|
||||
int found = 0;
|
||||
char *tail, *pref;
|
||||
|
||||
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
|
||||
{
|
||||
unsigned int c1 = (unsigned char) *pref;
|
||||
unsigned int c2 = (unsigned char) *tail;
|
||||
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pref && *pref != 0)
|
||||
continue; /* prefix match fail */
|
||||
|
||||
/* NB, must not alter name if we return zero */
|
||||
for (p = tail; *p; p++)
|
||||
{
|
||||
char c = *p;
|
||||
|
||||
if ((c >='0' && c <= '9') || c == '-')
|
||||
continue;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (*p != '.')
|
||||
continue;
|
||||
|
||||
*p = 0;
|
||||
|
||||
/* swap . or : for - */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '-')
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
*p = '.';
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*p = ':';
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
|
||||
{
|
||||
if (prot == AF_INET)
|
||||
{
|
||||
if (!c->is6 &&
|
||||
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
|
||||
found = 1;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
u64 addrpart = addr6part(&addr->addr.addr6);
|
||||
|
||||
if (c->is6 &&
|
||||
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
found = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* restore name */
|
||||
for (p = tail; *p; p++)
|
||||
if (*p == '.' || *p == ':')
|
||||
*p = '-';
|
||||
|
||||
*p = '.';
|
||||
|
||||
if (found)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_rev_synth(int flag, struct all_addr *addr, char *name)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if (flag & F_IPV4 && (c = search_domain(addr->addr.addr4, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
|
||||
for (p = name; *p; p++)
|
||||
if (*p == '.')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (flag & F_IPV6 && (c = search_domain6(&addr->addr.addr6, daemon->synth_domains)))
|
||||
{
|
||||
char *p;
|
||||
|
||||
*name = 0;
|
||||
if (c->prefix)
|
||||
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
|
||||
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
|
||||
|
||||
/* IPv6 presentation address can start with ":", but valid domain names
|
||||
cannot start with "-" so prepend a zero in that case. */
|
||||
if (!c->prefix && *name == ':')
|
||||
{
|
||||
*name = '0';
|
||||
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
|
||||
}
|
||||
|
||||
for (p = name; *p; p++)
|
||||
if (*p == ':')
|
||||
*p = '-';
|
||||
|
||||
strncat(name, ".", MAXDNAME);
|
||||
strncat(name, c->domain, MAXDNAME);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
|
||||
{
|
||||
for (; c; c = c->next)
|
||||
if (!c->is6 &&
|
||||
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
|
||||
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain(struct in_addr addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if ((c = search_domain(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
|
||||
{
|
||||
u64 addrpart = addr6part(addr);
|
||||
|
||||
for (; c; c = c->next)
|
||||
if (c->is6 &&
|
||||
is_same_net6(addr, &c->start6, 64) &&
|
||||
addrpart >= addr6part(&c->start6) &&
|
||||
addrpart <= addr6part(&c->end6))
|
||||
return c;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_domain6(struct in6_addr *addr)
|
||||
{
|
||||
struct cond_domain *c;
|
||||
|
||||
if ((c = search_domain6(addr, daemon->cond_domain)))
|
||||
return c->domain;
|
||||
|
||||
return daemon->domain_suffix;
|
||||
}
|
||||
#endif
|
||||
+30
-25
@@ -328,8 +328,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, &forward->source);
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -372,7 +372,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (option_bool(OPT_CONNTRACK))
|
||||
{
|
||||
unsigned int mark;
|
||||
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||
if (get_incoming_mark(&forward->source, &forward->dest, 0, &mark))
|
||||
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||
}
|
||||
#endif
|
||||
@@ -680,7 +680,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
dst_addr_4.s_addr = 0;
|
||||
netmask.s_addr = 0;
|
||||
|
||||
if (listen->iface && option_bool(OPT_NOWILD))
|
||||
if (option_bool(OPT_NOWILD) && listen->iface)
|
||||
{
|
||||
auth_dns = listen->iface->dns_auth;
|
||||
|
||||
@@ -788,8 +788,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
|
||||
!label_exception(if_index, listen->family, &dst_addr))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -807,7 +808,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
|
||||
/* interface may be new */
|
||||
if (!iface && !option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->addr.sa.sa_family == AF_INET &&
|
||||
@@ -880,9 +881,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
unsigned short qtype;
|
||||
unsigned int gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
struct dns_header *header;
|
||||
/* Max TCP packet + slop + size */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
unsigned char *payload = &packet[2];
|
||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
u16 *length = (u16 *)packet;
|
||||
struct server *last_server;
|
||||
struct in_addr dst_addr_4;
|
||||
union mysockaddr peer_addr;
|
||||
@@ -896,14 +900,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (!packet ||
|
||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
!(size = c1 << 8 | c2) ||
|
||||
!read_write(confd, packet, size, 1))
|
||||
!read_write(confd, payload, size, 1))
|
||||
return packet;
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
header = (struct dns_header *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
@@ -1020,12 +1022,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#endif
|
||||
}
|
||||
|
||||
c1 = size >> 8;
|
||||
c2 = size;
|
||||
*length = htons(size);
|
||||
|
||||
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 0) ||
|
||||
!read_write(last_server->tcpfd, packet, size, 0) ||
|
||||
if (!read_write(last_server->tcpfd, packet, size + sizeof(u16), 0) ||
|
||||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||
!read_write(last_server->tcpfd, &c2, 1, 1))
|
||||
{
|
||||
@@ -1035,7 +1034,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
}
|
||||
|
||||
m = (c1 << 8) | c2;
|
||||
if (!read_write(last_server->tcpfd, packet, m, 1))
|
||||
if (!read_write(last_server->tcpfd, payload, m, 1))
|
||||
return packet;
|
||||
|
||||
if (!gotname)
|
||||
@@ -1071,12 +1070,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
check_log_writer(NULL);
|
||||
|
||||
c1 = m>>8;
|
||||
c2 = m;
|
||||
if (m == 0 ||
|
||||
!read_write(confd, &c1, 1, 0) ||
|
||||
!read_write(confd, &c2, 1, 0) ||
|
||||
!read_write(confd, packet, m, 0))
|
||||
*length = htons(m);
|
||||
|
||||
if (m == 0 || !read_write(confd, packet, m + sizeof(u16), 0))
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
@@ -1209,8 +1205,17 @@ struct frec *get_new_frec(time_t now, int *wait)
|
||||
/* none available, calculate time 'till oldest record expires */
|
||||
if (count > daemon->ftabsize)
|
||||
{
|
||||
static time_t last_log = 0;
|
||||
|
||||
if (oldest && wait)
|
||||
*wait = oldest->time + (time_t)TIMEOUT - now;
|
||||
|
||||
if ((int)difftime(now, last_log) > 5)
|
||||
{
|
||||
last_log = now;
|
||||
my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -655,8 +655,9 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
unsigned char *p;
|
||||
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
|
||||
int fd = daemon->dhcpfd;
|
||||
#ifdef HAVE_DHCP6
|
||||
int is6 = !!(lease->flags & (LEASE_TA | LEASE_NA));
|
||||
|
||||
#ifdef HAVE_DHCP6
|
||||
if (!daemon->dhcp)
|
||||
fd = daemon->dhcp6fd;
|
||||
#endif
|
||||
@@ -676,7 +677,12 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
||||
|
||||
buf->action = action;
|
||||
buf->flags = lease->flags;
|
||||
buf->hwaddr_len = lease->hwaddr_len;
|
||||
#ifdef HAVE_DHCP6
|
||||
if (is6)
|
||||
buf->hwaddr_len = lease->vendorclass_count;
|
||||
else
|
||||
#endif
|
||||
buf->hwaddr_len = lease->hwaddr_len;
|
||||
buf->hwaddr_type = lease->hwaddr_type;
|
||||
buf->clid_len = clid_len;
|
||||
buf->ed_len = ed_len;
|
||||
|
||||
+40
-16
@@ -26,9 +26,12 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#ifndef NFNL_SUBSYS_IPSET
|
||||
|
||||
/* We want to be able to compile against old header files
|
||||
Kernel version is handled at run-time. */
|
||||
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
|
||||
#define IPSET_ATTR_DATA 7
|
||||
#define IPSET_ATTR_IP 1
|
||||
#define IPSET_ATTR_IPADDR_IPV4 1
|
||||
@@ -39,10 +42,31 @@
|
||||
#define IPSET_CMD_DEL 10
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
#define IPSET_PROTOCOL 6
|
||||
#else
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
|
||||
#ifndef NFNETLINK_V0
|
||||
#define NFNETLINK_V0 0
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NESTED
|
||||
#define NLA_F_NESTED (1 << 15)
|
||||
#endif
|
||||
|
||||
#ifndef NLA_F_NET_BYTEORDER
|
||||
#define NLA_F_NET_BYTEORDER (1 << 14)
|
||||
#endif
|
||||
|
||||
struct my_nlattr {
|
||||
__u16 nla_len;
|
||||
__u16 nla_type;
|
||||
};
|
||||
|
||||
struct my_nfgenmsg {
|
||||
__u8 nfgen_family; /* AF_xxx */
|
||||
__u8 version; /* nfnetlink version */
|
||||
__be16 res_id; /* resource id */
|
||||
};
|
||||
|
||||
|
||||
/* data structure size in here is fixed */
|
||||
#define BUFF_SZ 256
|
||||
|
||||
@@ -53,11 +77,11 @@ static char *buffer;
|
||||
|
||||
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len;
|
||||
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
|
||||
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len);
|
||||
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
|
||||
nlh->nlmsg_len += NL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
@@ -93,8 +117,8 @@ void ipset_init(void)
|
||||
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfg;
|
||||
struct nlattr *nested[2];
|
||||
struct my_nfgenmsg *nfg;
|
||||
struct my_nlattr *nested[2];
|
||||
uint8_t proto;
|
||||
int addrsz = INADDRSZ;
|
||||
ssize_t rc;
|
||||
@@ -110,15 +134,15 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
memset(buffer, 0, BUFF_SZ);
|
||||
|
||||
nlh = (struct nlmsghdr *)buffer;
|
||||
nlh->nlmsg_len = NL_ALIGN(sizeof(struct nlmsghdr));
|
||||
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
|
||||
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg));
|
||||
nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
|
||||
nfg->nfgen_family = af;
|
||||
nfg->version = NFNETLINK_V0;
|
||||
nfg->res_id = htons(0);
|
||||
@@ -126,11 +150,11 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
|
||||
proto = IPSET_PROTOCOL;
|
||||
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
|
||||
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
|
||||
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
|
||||
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
|
||||
nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
|
||||
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
|
||||
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
add_attr(nlh,
|
||||
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
|
||||
|
||||
+16
-6
@@ -115,7 +115,7 @@ void lease_init(time_t now)
|
||||
s++;
|
||||
}
|
||||
|
||||
hw_type = atoi(s);
|
||||
hw_type = strtoul(s, NULL, 10);
|
||||
|
||||
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
|
||||
{
|
||||
@@ -345,11 +345,12 @@ void lease_update_file(time_t now)
|
||||
}
|
||||
|
||||
|
||||
static int find_interface_v4(struct in_addr local, int if_index,
|
||||
static int find_interface_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
(void) label;
|
||||
(void) broadcast;
|
||||
(void) vparam;
|
||||
|
||||
@@ -595,6 +596,8 @@ struct dhcp_lease *lease6_find_by_client(struct dhcp_lease *first, int lease_typ
|
||||
|
||||
if (!first)
|
||||
first = leases;
|
||||
else
|
||||
first = first->next;
|
||||
|
||||
for (lease = first; lease; lease = lease->next)
|
||||
{
|
||||
@@ -701,8 +704,11 @@ static struct dhcp_lease *lease_allocate(void)
|
||||
struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
if (lease)
|
||||
{
|
||||
lease->addr = addr;
|
||||
lease->hwaddr_len = 256; /* illegal value */
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
@@ -711,8 +717,12 @@ struct dhcp_lease *lease4_allocate(struct in_addr addr)
|
||||
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type)
|
||||
{
|
||||
struct dhcp_lease *lease = lease_allocate();
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->flags |= lease_type;
|
||||
|
||||
if (lease)
|
||||
{
|
||||
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||
lease->flags |= lease_type;
|
||||
}
|
||||
|
||||
return lease;
|
||||
}
|
||||
|
||||
+10
-4
@@ -193,7 +193,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
/* May be multicast arriving async */
|
||||
if (nl_async(h))
|
||||
newaddr = 1;
|
||||
{
|
||||
newaddr = 1;
|
||||
enumerate_interfaces(1); /* reset */
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
@@ -215,7 +218,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
char *label = NULL;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
@@ -226,12 +230,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_LABEL)
|
||||
label = RTA_DATA(rta);
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr && callback_ok)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
|
||||
callback_ok = 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -394,7 +400,7 @@ static int nl_async(struct nlmsghdr *h)
|
||||
static void nl_newaddress(time_t now)
|
||||
{
|
||||
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
create_bound_listeners(0);
|
||||
|
||||
+160
-62
@@ -99,6 +99,8 @@ int indextoname(int fd, int index, char *name)
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
{
|
||||
(void)fd;
|
||||
|
||||
if (index == 0 || !if_indextoname(index, name))
|
||||
return 0;
|
||||
|
||||
@@ -123,7 +125,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
ret = 0;
|
||||
|
||||
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = tmp->used = 1;
|
||||
|
||||
if (addr)
|
||||
@@ -143,7 +145,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *auth)
|
||||
}
|
||||
|
||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
ret = 0;
|
||||
|
||||
|
||||
@@ -204,11 +206,36 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iface_allowed(struct irec **irecp, int if_index,
|
||||
/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
|
||||
on the relevant address, but the name of the arrival interface, derived from the
|
||||
index won't match the config. Check that we found an interface address for the arrival
|
||||
interface: daemon->interfaces must be up-to-date. */
|
||||
int label_exception(int index, int family, struct all_addr *addr)
|
||||
{
|
||||
struct irec *iface;
|
||||
|
||||
/* labels only supported on IPv4 addresses. */
|
||||
if (family != AF_INET)
|
||||
return 0;
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
|
||||
iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct iface_param {
|
||||
struct addrlist *spare;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int iface_allowed(struct iface_param *param, int if_index, char *label,
|
||||
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||
{
|
||||
struct irec *iface;
|
||||
int fd, mtu = 0, loopback;
|
||||
int mtu = 0, loopback;
|
||||
struct ifreq ifr;
|
||||
int tftp_ok = !!option_bool(OPT_TFTP);
|
||||
int dhcp_ok = 1;
|
||||
@@ -217,39 +244,72 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
struct iname *tmp;
|
||||
#endif
|
||||
|
||||
if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
return 0;
|
||||
|
||||
loopback = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
|
||||
if (loopback)
|
||||
dhcp_ok = 0;
|
||||
|
||||
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
if (!label)
|
||||
label = ifr.ifr_name;
|
||||
|
||||
|
||||
/* Update addresses from interface_names. These are a set independent
|
||||
of the set we're listening on. */
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
|
||||
#endif
|
||||
{
|
||||
struct interface_name *int_name;
|
||||
struct addrlist *al;
|
||||
|
||||
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
|
||||
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
|
||||
{
|
||||
if (param->spare)
|
||||
{
|
||||
al = param->spare;
|
||||
param->spare = al->next;
|
||||
}
|
||||
else
|
||||
al = whine_malloc(sizeof(struct addrlist));
|
||||
|
||||
if (al)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
al->addr.addr.addr4 = addr->in.sin_addr;
|
||||
al->next = int_name->addr4;
|
||||
int_name->addr4 = al;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
al->addr.addr.addr6 = addr->in6.sin6_addr;
|
||||
al->next = int_name->addr6;
|
||||
int_name->addr6 = al;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check whether the interface IP has been added already
|
||||
we call this routine multiple times. */
|
||||
for (iface = *irecp; iface; iface = iface->next)
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, addr))
|
||||
{
|
||||
iface->dad = dad;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||
{
|
||||
if (fd != -1)
|
||||
{
|
||||
int errsave = errno;
|
||||
close(fd);
|
||||
errno = errsave;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
loopback = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
|
||||
if (loopback)
|
||||
dhcp_ok = 0;
|
||||
|
||||
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
close(fd);
|
||||
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
/* If we are restricting the set of interfaces to use, make
|
||||
sure that loopback interfaces are in that set. */
|
||||
if (daemon->if_names && loopback)
|
||||
{
|
||||
@@ -273,12 +333,12 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
}
|
||||
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
|
||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
|
||||
return 1;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (addr->sa.sa_family == AF_INET6 &&
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
|
||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
@@ -291,7 +351,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
}
|
||||
else
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
|
||||
{
|
||||
tftp_ok = 0;
|
||||
dhcp_ok = 0;
|
||||
@@ -313,8 +373,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||
{
|
||||
strcpy(iface->name, ifr.ifr_name);
|
||||
iface->next = *irecp;
|
||||
*irecp = iface;
|
||||
iface->next = daemon->interfaces;
|
||||
daemon->interfaces = iface;
|
||||
return 1;
|
||||
}
|
||||
free(iface);
|
||||
@@ -348,11 +408,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
addr.in6.sin6_scope_id = if_index;
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
|
||||
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
@@ -366,17 +426,75 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
addr.in.sin_addr = local;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
|
||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, 0);
|
||||
}
|
||||
|
||||
int enumerate_interfaces(void)
|
||||
int enumerate_interfaces(int reset)
|
||||
{
|
||||
static struct addrlist *spare = NULL;
|
||||
static int done = 0;
|
||||
struct iface_param param;
|
||||
int errsave, ret = 1;
|
||||
struct addrlist *addr, *tmp;
|
||||
struct interface_name *intname;
|
||||
|
||||
/* Do this max once per select cycle - also inhibits netlink socket use
|
||||
in TCP child processes. */
|
||||
|
||||
if (reset)
|
||||
{
|
||||
done = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (done)
|
||||
return 1;
|
||||
|
||||
done = 1;
|
||||
|
||||
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
/* remove addresses stored against interface_names */
|
||||
for (intname = daemon->int_names; intname; intname = intname->next)
|
||||
{
|
||||
for (addr = intname->addr4; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
|
||||
intname->addr4 = NULL;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
|
||||
return 0;
|
||||
for (addr = intname->addr6; addr; addr = tmp)
|
||||
{
|
||||
tmp = addr->next;
|
||||
addr->next = spare;
|
||||
spare = addr;
|
||||
}
|
||||
|
||||
intname->addr6 = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
param.spare = spare;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
ret = iface_enumerate(AF_INET6, ¶m, iface_allowed_v6);
|
||||
#endif
|
||||
|
||||
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
|
||||
if (ret)
|
||||
ret = iface_enumerate(AF_INET, ¶m, iface_allowed_v4);
|
||||
|
||||
errsave = errno;
|
||||
close(param.fd);
|
||||
errno = errsave;
|
||||
|
||||
spare = param.spare;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -948,7 +1066,7 @@ void check_servers(void)
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
{
|
||||
@@ -1156,27 +1274,7 @@ int reload_servers(char *fname)
|
||||
}
|
||||
|
||||
|
||||
/* Use an IPv4 listener socket for ioctling */
|
||||
struct in_addr get_ifaddr(char *intr)
|
||||
{
|
||||
struct listener *l;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in ret;
|
||||
|
||||
ret.sin_addr.s_addr = -1;
|
||||
|
||||
for (l = daemon->listeners;
|
||||
l && (l->family != AF_INET || l->fd == -1);
|
||||
l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
|
||||
memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
|
||||
|
||||
return ret.sin_addr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+134
-70
@@ -128,6 +128,10 @@ struct myoption {
|
||||
#define LOPT_AUTHSFS 317
|
||||
#define LOPT_AUTHPEER 318
|
||||
#define LOPT_IPSET 319
|
||||
#define LOPT_SYNTH 320
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
#define LOPT_PREF_CLSS 321
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -261,6 +265,10 @@ static const struct myoption opts[] =
|
||||
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
|
||||
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
|
||||
{ "ipset", 1, 0, LOPT_IPSET },
|
||||
{ "synth-domain", 1, 0, LOPT_SYNTH },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ "dhcp-prefix-class", 1, 0, LOPT_PREF_CLSS },
|
||||
#endif
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -400,6 +408,10 @@ static struct {
|
||||
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
|
||||
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
#endif
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -648,7 +660,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
scope_id = split_chr(arg, '%');
|
||||
#endif
|
||||
|
||||
if ((addr->in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
||||
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
|
||||
{
|
||||
addr->in.sin_port = htons(serv_port);
|
||||
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
|
||||
@@ -663,7 +675,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
|
||||
if (flags)
|
||||
*flags |= SERV_HAS_SOURCE;
|
||||
source_addr->in.sin_port = htons(source_port);
|
||||
if ((source_addr->in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
|
||||
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
|
||||
{
|
||||
#if defined(SO_BINDTODEVICE)
|
||||
source_addr->in.sin_addr.s_addr = INADDR_ANY;
|
||||
@@ -741,6 +753,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
struct dhcp_netid *np = NULL;
|
||||
u16 opt_len = 0;
|
||||
int is6 = 0;
|
||||
int option_ok = 0;
|
||||
|
||||
new->len = 0;
|
||||
new->flags = flags;
|
||||
@@ -760,16 +773,19 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strstr(arg, "option:") == arg)
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET, arg+7);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
|
||||
new->opt = 0;
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET, arg+7)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
/* option:<optname> must follow tag and vendor string. */
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef HAVE_DHCP6
|
||||
@@ -783,13 +799,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
{
|
||||
new->opt = atoi(arg+8);
|
||||
opt_len = 0;
|
||||
option_ok = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->opt = lookup_dhcp_opt(AF_INET6, arg+8);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if ((opt_len & OT_INTERNAL) && flags != DHOPT_MATCH)
|
||||
new->opt = 0;
|
||||
if ((new->opt = lookup_dhcp_opt(AF_INET6, arg+8)) != -1)
|
||||
{
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
if (!(opt_len & OT_INTERNAL) || flags == DHOPT_MATCH)
|
||||
option_ok = 1;
|
||||
}
|
||||
}
|
||||
/* option6:<opt>|<optname> must follow tag and vendor string. */
|
||||
is6 = 1;
|
||||
@@ -812,7 +831,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
new->flags |= DHOPT_RFC3925;
|
||||
if (flags == DHOPT_MATCH)
|
||||
{
|
||||
new->opt = 1; /* avoid error below */
|
||||
option_ok = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -839,16 +858,16 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & DHOPT_RFC3925))
|
||||
opt_len = lookup_dhcp_len(AF_INET6 ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET6, new->opt);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (opt_len == 0 &&
|
||||
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
|
||||
opt_len = lookup_dhcp_len(AF_INET ,new->opt);
|
||||
opt_len = lookup_dhcp_len(AF_INET, new->opt);
|
||||
|
||||
/* option may be missing with rfc3925 match */
|
||||
if (new->opt == 0)
|
||||
if (!option_ok)
|
||||
ret_err(_("bad dhcp-option"));
|
||||
|
||||
if (comma)
|
||||
@@ -1012,7 +1031,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
|
||||
cp = comma;
|
||||
comma = split(cp);
|
||||
slash = split_chr(cp, '/');
|
||||
in.s_addr = inet_addr(cp);
|
||||
inet_pton(AF_INET, cp, &in);
|
||||
if (!slash)
|
||||
{
|
||||
memcpy(op, &in, INADDRSZ);
|
||||
@@ -1557,7 +1576,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
comma = split(arg);
|
||||
new->name = NULL;
|
||||
unhide_metas(arg);
|
||||
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
#ifdef HAVE_IPV6
|
||||
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
|
||||
@@ -1618,8 +1637,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
if (inet_pton(AF_INET, arg, &subnet->addr4))
|
||||
{
|
||||
if ((prefixlen & 0x07) != 0 || prefixlen > 24)
|
||||
ret_err(_("bad prefix"));
|
||||
subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
|
||||
subnet->is6 = 0;
|
||||
}
|
||||
@@ -1671,7 +1688,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
break;
|
||||
|
||||
case 's': /* --domain */
|
||||
case 's': /* --domain */
|
||||
case LOPT_SYNTH: /* --synth-domain */
|
||||
if (strcmp (arg, "#") == 0)
|
||||
set_option_bool(OPT_RESOLV_DOMAIN);
|
||||
else
|
||||
@@ -1686,6 +1704,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
|
||||
char *netpart;
|
||||
|
||||
new->prefix = NULL;
|
||||
|
||||
unhide_metas(comma);
|
||||
if ((netpart = split_chr(comma, '/')))
|
||||
@@ -1703,25 +1723,30 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->end.s_addr = new->start.s_addr | htonl(mask);
|
||||
if (arg)
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
|
||||
if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
if (option != 's')
|
||||
{
|
||||
if (!(new->prefix = canonicalise_opt(arg)) ||
|
||||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
|
||||
ret_err(_("bad prefix"));
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 ||
|
||||
(msize != 8 && msize != 16 && msize != 24))
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.in-addr.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
in_addr_t a = ntohl(new->start.s_addr) >> 8;
|
||||
char *p;
|
||||
|
||||
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
serv->domain = d;
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
|
||||
|
||||
serv = opt_malloc(sizeof(struct server));
|
||||
memset(serv, 0, sizeof(struct server));
|
||||
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
|
||||
@@ -1733,7 +1758,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
p += sprintf(p, "%d.", a & 0xff);
|
||||
a = a >> 8;
|
||||
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
|
||||
|
||||
|
||||
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
|
||||
serv->next = daemon->servers;
|
||||
daemon->servers = serv;
|
||||
@@ -1746,11 +1771,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
u64 mask = (1LLU << (128 - msize)) - 1LLU;
|
||||
u64 addrpart = addr6part(&new->start6);
|
||||
new->is6 = 1;
|
||||
|
||||
|
||||
/* prefix==64 overflows the mask calculation above */
|
||||
if (msize == 64)
|
||||
mask = (u64)-1LL;
|
||||
|
||||
|
||||
new->end6 = new->start6;
|
||||
setaddr6part(&new->start6, addrpart & ~mask);
|
||||
setaddr6part(&new->end6, addrpart | mask);
|
||||
@@ -1759,14 +1784,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
ret_err(gen_err);
|
||||
else if (arg)
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
|
||||
if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
if (option != 's')
|
||||
{
|
||||
if (!(new->prefix = canonicalise_opt(arg)) ||
|
||||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
|
||||
ret_err(_("bad prefix"));
|
||||
}
|
||||
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
|
||||
ret_err(gen_err);
|
||||
else
|
||||
{
|
||||
/* generate the equivalent of
|
||||
local=/<domain>/
|
||||
local=/xxx.yyy.zzz.ip6.arpa/ */
|
||||
struct server *serv = opt_malloc(sizeof(struct server));
|
||||
char *p;
|
||||
|
||||
@@ -1797,7 +1827,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
arg = split(comma);
|
||||
if (inet_pton(AF_INET, comma, &new->start))
|
||||
@@ -1823,11 +1853,21 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
new->domain = d;
|
||||
new->next = daemon->cond_domain;
|
||||
daemon->cond_domain = new;
|
||||
if (option == 's')
|
||||
{
|
||||
new->next = daemon->cond_domain;
|
||||
daemon->cond_domain = new;
|
||||
}
|
||||
else
|
||||
{
|
||||
new->next = daemon->synth_domains;
|
||||
daemon->synth_domains = new;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (option == 's')
|
||||
daemon->domain_suffix = d;
|
||||
else
|
||||
ret_err(gen_err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1885,7 +1925,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
{
|
||||
struct in_addr addr;
|
||||
unhide_metas(arg);
|
||||
if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
|
||||
{
|
||||
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
|
||||
baddr->next = daemon->bogus_addr;
|
||||
@@ -1903,7 +1943,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
struct iname *new = opt_malloc(sizeof(struct iname));
|
||||
comma = split(arg);
|
||||
unhide_metas(arg);
|
||||
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
|
||||
if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
|
||||
{
|
||||
new->addr.sa.sa_family = AF_INET;
|
||||
new->addr.in.sin_port = 0;
|
||||
@@ -2327,7 +2367,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (k >= 3 && strchr(a[2], '.') &&
|
||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||
(inet_pton(AF_INET, a[2], &new->netmask) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_NETMASK;
|
||||
leasepos = 3;
|
||||
@@ -2336,7 +2376,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
|
||||
if (k >= 4 && strchr(a[3], '.') &&
|
||||
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
||||
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
|
||||
{
|
||||
new->flags |= CONTEXT_BRDCAST;
|
||||
leasepos = 4;
|
||||
@@ -2366,14 +2406,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->flags |= CONTEXT_DHCP;
|
||||
else if (strstr(a[leasepos], "constructor:") == a[leasepos])
|
||||
{
|
||||
if (a[leasepos][strlen(a[leasepos])-1] == '*')
|
||||
{
|
||||
a[leasepos][strlen(a[leasepos])-1] = 0;
|
||||
new->flags |= CONTEXT_WILDCARD;
|
||||
}
|
||||
new->template_interface = opt_string_alloc(a[leasepos] + 12);
|
||||
new->flags |= CONTEXT_TEMPLATE;
|
||||
}
|
||||
else if (strstr(a[leasepos], "constructor-noauth:") == a[leasepos])
|
||||
{
|
||||
new->template_interface = opt_string_alloc(a[leasepos] + 19);
|
||||
new->flags |= CONTEXT_TEMPLATE | CONTEXT_NOAUTH;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
@@ -2414,6 +2454,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
ret_err(_("bad dhcp-range"));
|
||||
|
||||
if (leasepos < k)
|
||||
{
|
||||
@@ -2471,7 +2513,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
case 'G': /* --dhcp-host */
|
||||
{
|
||||
int j, k = 0;
|
||||
char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
struct dhcp_config *new;
|
||||
struct in_addr in;
|
||||
|
||||
@@ -2483,7 +2525,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->netid = NULL;
|
||||
|
||||
if ((a[0] = arg))
|
||||
for (k = 1; k < 6; k++)
|
||||
for (k = 1; k < 7; k++)
|
||||
if (!(a[k] = split(a[k-1])))
|
||||
break;
|
||||
|
||||
@@ -2569,7 +2611,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
|
||||
else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
|
||||
{
|
||||
struct dhcp_config *configs;
|
||||
|
||||
@@ -2766,17 +2808,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
if (comma)
|
||||
{
|
||||
unhide_metas(comma);
|
||||
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
|
||||
|
||||
/*
|
||||
* The user may have specified the tftp hostname here.
|
||||
* save it so that it can be resolved/looked up during
|
||||
* actual dhcp_reply().
|
||||
*/
|
||||
|
||||
tftp_sname = opt_string_alloc(comma);
|
||||
dhcp_next_server.s_addr = 0;
|
||||
}
|
||||
if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
|
||||
{
|
||||
/*
|
||||
* The user may have specified the tftp hostname here.
|
||||
* save it so that it can be resolved/looked up during
|
||||
* actual dhcp_reply().
|
||||
*/
|
||||
|
||||
tftp_sname = opt_string_alloc(comma);
|
||||
dhcp_next_server.s_addr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2789,7 +2831,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
new->next = daemon->boot_config;
|
||||
daemon->boot_config = new;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2943,7 +2985,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
case LOPT_PREF_CLSS: /* --dhcp-prefix-class */
|
||||
{
|
||||
struct prefix_class *new = opt_malloc(sizeof(struct prefix_class));
|
||||
|
||||
if (!(comma = split(arg)) ||
|
||||
!atoi_check16(comma, &new->class))
|
||||
ret_err(gen_err);
|
||||
|
||||
new->tag.net = opt_string_alloc(set_prefix(arg));
|
||||
new->next = daemon->prefix_classes;
|
||||
daemon->prefix_classes = new;
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
case 'U': /* --dhcp-vendorclass */
|
||||
case 'j': /* --dhcp-userclass */
|
||||
case LOPT_CIRCUIT: /* --dhcp-circuitid */
|
||||
@@ -3087,7 +3147,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
while (arg) {
|
||||
struct addr_list *new = opt_malloc(sizeof(struct addr_list));
|
||||
comma = split(arg);
|
||||
if ((new->addr.s_addr = inet_addr(arg)) == (in_addr_t)-1)
|
||||
if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
|
||||
ret_err(_("bad dhcp-proxy address"));
|
||||
new->next = daemon->override_relays;
|
||||
daemon->override_relays = new;
|
||||
@@ -3130,15 +3190,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
dash = split_chr(a[0], '-');
|
||||
|
||||
if ((k < 2) ||
|
||||
((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
|
||||
((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
|
||||
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
|
||||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
|
||||
option = '?';
|
||||
|
||||
if (k == 3)
|
||||
new->mask.s_addr = inet_addr(a[2]);
|
||||
inet_pton(AF_INET, a[2], &new->mask);
|
||||
|
||||
if (dash &&
|
||||
((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
|
||||
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
|
||||
!is_same_net(new->in, new->end, new->mask) ||
|
||||
ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
|
||||
ret_err(_("invalid alias range"));
|
||||
@@ -3158,6 +3218,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
|
||||
new = opt_malloc(sizeof(struct interface_name));
|
||||
new->next = NULL;
|
||||
new->addr4 = NULL;
|
||||
#ifdef HAVE_IPV6
|
||||
new->addr6 = NULL;
|
||||
#endif
|
||||
/* Add to the end of the list, so that first name
|
||||
of an interface is used for PTR lookups. */
|
||||
for (up = &daemon->int_names; *up; up = &((*up)->next));
|
||||
|
||||
+101
-31
@@ -47,6 +47,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
int scope, int if_index, int flags,
|
||||
int prefered, int valid, void *vparam);
|
||||
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
|
||||
static void new_timeout(struct dhcp_context *context, time_t now);
|
||||
|
||||
static int hop_limit;
|
||||
|
||||
@@ -158,7 +159,7 @@ void icmp6_packet(time_t now)
|
||||
return;
|
||||
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, interface))
|
||||
return;
|
||||
|
||||
if (packet[1] != 0)
|
||||
@@ -187,9 +188,8 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
{
|
||||
struct ra_packet *ra;
|
||||
struct ra_param parm;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in6 addr;
|
||||
struct dhcp_context *context;
|
||||
struct dhcp_context *context, *tmp, **up;
|
||||
struct dhcp_netid iface_id;
|
||||
struct dhcp_opt *opt_cfg;
|
||||
int done_dns = 0;
|
||||
@@ -228,12 +228,66 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
context->netid.next = &context->netid;
|
||||
}
|
||||
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
|
||||
!parm.found_context)
|
||||
if (!iface_enumerate(AF_INET6, &parm, add_prefixes))
|
||||
return;
|
||||
|
||||
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
|
||||
/* Look for constructed contexts associated with addresses which have gone,
|
||||
and advertise them with preferred_time == 0 RFC 6204 4.3 L-13 */
|
||||
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
|
||||
{
|
||||
tmp = context->next;
|
||||
|
||||
if (context->if_index == iface && (context->flags & CONTEXT_OLD))
|
||||
{
|
||||
unsigned int old = difftime(now, context->address_lost_time);
|
||||
|
||||
if (old > context->saved_valid)
|
||||
{
|
||||
/* We've advertised this enough, time to go */
|
||||
*up = context->next;
|
||||
free(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct prefix_opt *opt;
|
||||
struct in6_addr local = context->start6;
|
||||
int do_slaac = 0;
|
||||
|
||||
parm.found_context = 1;
|
||||
|
||||
/* zero net part of address */
|
||||
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
do_slaac = 1;
|
||||
|
||||
if ((opt = expand(sizeof(struct prefix_opt))))
|
||||
{
|
||||
opt->type = ICMP6_OPT_PREFIX;
|
||||
opt->len = 4;
|
||||
opt->prefix_len = context->prefix;
|
||||
/* autonomous only if we're not doing dhcp, always set "on-link" */
|
||||
opt->flags = do_slaac ? 0xC0 : 0x80;
|
||||
opt->valid_lifetime = htonl(context->saved_valid - old);
|
||||
opt->preferred_lifetime = htonl(0);
|
||||
opt->reserved = 0;
|
||||
opt->prefix = local;
|
||||
|
||||
inet_ntop(AF_INET6, &local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s old prefix", iface_name, daemon->addrbuff);
|
||||
}
|
||||
|
||||
up = &context->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
up = &context->next;
|
||||
}
|
||||
|
||||
if (!parm.found_context)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
|
||||
available from SIOCGIFMTU */
|
||||
@@ -291,7 +345,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
put_opt6_char(ICMP6_OPT_DNSSL);
|
||||
put_opt6_char(len + 1);
|
||||
put_opt6_short(0);
|
||||
put_opt6_long(1800); /* lifetime - twice RA retransmit */
|
||||
put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
|
||||
put_opt6(opt_cfg->val, opt_cfg->len);
|
||||
|
||||
/* pad */
|
||||
@@ -300,9 +354,9 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
|
||||
}
|
||||
}
|
||||
|
||||
if (!done_dns)
|
||||
if (daemon->port == NAMESERVER_PORT && !done_dns)
|
||||
{
|
||||
/* default == us. */
|
||||
/* default == us, as long as we are supplying DNS service. */
|
||||
put_opt6_char(ICMP6_OPT_RDNSS);
|
||||
put_opt6_char(3);
|
||||
put_opt6_short(0);
|
||||
@@ -361,11 +415,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
struct dhcp_context *context;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix))
|
||||
{
|
||||
context->saved_valid = valid;
|
||||
|
||||
if ((context->flags &
|
||||
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
|
||||
{
|
||||
@@ -386,12 +442,12 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
param->other = 1;
|
||||
}
|
||||
|
||||
/* find floor time, don't reduce below RA interval. */
|
||||
/* find floor time, don't reduce below 3 * RA interval. */
|
||||
if (time > context->lease_time)
|
||||
{
|
||||
time = context->lease_time;
|
||||
if (time < ((unsigned int)RA_INTERVAL))
|
||||
time = RA_INTERVAL;
|
||||
if (time < ((unsigned int)(3 * RA_INTERVAL)))
|
||||
time = 3 * RA_INTERVAL;
|
||||
}
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
@@ -466,6 +522,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
|
||||
inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
|
||||
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -520,20 +577,29 @@ time_t periodic_ra(time_t now)
|
||||
if (!context)
|
||||
break;
|
||||
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
if ((context->flags & CONTEXT_OLD) && context->if_index != 0)
|
||||
{
|
||||
/* A context for an old address. We'll not find the interface by
|
||||
looking for addresses, but we know it anyway, as long as we
|
||||
sent at least one RA whilst the address was current. */
|
||||
param.iface = context->if_index;
|
||||
new_timeout(context, now);
|
||||
}
|
||||
else if (iface_enumerate(AF_INET6, ¶m, iface_search))
|
||||
/* There's a context overdue, but we can't find an interface
|
||||
associated with it, because it's for a subnet we dont
|
||||
have an interface on. Probably we're doing DHCP on
|
||||
a remote subnet via a relay. Zero the timer, since we won't
|
||||
ever be able to send ra's and satistfy it. */
|
||||
context->ra_time = 0;
|
||||
else if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
|
||||
if (param.iface != 0 &&
|
||||
indextoname(daemon->icmp6fd, param.iface, interface) &&
|
||||
iface_check(AF_LOCAL, NULL, interface, NULL))
|
||||
{
|
||||
struct iname *tmp;
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, interface) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, interface))
|
||||
break;
|
||||
if (!tmp)
|
||||
send_ra(now, param.iface, interface, NULL);
|
||||
@@ -554,7 +620,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
(void)valid;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if (!(context->flags & CONTEXT_TEMPLATE) &&
|
||||
if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
prefix == context->prefix &&
|
||||
is_same_net6(local, &context->start6, prefix) &&
|
||||
is_same_net6(local, &context->end6, prefix) &&
|
||||
@@ -568,12 +634,7 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
if (!(flags & IFACE_TENTATIVE))
|
||||
param->iface = if_index;
|
||||
|
||||
if (difftime(param->now, context->ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = param->now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 3/4 - 1 times RA_INTERVAL */
|
||||
context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
|
||||
new_timeout(context, param->now);
|
||||
|
||||
/* zero timers for other contexts on the same subnet, so they don't timeout
|
||||
independently */
|
||||
@@ -588,6 +649,15 @@ static int iface_search(struct in6_addr *local, int prefix,
|
||||
|
||||
return 1; /* keep searching */
|
||||
}
|
||||
|
||||
|
||||
static void new_timeout(struct dhcp_context *context, time_t now)
|
||||
{
|
||||
if (difftime(now, context->ra_short_period_start) < 60.0)
|
||||
/* range 5 - 20 */
|
||||
context->ra_time = now + 5 + (rand16()/4400);
|
||||
else
|
||||
/* range 3/4 - 1 times RA_INTERVAL */
|
||||
context->ra_time = now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
|
||||
}
|
||||
|
||||
#endif
|
||||
+78
-23
@@ -1450,19 +1450,42 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
if (is_arpa == F_IPV4)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
|
||||
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (is_arpa == F_IPV6)
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
{
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
|
||||
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
|
||||
break;
|
||||
|
||||
if (addrlist)
|
||||
break;
|
||||
else
|
||||
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
|
||||
intr = intr->next;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intr)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", intr->name))
|
||||
@@ -1517,6 +1540,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_rev_synth(is_arpa, &addr, name))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CONFIG | F_REVERSE | is_arpa, name, &addr, NULL);
|
||||
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_PTR, C_IN, "d", name))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
option_bool(OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4, 1))
|
||||
@@ -1533,7 +1569,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||
{
|
||||
unsigned short type = T_A;
|
||||
|
||||
struct interface_name *intr;
|
||||
|
||||
if (flag == F_IPV6)
|
||||
#ifdef HAVE_IPV6
|
||||
type = T_AAAA;
|
||||
@@ -1582,31 +1619,38 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* interface name stuff */
|
||||
if (qtype == T_A)
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
break;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
struct interface_name *intr;
|
||||
struct addrlist *addrlist;
|
||||
|
||||
for (intr = daemon->int_names; intr; intr = intr->next)
|
||||
if (hostname_isequal(name, intr->name))
|
||||
break;
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (intr)
|
||||
addrlist = intr->addr4;
|
||||
#ifdef HAVE_IPV6
|
||||
if (type == T_AAAA)
|
||||
addrlist = intr->addr6;
|
||||
#endif
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
|
||||
else
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
if (!addrlist)
|
||||
log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
|
||||
else
|
||||
for (; addrlist; addrlist = addrlist->next)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN,
|
||||
type == T_A ? "4" : "6", &addrlist->addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
cname_restart:
|
||||
@@ -1687,6 +1731,17 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)));
|
||||
}
|
||||
else if (is_name_synthetic(flag, name, &addr))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL);
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL, type, C_IN, type == T_A ? "4" : "6", &addr))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (qtype == T_CNAME || qtype == T_ANY)
|
||||
|
||||
+139
-121
@@ -39,6 +39,7 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
|
||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static int in_list(unsigned char *list, int opt);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
unsigned char *real_end,
|
||||
@@ -354,6 +355,117 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
ntohl(mess->xid), daemon->namebuff, inet_ntoa(context_tmp->end));
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
mess->op = BOOTREPLY;
|
||||
|
||||
@@ -493,9 +605,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
lease_set_interface(lease, int_index, now);
|
||||
|
||||
clear_packet(mess, end);
|
||||
match_vendor_opts(NULL, daemon->dhcp_opts); /* clear flags */
|
||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||
netid, subnet_addr, 0, 0, -1, NULL, 0, now);
|
||||
netid, subnet_addr, 0, 0, -1, NULL, vendor_class_len, now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +615,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 3)))
|
||||
{
|
||||
/* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
|
||||
int len = option_len(opt);
|
||||
@@ -534,7 +645,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
|
||||
if (fqdn_flags & 0x04)
|
||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||
while (*op != 0 && ((op + (*op)) - pp) < len)
|
||||
{
|
||||
memcpy(pq, op+1, *op);
|
||||
pq += *op;
|
||||
@@ -622,119 +733,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
}
|
||||
|
||||
/* dhcp-match. If we have hex-and-wildcards, look for a left-anchored match.
|
||||
Otherwise assume the option is an array, and look for a matching element.
|
||||
If no data given, existance of the option is enough. This code handles
|
||||
rfc3925 V-I classes too. */
|
||||
for (o = daemon->dhcp_match; o; o = o->next)
|
||||
{
|
||||
unsigned int len, elen, match = 0;
|
||||
size_t offset, o2;
|
||||
|
||||
if (o->flags & DHOPT_RFC3925)
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, OPTION_VENDOR_IDENT, 5)))
|
||||
continue;
|
||||
|
||||
for (offset = 0; offset < (option_len(opt) - 5u); offset += len + 5)
|
||||
{
|
||||
len = option_uint(opt, offset + 4 , 1);
|
||||
/* Need to take care that bad data can't run us off the end of the packet */
|
||||
if ((offset + len + 5 <= (option_len(opt))) &&
|
||||
(option_uint(opt, offset, 4) == (unsigned int)o->u.encap))
|
||||
for (o2 = offset + 5; o2 < offset + len + 5; o2 += elen + 1)
|
||||
{
|
||||
elen = option_uint(opt, o2, 1);
|
||||
if ((o2 + elen + 1 <= option_len(opt)) &&
|
||||
(match = match_bytes(o, option_ptr(opt, o2 + 1), elen)))
|
||||
break;
|
||||
}
|
||||
if (match)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt = option_find(mess, sz, o->opt, 1)))
|
||||
continue;
|
||||
|
||||
match = match_bytes(o, option_ptr(opt, 0), option_len(opt));
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
o->netid->next = netid;
|
||||
netid = o->netid;
|
||||
}
|
||||
}
|
||||
|
||||
/* user-class options are, according to RFC3004, supposed to contain
|
||||
a set of counted strings. Here we check that this is so (by seeing
|
||||
if the counts are consistent with the overall option length) and if
|
||||
so zero the counts so that we don't get spurious matches between
|
||||
the vendor string and the counts. If the lengths don't add up, we
|
||||
assume that the option is a single string and non RFC3004 compliant
|
||||
and just do the substring match. dhclient provides these broken options.
|
||||
The code, later, which sends user-class data to the lease-change script
|
||||
relies on the transformation done here.
|
||||
*/
|
||||
|
||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
|
||||
{
|
||||
unsigned char *ucp = option_ptr(opt, 0);
|
||||
int tmp, j;
|
||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||
if (j == option_len(opt))
|
||||
for (j = 0; j < option_len(opt); j = tmp)
|
||||
{
|
||||
tmp = j + ucp[j] + 1;
|
||||
ucp[j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||
{
|
||||
int mopt;
|
||||
|
||||
if (vendor->match_type == MATCH_VENDOR)
|
||||
mopt = OPTION_VENDOR_ID;
|
||||
else if (vendor->match_type == MATCH_USER)
|
||||
mopt = OPTION_USER_CLASS;
|
||||
else
|
||||
continue;
|
||||
|
||||
if ((opt = option_find(mess, sz, mopt, 1)))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||
if (memcmp(vendor->data, option_ptr(opt, i), vendor->len) == 0)
|
||||
{
|
||||
vendor->netid.next = netid;
|
||||
netid = &vendor->netid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mark vendor-encapsulated options which match the client-supplied vendor class,
|
||||
save client-supplied vendor class */
|
||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID, 1)))
|
||||
{
|
||||
memcpy(daemon->dhcp_buff3, option_ptr(opt, 0), option_len(opt));
|
||||
vendor_class_len = option_len(opt);
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
if (sanitise(option_find(mess, sz, OPTION_USER_CLASS, 1), daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u user class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
}
|
||||
|
||||
tagif_netid = run_tag_if(netid);
|
||||
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||
if (match_netid(id_list->list, tagif_netid, 0))
|
||||
@@ -1072,7 +1072,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
Have to set override to make sure we echo back the correct server-id */
|
||||
struct irec *intr;
|
||||
|
||||
enumerate_interfaces();
|
||||
enumerate_interfaces(0);
|
||||
|
||||
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||
if (intr->addr.sa.sa_family == AF_INET &&
|
||||
@@ -1410,7 +1410,21 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(server_id(context, override, fallback).s_addr));
|
||||
|
||||
|
||||
/* RFC 2131 says that DHCPINFORM shouldn't include lease-time parameters, but
|
||||
we supply a utility which makes DHCPINFORM requests to get this information.
|
||||
Only include lease time if OPTION_LEASE_TIME is in the parameter request list,
|
||||
which won't be true for ordinary clients, but will be true for the
|
||||
dhcp_lease_time utility. */
|
||||
if (lease && in_list(req_options, OPTION_LEASE_TIME))
|
||||
{
|
||||
if (lease->expires == 0)
|
||||
time = 0xffffffff;
|
||||
else
|
||||
time = (unsigned int)difftime(lease->expires, now);
|
||||
option_put(mess, end, OPTION_LEASE_TIME, 4, time);
|
||||
}
|
||||
|
||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||
|
||||
@@ -2275,7 +2289,9 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (domain)
|
||||
len += strlen(domain) + 1;
|
||||
|
||||
else if (fqdn_flags & 0x04)
|
||||
len--;
|
||||
|
||||
if ((p = free_space(mess, end, OPTION_CLIENT_FQDN, len)))
|
||||
{
|
||||
*(p++) = fqdn_flags & 0x0f; /* MBZ bits to zero */
|
||||
@@ -2286,8 +2302,10 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
p = do_rfc1035_name(p, hostname);
|
||||
if (domain)
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
{
|
||||
p = do_rfc1035_name(p, domain);
|
||||
*p++ = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+336
-125
@@ -29,6 +29,9 @@ struct state {
|
||||
char *iface_name;
|
||||
void *packet_options, *end;
|
||||
struct dhcp_netid *tags, *context_tags;
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *send_prefix_class;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **relay_tagsp, struct dhcp_context *context,
|
||||
@@ -45,11 +48,19 @@ static void get_context_tag(struct state *state, struct dhcp_context *context);
|
||||
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
|
||||
static int build_ia(struct state *state, int *t1cntr);
|
||||
static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz);
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context);
|
||||
#endif
|
||||
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr);
|
||||
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr);
|
||||
static int check_address(struct state *state, struct in6_addr *addr);
|
||||
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
|
||||
unsigned int *min_time, struct in6_addr *addr, int update_lease, time_t now);
|
||||
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now);
|
||||
static int add_local_addrs(struct dhcp_context *context);
|
||||
struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, struct dhcp_context *context);
|
||||
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
|
||||
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time);
|
||||
|
||||
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
|
||||
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
|
||||
@@ -109,10 +120,11 @@ static int dhcp6_maybe_relay(struct in6_addr *link_address, struct dhcp_netid **
|
||||
!IN6_IS_ADDR_MULTICAST(link_address))
|
||||
for (c = daemon->dhcp6; c; c = c->next)
|
||||
if ((c->flags & CONTEXT_DHCP) &&
|
||||
!(c->flags & CONTEXT_TEMPLATE) &&
|
||||
!(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
|
||||
is_same_net6(link_address, &c->start6, c->prefix) &&
|
||||
is_same_net6(link_address, &c->end6, c->prefix))
|
||||
{
|
||||
c->preferred = c->valid = 0xffffffff;
|
||||
c->current = context;
|
||||
context = c;
|
||||
}
|
||||
@@ -204,6 +216,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
struct dhcp_context *context_tmp;
|
||||
unsigned int ignore = 0;
|
||||
struct state state;
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
struct prefix_class *p;
|
||||
int dump_all_prefix_classes = 0;
|
||||
#endif
|
||||
|
||||
state.packet_options = inbuff + 4;
|
||||
state.end = inbuff + sz;
|
||||
@@ -221,6 +237,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
state.client_hostname = NULL;
|
||||
state.iface_name = iface_name;
|
||||
state.fqdn_flags = 0x01; /* default to send if we recieve no FQDN option */
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
state.send_prefix_class = NULL;
|
||||
#endif
|
||||
|
||||
/* set tag with name == interface */
|
||||
iface_id.net = iface_name;
|
||||
@@ -460,7 +479,32 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
if (have_config(config, CONFIG_DISABLE))
|
||||
ignore = 1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
|
||||
if (daemon->prefix_classes && (msg_type == DHCP6SOLICIT || msg_type == DHCP6REQUEST))
|
||||
{
|
||||
void *oro;
|
||||
|
||||
if ((oro = opt6_find(state.packet_options, state.end, OPTION6_ORO, 0)))
|
||||
for (i = 0; i < opt6_len(oro) - 1; i += 2)
|
||||
if (opt6_uint(oro, i, 2) == OPTION6_PREFIX_CLASS)
|
||||
{
|
||||
dump_all_prefix_classes = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg_type != DHCP6SOLICIT || dump_all_prefix_classes)
|
||||
/* Add the tags associated with prefix classes so we can use the DHCP ranges.
|
||||
Not done for SOLICIT as we add them one-at-time. */
|
||||
for (p = daemon->prefix_classes; p ; p = p->next)
|
||||
{
|
||||
p->tag.next = state.tags;
|
||||
state.tags = &p->tag;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tagif = run_tag_if(state.tags);
|
||||
|
||||
/* if all the netids in the ignore list are present, ignore this client */
|
||||
@@ -495,8 +539,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
case DHCP6SOLICIT:
|
||||
{
|
||||
void *rapid_commit = opt6_find(state.packet_options, state.end, OPTION6_RAPID_COMMIT, 0);
|
||||
int used_config = 0, address_assigned = 0;
|
||||
|
||||
int address_assigned = 0;
|
||||
/* tags without all prefix-class tags */
|
||||
struct dhcp_netid *solicit_tags = tagif;
|
||||
struct dhcp_context *c;
|
||||
|
||||
if (rapid_commit)
|
||||
{
|
||||
o = new_opt6(OPTION6_RAPID_COMMIT);
|
||||
@@ -506,111 +553,180 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
/* set reply message type */
|
||||
*outmsgtypep = rapid_commit ? DHCP6REPLY : DHCP6ADVERTISE;
|
||||
|
||||
log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? "ignored" : NULL);
|
||||
log6_packet(&state, "DHCPSOLICIT", NULL, ignore ? _("ignored") : NULL);
|
||||
|
||||
if (ignore)
|
||||
return 0;
|
||||
|
||||
/* reset USED bits in leases */
|
||||
lease6_reset();
|
||||
|
||||
/* Can use configured address max once per prefix */
|
||||
for (c = context; c; c = c->current)
|
||||
c->flags &= ~CONTEXT_CONF_USED;
|
||||
|
||||
for (opt = state.packet_options; opt; opt = opt6_next(opt, state.end))
|
||||
{
|
||||
void *ia_option, *ia_end;
|
||||
unsigned int min_time = 0xffffffff;
|
||||
int t1cntr;
|
||||
int config_ok = 0;
|
||||
struct dhcp_context *c;
|
||||
int ia_counter;
|
||||
/* set unless we're sending a particular prefix-class, when we
|
||||
want only dhcp-ranges with the correct tags set and not those without any tags. */
|
||||
int plain_range = 1;
|
||||
u32 lease_time, requested_time;
|
||||
struct dhcp_lease *ltmp;
|
||||
struct in6_addr *req_addr;
|
||||
struct in6_addr addr;
|
||||
|
||||
|
||||
if (!check_ia(&state, opt, &ia_end, &ia_option))
|
||||
continue;
|
||||
|
||||
if (have_config(config, CONFIG_ADDR6))
|
||||
/* reset USED bits in contexts - one address per prefix per IAID */
|
||||
for (c = context; c; c = c->current)
|
||||
c->flags &= ~CONTEXT_USED;
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (daemon->prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
{
|
||||
struct dhcp_lease *config_lease = lease6_find_by_addr(&config->addr6, 128, 0);
|
||||
void *prefix_opt;
|
||||
int prefix_class;
|
||||
|
||||
config_ok = 1;
|
||||
|
||||
if (config_lease &&
|
||||
(config_lease->clid_len != state.clid_len ||
|
||||
memcmp(config_lease->clid, state.clid, state.clid_len) != 0 ||
|
||||
config_lease->hwaddr_type != state.iaid))
|
||||
config_ok = 0; /* configured address leased elsewhere */
|
||||
if (dump_all_prefix_classes)
|
||||
/* OPTION_PREFIX_CLASS in ORO, send addresses in all prefix classes */
|
||||
plain_range = 0;
|
||||
else
|
||||
{
|
||||
if ((prefix_opt = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_PREFIX_CLASS, 2)))
|
||||
{
|
||||
|
||||
prefix_class = opt6_uint(prefix_opt, 0, 2);
|
||||
|
||||
for (p = daemon->prefix_classes; p ; p = p->next)
|
||||
if (p->class == prefix_class)
|
||||
break;
|
||||
|
||||
if (!p)
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("unknown prefix-class %d"), prefix_class);
|
||||
else
|
||||
{
|
||||
/* add tag to list, and exclude undecorated dhcp-ranges */
|
||||
p->tag.next = state.tags;
|
||||
solicit_tags = run_tag_if(&p->tag);
|
||||
plain_range = 0;
|
||||
state.send_prefix_class = p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* client didn't ask for a prefix class, lets see if we can find one. */
|
||||
for (p = daemon->prefix_classes; p ; p = p->next)
|
||||
{
|
||||
p->tag.next = NULL;
|
||||
if (match_netid(&p->tag, solicit_tags, 1))
|
||||
break;
|
||||
}
|
||||
|
||||
if (p)
|
||||
{
|
||||
plain_range = 0;
|
||||
state.send_prefix_class = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (p && option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u prefix class %d tag:%s", state.xid, p->class, p->tag.net);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset USED bits in leases */
|
||||
lease6_reset();
|
||||
|
||||
#endif
|
||||
|
||||
o = build_ia(&state, &t1cntr);
|
||||
|
||||
for (; ia_option; ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
for (ia_counter = 0; ia_option; ia_counter++, ia_option = opt6_find(opt6_next(ia_option, ia_end), ia_end, OPTION6_IAADDR, 24))
|
||||
{
|
||||
req_addr = opt6_ptr(ia_option, 0);
|
||||
ltmp = lease6_find_by_addr(req_addr, 128, 0);
|
||||
requested_time = opt6_uint(ia_option, 16, 4);
|
||||
|
||||
/* reset USED bits in contexts - one address per prefix per IAID */
|
||||
for (c = context; c; c = c->current)
|
||||
c->flags &= ~CONTEXT_USED;
|
||||
|
||||
if ((c = address6_valid(context, req_addr, tagif)))
|
||||
if ((c = address6_valid(context, req_addr, solicit_tags, plain_range)))
|
||||
{
|
||||
lease_time = c->lease_time;
|
||||
/* If the client asks for an address on the same network as a configured address,
|
||||
offer the configured address instead, to make moving to newly-configured
|
||||
addresses automatic. */
|
||||
if (!used_config && config_ok && is_same_net6(req_addr, &config->addr6, c->prefix))
|
||||
if (!(c->flags & CONTEXT_CONF_USED) && config_valid(config, c, &addr) && check_address(&state, &addr))
|
||||
{
|
||||
req_addr = &config->addr6;
|
||||
used_config = 1;
|
||||
req_addr = &addr;
|
||||
mark_config_used(c, &addr);
|
||||
if (have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
}
|
||||
else if (!(c = address6_available(context, req_addr, tagif)))
|
||||
else if (!(c = address6_available(context, req_addr, solicit_tags, plain_range)))
|
||||
continue; /* not an address we're allowed */
|
||||
else if (ltmp &&
|
||||
(ltmp->clid_len != state.clid_len ||
|
||||
memcmp(ltmp->clid, state.clid, state.clid_len) != 0 ||
|
||||
ltmp->hwaddr_type != state.iaid))
|
||||
else if (!check_address(&state, req_addr))
|
||||
continue; /* address leased elsewhere */
|
||||
|
||||
/* add address to output packet */
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
state.send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(&state, c, lease_time, requested_time, &min_time, req_addr, rapid_commit != NULL, now);
|
||||
mark_context_used(&state, context, req_addr);
|
||||
get_context_tag(&state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Suggest configured address */
|
||||
if (!used_config && config_ok && (c = address6_valid(context, &config->addr6, tagif)))
|
||||
{
|
||||
used_config = 1;
|
||||
if (have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
/* add address to output packet */
|
||||
add_address(&state, c, lease_time, requested_time, &min_time, &config->addr6, rapid_commit != NULL, now);
|
||||
get_context_tag(&state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
|
||||
/* Suggest configured address(es) */
|
||||
for (c = context; c; c = c->current)
|
||||
if (!(c->flags & CONTEXT_CONF_USED) &&
|
||||
match_netid(c->filter, solicit_tags, plain_range) &&
|
||||
config_valid(config, c, &addr) &&
|
||||
check_address(&state, &addr))
|
||||
{
|
||||
mark_config_used(context, &addr);
|
||||
if (have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
else
|
||||
lease_time = c->lease_time;
|
||||
/* add address to output packet */
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
state.send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(&state, c, lease_time, lease_time, &min_time, &addr, rapid_commit != NULL, now);
|
||||
mark_context_used(&state, context, &addr);
|
||||
get_context_tag(&state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
|
||||
/* return addresses for existing leases */
|
||||
ltmp = NULL;
|
||||
while ((ltmp = lease6_find_by_client(ltmp, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.clid, state.clid_len, state.iaid)))
|
||||
{
|
||||
req_addr = (struct in6_addr *)ltmp->hwaddr;
|
||||
if ((c = address6_available(context, req_addr, tagif)))
|
||||
if ((c = address6_available(context, req_addr, solicit_tags, plain_range)))
|
||||
{
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
state.send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(&state, c, c->lease_time, c->lease_time, &min_time, req_addr, rapid_commit != NULL, now);
|
||||
mark_context_used(&state, context, req_addr);
|
||||
get_context_tag(&state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return addresses for all valid contexts which don't yet have one */
|
||||
while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, tagif, &addr)))
|
||||
while ((c = address6_allocate(context, state.clid, state.clid_len, state.iaid, ia_counter, solicit_tags, plain_range, &addr)))
|
||||
{
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
state.send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(&state, c, c->lease_time, c->lease_time, &min_time, &addr, rapid_commit != NULL, now);
|
||||
mark_context_used(&state, context, &addr);
|
||||
get_context_tag(&state, c);
|
||||
address_assigned = 1;
|
||||
}
|
||||
@@ -623,7 +739,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS);
|
||||
put_opt6_string("Oh hai from dnsmasq");
|
||||
put_opt6_string(_("success"));
|
||||
end_opt6(o1);
|
||||
|
||||
/* If --dhcp-authoritative is set, we can tell client not to wait for
|
||||
@@ -638,9 +754,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
/* no address, return error */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string("No addresses available");
|
||||
put_opt6_string(_("no addresses available"));
|
||||
end_opt6(o1);
|
||||
log6_packet(&state, "DHCPADVERTISE", NULL, _("No addresses available"));
|
||||
log6_packet(&state, "DHCPADVERTISE", NULL, _("no addresses available"));
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -653,7 +769,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
/* set reply message type */
|
||||
*outmsgtypep = DHCP6REPLY;
|
||||
|
||||
log6_packet(&state, "DHCPREQUEST", NULL, ignore ? "ignored" : NULL);
|
||||
log6_packet(&state, "DHCPREQUEST", NULL, ignore ? _("ignored") : NULL);
|
||||
|
||||
if (ignore)
|
||||
return 0;
|
||||
@@ -675,24 +791,28 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
u32 requested_time = opt6_uint(ia_option, 16, 4);
|
||||
struct dhcp_context *dynamic, *c;
|
||||
unsigned int lease_time;
|
||||
|
||||
if ((dynamic = address6_available(context, req_addr, tagif)) || (c = address6_valid(context, req_addr, tagif)))
|
||||
struct in6_addr addr;
|
||||
int config_ok = 0;
|
||||
|
||||
if ((c = address6_valid(context, req_addr, tagif, 1)))
|
||||
config_ok = config_valid(config, c, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr);
|
||||
|
||||
if ((dynamic = address6_available(context, req_addr, tagif, 1)) || c)
|
||||
{
|
||||
if (!dynamic && !(have_config(config, CONFIG_ADDR6) || !IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr)))
|
||||
if (!dynamic && !config_ok)
|
||||
{
|
||||
/* Static range, not configured. */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6UNSPEC);
|
||||
put_opt6_string("Address unavailable");
|
||||
put_opt6_string(_("address unavailable"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
else if (lease6_find_by_addr(req_addr, 128, 0) &&
|
||||
!lease6_find(state.clid, state.clid_len, state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, state.iaid, req_addr))
|
||||
else if (!check_address(&state, req_addr))
|
||||
{
|
||||
/* Address leased to another DUID/IAID */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6UNSPEC);
|
||||
put_opt6_string("Address in use");
|
||||
put_opt6_string(_("address in use"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
else
|
||||
@@ -702,22 +822,24 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
lease_time = dynamic->lease_time;
|
||||
|
||||
if (have_config(config, CONFIG_ADDR6) &&
|
||||
IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr) &&
|
||||
have_config(config, CONFIG_TIME))
|
||||
if (config_ok && have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (dump_all_prefix_classes && state.ia_type == OPTION6_IA_NA)
|
||||
state.send_prefix_class = prefix_class_from_context(c);
|
||||
#endif
|
||||
add_address(&state, dynamic, lease_time, requested_time, &min_time, req_addr, 1, now);
|
||||
get_context_tag(&state, dynamic);
|
||||
address_assigned = 1;
|
||||
}
|
||||
}
|
||||
else if (msg_type == DHCP6REQUEST)
|
||||
else
|
||||
{
|
||||
/* requested address not on the correct link */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOTONLINK);
|
||||
put_opt6_string("Not on link");
|
||||
put_opt6_string(_("not on link"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
}
|
||||
@@ -730,7 +852,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS);
|
||||
put_opt6_string("Oh hai from dnsmasq");
|
||||
put_opt6_string(_("success"));
|
||||
end_opt6(o1);
|
||||
}
|
||||
else
|
||||
@@ -738,9 +860,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
/* no address, return error */
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOADDRS);
|
||||
put_opt6_string("No addresses available");
|
||||
put_opt6_string(_("no addresses available"));
|
||||
end_opt6(o1);
|
||||
log6_packet(&state, "DHCPREPLY", NULL, _("No addresses available"));
|
||||
log6_packet(&state, "DHCPREPLY", NULL, _("no addresses available"));
|
||||
}
|
||||
|
||||
tagif = add_options(&state, fallback, context);
|
||||
@@ -772,14 +894,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
struct dhcp_lease *lease = NULL;
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
u32 requested_time = opt6_uint(ia_option, 16, 4);
|
||||
unsigned int lease_time;
|
||||
unsigned int preferred_time = 0; /* in case renewal inappropriate */
|
||||
unsigned int valid_time = 0;
|
||||
char *message = NULL;
|
||||
struct dhcp_context *this_context;
|
||||
struct dhcp_config *valid_config = config;
|
||||
|
||||
/* don't use a config to set lease time if it specifies an address which isn't this. */
|
||||
if (have_config(config, CONFIG_ADDR6) && !IN6_ARE_ADDR_EQUAL(&config->addr6, req_addr))
|
||||
valid_config = NULL;
|
||||
|
||||
if (!(lease = lease6_find(state.clid, state.clid_len,
|
||||
state.ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
|
||||
state.iaid, req_addr)))
|
||||
@@ -790,48 +909,54 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
save_counter(iacntr);
|
||||
t1cntr = 0;
|
||||
|
||||
log6_packet(&state, "DHCPREPLY", req_addr, "lease not found");
|
||||
log6_packet(&state, "DHCPREPLY", req_addr, _("lease not found"));
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
put_opt6_string("No binding found");
|
||||
put_opt6_string(_("no binding found"));
|
||||
end_opt6(o1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if ((this_context = address6_available(context, req_addr, tagif)) ||
|
||||
(this_context = address6_valid(context, req_addr, tagif)))
|
||||
if ((this_context = address6_available(context, req_addr, tagif, 1)) ||
|
||||
(this_context = address6_valid(context, req_addr, tagif, 1)))
|
||||
{
|
||||
struct in6_addr addr;
|
||||
unsigned int lease_time;
|
||||
|
||||
get_context_tag(&state, this_context);
|
||||
|
||||
lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time;
|
||||
if (config_valid(config, this_context, &addr) && IN6_ARE_ADDR_EQUAL(&addr, req_addr) && have_config(config, CONFIG_TIME))
|
||||
lease_time = config->lease_time;
|
||||
else
|
||||
lease_time = this_context->lease_time;
|
||||
|
||||
if (requested_time < 120u )
|
||||
requested_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
|
||||
lease_time = requested_time;
|
||||
calculate_times(this_context, &min_time, &valid_time, &preferred_time, lease_time, requested_time);
|
||||
|
||||
lease_set_expires(lease, lease_time, now);
|
||||
lease_set_expires(lease, valid_time, now);
|
||||
if (state.ia_type == OPTION6_IA_NA && state.hostname)
|
||||
{
|
||||
char *addr_domain = get_domain6(req_addr);
|
||||
if (!state.send_domain)
|
||||
state.send_domain = addr_domain;
|
||||
lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain);
|
||||
lease_set_hostname(lease, state.hostname, state.hostname_auth, addr_domain, state.domain);
|
||||
message = state.hostname;
|
||||
}
|
||||
|
||||
if (lease_time < min_time)
|
||||
min_time = lease_time;
|
||||
|
||||
if (preferred_time == 0)
|
||||
message = _("deprecated");
|
||||
}
|
||||
else
|
||||
message = _("address invalid");
|
||||
|
||||
log6_packet(&state, "DHCPREPLY", req_addr, state.hostname);
|
||||
log6_packet(&state, "DHCPREPLY", req_addr, message);
|
||||
|
||||
o1 = new_opt6(OPTION6_IAADDR);
|
||||
put_opt6(req_addr, sizeof(*req_addr));
|
||||
/* preferred lifetime */
|
||||
put_opt6_long(!this_context || (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
|
||||
put_opt6_long(!this_context ? 0 : lease_time); /* valid lifetime */
|
||||
put_opt6_long(preferred_time);
|
||||
put_opt6_long(valid_time);
|
||||
end_opt6(o1);
|
||||
}
|
||||
|
||||
@@ -861,11 +986,11 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
|
||||
|
||||
if (!address6_available(context, req_addr, tagif))
|
||||
if (!address6_available(context, req_addr, tagif, 1))
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOTONLINK);
|
||||
put_opt6_string("Confirm failed");
|
||||
put_opt6_string(_("confirm failed"));
|
||||
end_opt6(o1);
|
||||
return 1;
|
||||
}
|
||||
@@ -876,7 +1001,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS );
|
||||
put_opt6_string("All addresses still on link");
|
||||
put_opt6_string(_("all addresses still on link"));
|
||||
end_opt6(o1);
|
||||
break;
|
||||
}
|
||||
@@ -890,7 +1015,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
context->netid.next = NULL;
|
||||
state.context_tags = &context->netid;
|
||||
}
|
||||
log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? "ignored" : state.hostname);
|
||||
log6_packet(&state, "DHCPINFORMATION-REQUEST", NULL, ignore ? _("ignored") : state.hostname);
|
||||
if (ignore)
|
||||
return 0;
|
||||
*outmsgtypep = DHCP6REPLY;
|
||||
@@ -946,7 +1071,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
put_opt6_string("No binding found");
|
||||
put_opt6_string(_("no binding found"));
|
||||
end_opt6(o1);
|
||||
|
||||
end_opt6(o);
|
||||
@@ -955,7 +1080,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6SUCCESS);
|
||||
put_opt6_string("Release received");
|
||||
put_opt6_string(_("release received"));
|
||||
end_opt6(o1);
|
||||
|
||||
break;
|
||||
@@ -1023,7 +1148,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
|
||||
{
|
||||
o1 = new_opt6(OPTION6_STATUS_CODE);
|
||||
put_opt6_short(DHCP6NOBINDING);
|
||||
put_opt6_string("No binding found");
|
||||
put_opt6_string(_("no binding found"));
|
||||
end_opt6(o1);
|
||||
|
||||
end_opt6(o);
|
||||
@@ -1174,16 +1299,18 @@ struct dhcp_netid *add_options(struct state *state, struct in6_addr *fallback, s
|
||||
size_t len = strlen(state->hostname);
|
||||
|
||||
if (state->send_domain)
|
||||
len += strlen(state->send_domain) + 1;
|
||||
len += strlen(state->send_domain) + 2;
|
||||
|
||||
o = new_opt6(OPTION6_FQDN);
|
||||
if ((p = expand(len + 3)))
|
||||
if ((p = expand(len + 2)))
|
||||
{
|
||||
*(p++) = state->fqdn_flags;
|
||||
p = do_rfc1035_name(p, state->hostname);
|
||||
if (state->send_domain)
|
||||
p = do_rfc1035_name(p, state->send_domain);
|
||||
*p = 0;
|
||||
{
|
||||
p = do_rfc1035_name(p, state->send_domain);
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
end_opt6(o);
|
||||
}
|
||||
@@ -1257,6 +1384,22 @@ static void get_context_tag(struct state *state, struct dhcp_context *context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
static struct prefix_class *prefix_class_from_context(struct dhcp_context *context)
|
||||
{
|
||||
struct prefix_class *p;
|
||||
struct dhcp_netid *t;
|
||||
|
||||
for (p = daemon->prefix_classes; p ; p = p->next)
|
||||
for (t = context->filter; t; t = t->next)
|
||||
if (strcmp(p->tag.net, t->net) == 0)
|
||||
return p;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option)
|
||||
{
|
||||
state->ia_type = opt6_type(opt);
|
||||
@@ -1325,24 +1468,25 @@ static void end_ia(int t1cntr, unsigned int min_time, int do_fuzz)
|
||||
static void add_address(struct state *state, struct dhcp_context *context, unsigned int lease_time, unsigned int requested_time,
|
||||
unsigned int *min_time, struct in6_addr *addr, int do_update, time_t now)
|
||||
{
|
||||
unsigned int valid_time = (context->valid < lease_time) ? context->valid : lease_time;
|
||||
unsigned int valid_time, preferred_time;
|
||||
int o = new_opt6(OPTION6_IAADDR);
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
put_opt6(addr, sizeof(*addr));
|
||||
calculate_times(context, min_time, &valid_time, &preferred_time, lease_time, requested_time);
|
||||
|
||||
/* preferred lifetime */
|
||||
if (requested_time < 120u )
|
||||
requested_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
|
||||
lease_time = requested_time;
|
||||
|
||||
if (lease_time < *min_time)
|
||||
*min_time = lease_time;
|
||||
put_opt6(addr, sizeof(*addr));
|
||||
put_opt6_long(preferred_time);
|
||||
put_opt6_long(valid_time);
|
||||
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
if (state->send_prefix_class)
|
||||
{
|
||||
int o1 = new_opt6(OPTION6_PREFIX_CLASS);
|
||||
put_opt6_short(state->send_prefix_class->class);
|
||||
end_opt6(o1);
|
||||
}
|
||||
#endif
|
||||
|
||||
put_opt6_long((context->preferred < lease_time) ? context->preferred : lease_time);
|
||||
put_opt6_long(valid_time); /* valid lifetime */
|
||||
|
||||
end_opt6(o);
|
||||
|
||||
if (do_update)
|
||||
@@ -1369,15 +1513,75 @@ static void add_address(struct state *state, struct dhcp_context *context, unsig
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark that we have an address for this prefix. */
|
||||
for (context = state->context; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix))
|
||||
context->flags |= CONTEXT_USED;
|
||||
|
||||
log6_packet(state, do_update ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void mark_context_used(struct state *state, struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
/* Mark that we have an address for this prefix. */
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix) &&
|
||||
(!state->send_prefix_class || state->send_prefix_class == prefix_class_from_context(context)))
|
||||
context->flags |= CONTEXT_USED;
|
||||
#else
|
||||
(void)state; /* warning */
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix))
|
||||
context->flags |= CONTEXT_USED;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mark_config_used(struct dhcp_context *context, struct in6_addr *addr)
|
||||
{
|
||||
for (; context; context = context->current)
|
||||
if (is_same_net6(addr, &context->start6, context->prefix))
|
||||
context->flags |= CONTEXT_CONF_USED;
|
||||
}
|
||||
|
||||
/* make sure address not leased to another CLID/IAID */
|
||||
static int check_address(struct state *state, struct in6_addr *addr)
|
||||
{
|
||||
struct dhcp_lease *lease;
|
||||
|
||||
if (!(lease = lease6_find_by_addr(addr, 128, 0)))
|
||||
return 1;
|
||||
|
||||
if (lease->clid_len != state->clid_len ||
|
||||
memcmp(lease->clid, state->clid, state->clid_len) != 0 ||
|
||||
lease->hwaddr_type != state->iaid)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void calculate_times(struct dhcp_context *context, unsigned int *min_time, unsigned int *valid_timep,
|
||||
unsigned int *preferred_timep, unsigned int lease_time, unsigned int requested_time)
|
||||
{
|
||||
unsigned int preferred_time, valid_time;
|
||||
|
||||
if (requested_time < 120u )
|
||||
requested_time = 120u; /* sanity */
|
||||
if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
|
||||
lease_time = requested_time;
|
||||
|
||||
valid_time = (context->valid < lease_time) ? context->valid : lease_time;
|
||||
preferred_time = (context->preferred < lease_time) ? context->preferred : lease_time;
|
||||
|
||||
if (context->flags & CONTEXT_DEPRECATE)
|
||||
preferred_time = 0;
|
||||
|
||||
if (preferred_time != 0 && preferred_time < *min_time)
|
||||
*min_time = preferred_time;
|
||||
|
||||
if (valid_time != 0 && valid_time < *min_time)
|
||||
*min_time = valid_time;
|
||||
|
||||
*valid_timep = valid_time;
|
||||
*preferred_timep = preferred_time;
|
||||
}
|
||||
|
||||
static void update_leases(struct state *state, struct dhcp_context *context, struct in6_addr *addr, unsigned int lease_time, time_t now)
|
||||
{
|
||||
struct dhcp_lease *lease = lease6_find_by_addr(addr, 128, 0);
|
||||
@@ -1407,12 +1611,12 @@ static void update_leases(struct state *state, struct dhcp_context *context, str
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
lease->hwaddr_len = 0; /* surrogate for no of vendor classes */
|
||||
lease->vendorclass_count = 0;
|
||||
|
||||
if ((class_opt = opt6_find(state->packet_options, state->end, OPTION6_VENDOR_CLASS, 4)))
|
||||
{
|
||||
void *enc_opt, *enc_end = opt6_ptr(class_opt, opt6_len(class_opt));
|
||||
lease->hwaddr_len++;
|
||||
lease->vendorclass_count++;
|
||||
/* send enterprise number first */
|
||||
sprintf(daemon->dhcp_buff2, "%u", opt6_uint(class_opt, 0, 4));
|
||||
lease_add_extradata(lease, (unsigned char *)daemon->dhcp_buff2, strlen(daemon->dhcp_buff2), 0);
|
||||
@@ -1420,7 +1624,7 @@ static void update_leases(struct state *state, struct dhcp_context *context, str
|
||||
if (opt6_len(class_opt) >= 6)
|
||||
for (enc_opt = opt6_ptr(class_opt, 4); enc_opt; enc_opt = opt6_next(enc_opt, enc_end))
|
||||
{
|
||||
lease->hwaddr_len++;
|
||||
lease->vendorclass_count++;
|
||||
lease_add_extradata(lease, opt6_ptr(enc_opt, 0), opt6_len(enc_opt), 0);
|
||||
}
|
||||
}
|
||||
@@ -1506,6 +1710,13 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
|
||||
optname = "iaaddr";
|
||||
ia_options = opt6_ptr(opt, 24);
|
||||
}
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
else if (type == OPTION6_PREFIX_CLASS)
|
||||
{
|
||||
optname = "prefix-class";
|
||||
sprintf(daemon->namebuff, "class=%u", opt6_uint(opt, 0, 2));
|
||||
}
|
||||
#endif
|
||||
else if (type == OPTION6_STATUS_CODE)
|
||||
{
|
||||
int len = sprintf(daemon->namebuff, "%u ", opt6_uint(opt, 0, 2));
|
||||
|
||||
+4
-2
@@ -38,7 +38,9 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
|
||||
lease->slaac_address = NULL;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
|
||||
if ((context->flags & CONTEXT_RA_NAME) &&
|
||||
!(context->flags & CONTEXT_OLD) &&
|
||||
lease->last_interface == context->if_index)
|
||||
{
|
||||
struct in6_addr addr = context->start6;
|
||||
if (lease->hwaddr_len == 6 &&
|
||||
@@ -123,7 +125,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
|
||||
time_t next_event = 0;
|
||||
|
||||
for (context = daemon->dhcp6; context; context = context->next)
|
||||
if ((context->flags & CONTEXT_RA_NAME))
|
||||
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
|
||||
break;
|
||||
|
||||
/* nothing configured */
|
||||
|
||||
+5
-4
@@ -201,15 +201,16 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (!iface_check(listen->family, &addra, name, NULL))
|
||||
{
|
||||
if (!option_bool(OPT_CLEVERBIND))
|
||||
enumerate_interfaces();
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
|
||||
enumerate_interfaces(0);
|
||||
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
|
||||
!label_exception(if_index, listen->family, &addra) )
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
/* allowed interfaces are the same as for DHCP */
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||
if (tmp->name && wildcard_match(tmp->name, name))
|
||||
return;
|
||||
#endif
|
||||
|
||||
@@ -554,7 +555,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
else if (++transfer->backoff > 5 && len != 0)
|
||||
else if (++transfer->backoff > 7 && len != 0)
|
||||
{
|
||||
endcon = 1;
|
||||
len = 0;
|
||||
|
||||
+23
-3
@@ -142,17 +142,20 @@ static int check_name(char *in)
|
||||
int legal_hostname(char *name)
|
||||
{
|
||||
char c;
|
||||
int first;
|
||||
|
||||
if (!check_name(name))
|
||||
return 0;
|
||||
|
||||
for (; (c = *name); name++)
|
||||
for (first = 1; (c = *name); name++, first = 0)
|
||||
/* check for legal char a-z A-Z 0-9 - _ . */
|
||||
{
|
||||
if ((c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' || c == '_')
|
||||
(c >= '0' && c <= '9'))
|
||||
continue;
|
||||
|
||||
if (!first && (c == '-' || c == '_'))
|
||||
continue;
|
||||
|
||||
/* end of hostname part */
|
||||
@@ -581,3 +584,20 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Basically match a string value against a wildcard pattern. */
|
||||
int wildcard_match(const char* wildcard, const char* match)
|
||||
{
|
||||
while (*wildcard && *match)
|
||||
{
|
||||
if (*wildcard == '*')
|
||||
return 1;
|
||||
|
||||
if (*wildcard != *match)
|
||||
return 0;
|
||||
|
||||
++wildcard;
|
||||
++match;
|
||||
}
|
||||
|
||||
return *wildcard == *match;
|
||||
}
|
||||
Reference in new issue
Block a user