Compare commits

...
28 Commits
Author SHA1 Message Date
Simon Kelley 0793380b40 Implement dhcp-ignore-names and DNSMASQ_RELAY_ADDRESS for IPv6
Build DHCPv6 by default.
2012-02-14 20:55:25 +00:00
Simon Kelley 1adadf585d Tweak Makefile so it works again in BSD make.
First cut at man page changes for DHCPv6
2012-02-13 22:15:58 +00:00
Simon Kelley e5ffdb9c77 BUILD_DIR -> BUILDDIR, for consistency. 2012-02-13 14:28:13 +00:00
Simon Kelley 6da5201092 Merge branch 'makefile' 2012-02-13 12:55:33 +00:00
Simon Kelley b36ae19434 Add BUILD_DIR variable to makefile. 2012-02-13 12:54:34 +00:00
Simon Kelley 2307eac613 Fix code parsing --domain, broken whilst added IPv6 stuff. 2012-02-13 10:13:13 +00:00
Simon Kelley 127ea40ae7 Don't build DHCPv6 by default, except when build Debian package. 2012-02-11 22:14:52 +00:00
Simon Kelley 6aef600d48 Correct duid generate on FreeBSD 2012-02-11 22:01:50 +00:00
Simon Kelley 98d76a0326 Tweaks to fix compilation on FreeBSD. 2012-02-10 22:16:45 +00:00
Simon Kelley 6ea6dcf05b Update Debian readme for new build options and (belatedly) for the
introduction of dnsmasq-utils.
2012-02-10 21:26:52 +00:00
Simon Kelley 627797800d Report correct error if prefix in dhcp-range is less than 64
Update debian/rules to provide no_dhcp6 and use_lua build opts.
Log DHCPv6 information request packets.
2012-02-10 21:19:25 +00:00
Simon Kelley c6cc03ed0c Merge branch 'dhcpv6' 2012-02-10 17:36:20 +00:00
Simon Kelley 3d7b550f52 missed DHCP6 conditional compilation. 2012-02-10 17:35:37 +00:00
Simon Kelley 751d6f4ae6 Allow the TFP server or boot server in --pxe-service, to
be a domain name instead of an IP address. This allows for
 round-robin to multiple servers, in the same way as
 --dhcp-boot.
2012-02-10 15:24:51 +00:00
Simon Kelley a5c72ab51d DHCPv6 vendor class option includes an enterprise number. Handle that. 2012-02-10 13:42:47 +00:00
Simon Kelley 9bbc88762b Fix shell scripting bug in bug scripts. 2012-02-09 21:33:09 +00:00
Simon Kelley ceae00dddf lease script should work with IPv6 now. 2012-02-09 21:28:14 +00:00
Simon Kelley 3634c54e8d dhcp-ignore and dhcp-match implemented for DHCPv6 now. 2012-02-08 14:22:37 +00:00
Simon Kelley d74942a03d IPv6 address range parsing for --domain.
Counted string DHCP option type printing
2012-02-07 20:51:56 +00:00
Simon Kelley 70c5e3e076 DHCPDECLINE handling, domain handling, more complete address selection. 2012-02-06 22:05:15 +00:00
Simon Kelley 4cb1b32009 Clean compile, basic DHCPv6 functionality is there.
TODO
     hostname handling.
     update DHCP6 configs from dns
     parse domain=<domain>,<IPv6 range>
     pretty-print counted string options.
     DECLINE messages
     lease-script fro DHCPv6
2012-02-06 14:30:41 +00:00
Simon Kelley 3268e90f5e Make default NO_DHCP6 and remove compiler warning. 2012-01-22 16:15:02 +00:00
Simon Kelley e98170816a Merge branch 'dhcpv6' 2012-01-22 16:07:22 +00:00
Simon Kelley 52b92f4db8 It compiles and it allocates a lease! No renewals yet. 2012-01-22 16:05:15 +00:00
Simon Kelley a2761754da Fix problem if dnsmasq is started without the stdin,
stdout and stderr file descriptors open. This can manifest
itself as 100% CPU use. Thanks to Chris Moore for finding
this.
2012-01-18 16:07:21 +00:00
Simon Kelley 805a11345c We don't need to check that a cache record is F_HOST in the
duplicate address code, since we're now searching a temporary hash
which holds only F_HOST records.
2012-01-13 11:51:46 +00:00
Simon Kelley 1ab62aec37 Further tuning of the fast hostfile reading code.
Use the packet buffer for hash-buckets, better hash function.
2012-01-12 11:33:16 +00:00
Simon Kelley be2daf4ad5 Enable DHCPv6 compilation 2012-01-07 17:51:57 +00:00
36 changed files with 7802 additions and 4905 deletions

No files matched your search

+29
View File
@@ -29,6 +29,35 @@ version 2.60
Determine VERSION automatically based on git magic:
release tags or hash values.
Improve start-up speed when reading large hosts files
containing many distinct addresses.
Fix problem if dnsmasq is started without the stdin,
stdout and stderr file descriptors open. This can manifest
itself as 100% CPU use. Thanks to Chris Moore for finding
this.
Fix shell-scripting bug in bld/pkg-wrapper. Thanks to
Mark Mitchell for the patch.
Allow the TFP server or boot server in --pxe-service, to
be a domain name instead of an IP address. This allows for
round-robin to multiple servers, in the same way as
--dhcp-boot. A good suggestion from Cristiano Cumer.
Support BUILDDIR variable in the Makefile. Allows
builds from multiple architectures in the same tree with eg
make BUILDDIR=linux
If BUILDDIR is not set, compilation happens in the src
directory, as before. Suggestion from Mark Mitchell.
First cut at supporting DHCPv6. Support is pretty much
there for the sort of things the existing v4 server does,
including tags, options, static addresses and relay
support. Missing is prefix delegation. This is lightly
tested alpha code, it is NOT YET PRODUCTION READY. Test
reports would be greatly valued.
version 2.59
Fix regression in 2.58 which caused failure to start up
+32 -21
View File
@@ -18,16 +18,18 @@ BINDIR = ${PREFIX}/sbin
MANDIR = ${PREFIX}/share/man
LOCALEDIR = ${PREFIX}/share/locale
BUILDDIR = $(SRC)
CFLAGS = -Wall -W -O2
#################################################################
PKG_CONFIG = pkg-config
INSTALL = install
MSGMERGE = msgmerge
MSGFMT = msgfmt
XGETTEXT = xgettext
CFLAGS = -Wall -W -O2
#################################################################
SRC = src
PO = po
MAN = man
@@ -45,56 +47,65 @@ VERSION= -DVERSION='\"`../bld/get-version`\"'
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
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o dhcp-common.o
all :
@cd $(SRC) && $(MAKE) \
HDRS = dnsmasq.h config.h dhcp_protocol.h dhcp6_protocol.h dns_protocol.h
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS)" \
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS)" \
-f ../Makefile dnsmasq
clean :
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot
rm -f $(SRC)/*.o $(SRC)/dnsmasq.a $(SRC)/dnsmasq core */core
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
install : all install-common
install-common :
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
all-i18n :
@cd $(SRC) && $(MAKE) \
all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
I18N=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
-f ../Makefile dnsmasq
@cd $(PO); for f in *.po; do \
cd ../$(SRC) && $(MAKE) \
cd ../$(BUILDDIR) && $(MAKE) \
-f ../Makefile $${f%.po}.mo; \
done
install-i18n : all-i18n install-common
cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
cd $(BUILDDIR); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
merge :
@cd $(SRC) && $(MAKE) -f ../Makefile dnsmasq.pot
merge : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) -f ../Makefile dnsmasq.pot
@cd $(PO); for f in *.po; do \
echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(BUILDDIR)/dnsmasq.pot; \
done
$(BUILDDIR):
mkdir $(BUILDDIR)
# rules below are targets in recusive makes with cwd=$(SRC)
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $<
$(OBJS:.o=.c) $(HDRS):
ln -s ../$(SRC)/$@ .
dnsmasq : $(OBJS)
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(HDRS) $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS)
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
dnsmasq.pot : $(OBJS:.o=.c) $(HDRS)
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(OBJS:.o=.c)
%.mo : ../po/%.po dnsmasq.pot
+2 -1
View File
@@ -6,7 +6,8 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c
rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c
LOCAL_MODULE := dnsmasq
+5 -2
View File
@@ -9,11 +9,14 @@
# If we can find one which matches $v[0-9].* then we assume it's
# a version-number tag, else we just use the whole string.
# we're called with pwd == src
# we're called with pwd == TLD
cd ..
if [ -d .git ]; then
if which git >/dev/null 2>&1 && [ -d .git ]; then
git describe
elif grep '\$Format:%d\$' VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]`
+2 -2
View File
@@ -3,8 +3,8 @@
search=$1
shift
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h 2>&1 >/dev/null || \
grep $search 2>&1 >/dev/null ; then
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
grep $search >/dev/null 2>&1; then
exec $*
fi
+8 -2
View File
@@ -52,7 +52,10 @@ Notes on configuring dnsmasq as packaged for Debian.
nodocs : omit documentation.
notftp : omit TFTP support.
nodhcp : omit DHCP support.
nodhcp6 : omit DHCPv6 support.
noscript : omit lease-change script support.
use_lua : provide support for lease-change scripts written
in Lua.
noipv6 : omit IPv6 support.
nodbus : omit DBus support.
noconntrack : omit connection tracking support.
@@ -60,11 +63,14 @@ Notes on configuring dnsmasq as packaged for Debian.
noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be
combined with noi18n to be effective.
(9) Dnsmasq comes as two packages - dnsmasq-base and
dnsmasq. dnsmasq-base provides the dnsmasq executable and
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and
documentation (including this file). Dnsmasq, which depends on
dnsmasq-base, provides the init script and configuration
infrastructure. This file assumes that both are installed. It is
possible to install only dnsmasq-base and use dnsmasq as a
non-"system" daemon. Libvirt, for instance, does this.
Dnsmasq-utils provides the utilities dhcp_release and
dhcp_lease_time.
+18 -10
View File
@@ -12,7 +12,7 @@
package=dnsmasq-base
# policy manual, section 10.1
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS = -g -O0 -Wall -W
else
CFLAGS = -g -O2 -Wall -W
@@ -23,43 +23,51 @@ TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
ifeq (,$(findstring nodbus,$(DEB_BUILD_OPTIONS)))
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_DBUS
endif
ifeq (,$(findstring noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_BUILD_ARCH_OS),linux)
COPTS += -DHAVE_CONNTRACK
endif
endif
ifneq (,$(findstring noipv6,$(DEB_BUILD_OPTIONS)))
ifeq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_DHCP6
endif
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_IPV6
endif
ifneq (,$(findstring notftp,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_TFTP
endif
ifneq (,$(findstring nodhcp,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP
endif
ifneq (,$(findstring noscript,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_SCRIPT
endif
ifneq (,$(findstring nortc,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_BROKEN_RTC
endif
ifneq (,$(findstring noi18n,$(DEB_BUILD_OPTIONS)))
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install
ifeq (,$(findstring noidn, $(DEB_BUILD_OPTIONS)))
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_IDN
endif
endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_LUASCRIPT
endif
clean:
$(checkdir)
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
+96 -39
View File
@@ -495,6 +495,9 @@ included and configured. This option cannot be combined with
--query-port.
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-IPv6addr>,<end-IPv6addr>[,<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
in
@@ -515,6 +518,12 @@ C) of the network address. The broadcast address is
always optional. It is always
allowed to have more than one dhcp-range in a single subnet.
For IPv6, the parameters are slightly different: instead of netmask
and broadcast address, there is an optional prefix length. If not
given, this defaults to 64. Unlike the IPv4 case, the prefix length is not
automatically derived from the interface configuration. The mimimum
size of the prefix length is 64.
The optional
.B set:<tag>
sets an alphanumeric label which marks this network so that
@@ -535,7 +544,7 @@ subnet. (See
.B pxe-prompt
and
.B pxe-service
for details.)
for details, applies to IPv4 only.)
The interface:<interface name> section is not normally used. See the
NOTES section for details of this.
@@ -570,6 +579,12 @@ refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,.....
A single
.B dhcp-host
may contain an IPv4 address or an IPv6 address, or both. IPv6 addresses must be bracketed by square brackets thus:
.B --dhcp-host=laptop,[1234::56]
Note that in IPv6 DHCP, the hardware address is not normally available, so a client must be identified by client-id (called client DUID) in IPv6-land) or hostname.
The special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others.
@@ -617,7 +632,7 @@ will only match a
Token-Ring hardware address, since the ARP-address type for token ring
is 6.
As a special case, it is possible to include more than one
As a special case, in DHCPv4, it is possible to include more than one
hardware address. eg:
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
This allows an IP address to be associated with
@@ -655,14 +670,14 @@ hostname or dotted-quad IP address. When read by dnsmasq these lines
have exactly the same effect as
.B --dhcp-host
options containing the same information. /etc/ethers is re-read when
dnsmasq receives SIGHUP.
dnsmasq receives SIGHUP. IPv6 addresses are NOT read from /etc/ethers.
.TP
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]]
.B \-O, --dhcp-option=[tag:<tag>,[tag:<tag>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>|option6:<opt>|option6:<opt-name>],[<value>[,<value>]]
Specify different or extra options to DHCP clients. By default,
dnsmasq sends some standard options to DHCP clients, the netmask and
broadcast address are set to the same as the host running dnsmasq, and
the DNS server and default route are set to the address of the machine
running dnsmasq. If the domain name option has been set, that is sent.
running dnsmasq. (Equivalent rules apply for IPv6.) If the domain name option has been set, that is sent.
This configuration allows these defaults to be overridden,
or other options specified. The option, to be sent may be given as a
decimal number or as "option:<option-name>" The option numbers are
@@ -689,6 +704,14 @@ to option 120 are handled as per RFC 3361. Dotted-quad IP addresses
which are followed by a slash and then a netmask size are encoded as
described in RFC 3442.
IPv6 options are specified using the
.B option6:
keyword, followed by the option number or option name. The IPv6 option
name space is disjoint from the IPv4 option name space. IPv6 addresses
in options must be bracketed with square brackets, eg.
.B --dhcp-option=option6:ntp-server,[1234::56]
Be careful: no checking is done that the correct type of data for the
option number is sent, it is quite possible to
persuade dnsmasq to generate illegal DHCP packets with injudicious use
@@ -704,7 +727,7 @@ literal string, use quotes. For instance when using option 66 to send
a literal IP address as TFTP server name, it is necessary to do
.B --dhcp-option=66,"1.2.3.4"
Encapsulated Vendor-class options may also be specified using
Encapsulated Vendor-class options may also be specified (IPv4 only) using
--dhcp-option: for instance
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0
sends the encapsulated vendor
@@ -716,9 +739,9 @@ for selecting encapsulated options in preference to any sent by the
client. It is
possible to omit the vendorclass completely;
.B --dhcp-option=vendor:,1,0.0.0.0
in which case the encapsulated option is always sent.
in which case the encapsulated option is always sent.
Options may be encapsulated within other options: for instance
Options may be encapsulated (IPv4 only) within other options: for instance
.B --dhcp-option=encap:175, 190, "iscsi-client0"
will send option 175, within which is the option 190. If multiple
options are given which are encapsulated with the same option number
@@ -729,8 +752,9 @@ The final variant on encapsulated options is "Vendor-Identifying
Vendor Options" as specified by RFC3925. These are denoted like this:
.B --dhcp-option=vi-encap:2, 10, "text"
The number in the vi-encap: section is the IANA enterprise number
used to identify this option.
used to identify this option. This form of encapsulation is supported
in IPv6.
The address 0.0.0.0 is not treated specially in
encapsulated options.
.TP
@@ -742,14 +766,14 @@ not ask for it in the parameter request list. This is sometimes
needed, for example when sending options to PXELinux.
.TP
.B --dhcp-no-override
Disable re-use of the DHCP servername and filename fields as extra
(IPv4 only) Disable re-use of the DHCP servername and filename fields as extra
option space. If it can, dnsmasq moves the boot server and filename
information (from dhcp-boot) out of their dedicated fields into
DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,<vendor-class>
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
Map from a vendor-class string to a tag. Most DHCP clients provide a
"vendor class" which represents, in some sense, the type of host. This option
maps vendor classes to tags, so that DHCP options may be selectively delivered
@@ -759,7 +783,13 @@ will allow options to be set only for HP printers like so:
.B --dhcp-option=tag:printers,3,192.168.4.4
The vendor-class string is
substring matched against the vendor-class supplied by the client, to
allow fuzzy matching. The set: prefix is optional but allowed for consistency.
allow fuzzy matching. The set: prefix is optional but allowed for
consistency.
Note that in IPv6 only, vendorclasses are namespaced with an
IANA-allocated enterprise number. This is given with enterprise:
keyword and specifies that only vendorclasses matching the specified
number should be searched.
.TP
.B \-j, --dhcp-userclass=set:<tag>,<user-class>
Map from a user-class string to a tag (with substring
@@ -771,7 +801,7 @@ this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering".
.TP
.B \-4, --dhcp-mac=set:<tag>,<MAC address>
Map from a MAC address to a tag. The MAC address may include
(IPv4 only) Map from a MAC address to a tag. The MAC address may include
wildcards. For example
.B --dhcp-mac=set:3com,01:34:23:*:*:*
will set the tag "3com" for any host whose MAC address matches the pattern.
@@ -781,13 +811,16 @@ Map from RFC3046 relay agent options to tags. This data may
be provided by DHCP relay agents. The circuit-id or remote-id is
normally given as colon-separated hex, but is also allowed to be a
simple string. If an exact match is achieved between the circuit or
agent ID and one provided by a relay agent, the tag is set.
agent ID and one provided by a relay agent, the tag is set.
.B dhcp-remoteid
(but not dhcp-circuitid) is supported in IPv6.
.TP
.B --dhcp-subscrid=set:<tag>,<subscriber-id>
Map from RFC3993 subscriber-id relay agent options to tags.
(IPv4 and IPv6) Map from RFC3993 subscriber-id relay agent options to tags.
.TP
.B --dhcp-proxy[=<ip addr>]......
A normal DHCP relay agent is only used to forward the initial parts of
(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
@@ -847,7 +880,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
/etc/ethers.
.TP
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>]
Generate a name for DHCP clients which do not otherwise have one,
(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
if a host provides a name, it will be used by preference to this,
unless
@@ -855,14 +888,14 @@ unless
is set.
.TP
.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]]
When all the given tags appear in the tag set, always use broadcast to
(IPv4 only) When all the given tags appear in the tag set, always use broadcast to
communicate with the host when it is unconfigured. It is permissible
to supply no tags, in which case this is unconditional. Most DHCP clients which
need broadcast replies set a flag in their requests so that this
happens automatically, some old BOOTP clients do not.
.TP
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
Set BOOTP options to be returned by the DHCP server. Server name and
(IPv4 only) Set BOOTP options to be returned by the DHCP server. Server name and
address are optional: if not provided, the name is left empty, and the
address set to the address of the machine running dnsmasq. If dnsmasq
is providing a TFTP service (see
@@ -888,7 +921,7 @@ address, and setting this flag enables this mode. Note that in the
sequential mode, clients which allow a lease to expire are much more
likely to move IP address; for this reason it should not be generally used.
.TP
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>|<server_name>]
Most uses of PXE boot-ROMS simply allow the PXE
system to obtain an IP address and then download the file specified by
.B dhcp-boot
@@ -904,17 +937,19 @@ parameter after the menu text may be a file name, in which case dnsmasq acts as
boot server and directs the PXE client to download the file by TFTP,
either from itself (
.B enable-tftp
must be set for this to work) or another TFTP server if the final IP
address is given.
must be set for this to work) or another TFTP server if the final server
address/name is given.
Note that the "layer"
suffix (normally ".0") is supplied by PXE, and should not be added to
the basename. If an integer boot service type, rather than a basename
is given, then the PXE client will search for a
suitable boot service for that type on the network. This search may be done
by broadcast, or direct to a server if its IP address is provided.
by broadcast, or direct to a server if its IP address/name is provided.
If no boot service type or filename is provided (or a boot service type of 0 is specified)
then the menu entry will abort the net boot procedure and
continue booting from local media.
continue booting from local media. The server address can be given as a domain
name which is looked up in /etc/hosts. This name can be associated in
/etc/hosts with multiple IP addresses, which are used round-robin.
.TP
.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
Setting this provides a prompt to be displayed after PXE boot. If the
@@ -947,7 +982,7 @@ create thousands of leases and use lots of memory in the dnsmasq
process.
.TP
.B \-K, --dhcp-authoritative
Should be set when dnsmasq is definitely the only DHCP server on a network.
(IPv4 only) Should be set when dnsmasq is definitely the only DHCP server on a network.
It changes the behaviour from strict RFC compliance so that DHCP requests on
unknown leases from unknown hosts are not ignored. This allows new hosts
to get a lease without a tedious timeout under all circumstances. It also
@@ -955,7 +990,7 @@ allows dnsmasq to rebuild its lease database without each client needing to
reacquire a lease, if the database is lost.
.TP
.B --dhcp-alternate-port[=<server port>[,<client port>]]
Change the ports used for DHCP from the default. If this option is
(IPv4 only) Change the ports used for DHCP from the default. If this option is
given alone, without arguments, it changes the ports used for DHCP
from 67 and 68 to 1067 and 1068. If a single argument is given, that
port number is used for the server and the port number plus one used
@@ -963,7 +998,7 @@ for the client. Finally, two port numbers allows arbitrary
specification of both server and client ports for DHCP.
.TP
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Enable dynamic allocation of IP addresses to BOOTP clients. Use this
(IPv4 only) Enable dynamic allocation of IP addresses to BOOTP clients. Use this
with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by
other hosts. if this is given without tags, then it unconditionally
@@ -971,7 +1006,7 @@ enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP
.B \-5, --no-ping
By default, the DHCP server will attempt to ensure that an address in
(IPv4 only) By default, the DHCP server will attempt to ensure that an address in
not in use before allocating it to a host. It does this by sending an
ICMP echo request (aka "ping") to the address in question. If it gets
a reply, then the address must already be in use, and another is
@@ -990,7 +1025,7 @@ executable specified by this option is run. <path>
must be an absolute pathname, no PATH search occurs.
The arguments to the process
are "add", "old" or "del", the MAC
address of the host, the IP address, and the hostname,
address of the host (or DUID for IPv6) , the IP address, and the hostname,
if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing
@@ -1001,21 +1036,17 @@ token ring. The process is run as root (assuming that dnsmasq was originally run
root) even if dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, with some or
all of the following variables added.
all of the following variables added
DNSMASQ_CLIENT_ID if the host provided a client-id.
For both IPv4 and IPv6:
DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
known, this is set to the domain part. (Note that the hostname passed
to the script as an argument is never fully-qualified.)
If the client provides vendor-class, hostname or user-class,
these are provided in DNSMASQ_VENDOR_CLASS
DNSMASQ_SUPPLIED_HOSTNAME and
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
"add" actions or "old" actions when a host resumes an existing lease,
since these data are not held in dnsmasq's lease
database.
If the client provides a hostname, DNSMASQ_SUPPLIED_HOSTNAME
If the client provides user-classes, DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn
If dnsmasq was compiled with HAVE_BROKEN_RTC, then
the length of the lease (in seconds) is stored in
@@ -1039,6 +1070,32 @@ is known.
DNSMASQ_TAGS contains all the tags set during the
DHCP transaction, separated by spaces.
For IPv4 only:
DNSMASQ_CLIENT_ID if the host provided a client-id.
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS.
For IPv6 only:
If the client provides vendor-class, DNSMASQ_VENDOR_CLASS_ID,
containing the IANA enterprise id for the class, and
DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn for the data.
DNSMASQ_DUID containing the DUID of the server: this is the same for
every call to the script.
DNSMASQ_IAID containing the IAID for the lease. If the lease is a
temporary allocation, this is prefixed to 'T'.
Note that the supplied hostname, vendorclass and userclass data is
only supplied for
"add" actions or "old" actions when a host resumes an existing lease,
since these data are not held in dnsmasq's lease
database.
All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode).
+324 -280
View File
File diff suppressed because it is too large. Load diff
+441 -397
View File
File diff suppressed because it is too large. Load diff
+442 -406
View File
File diff suppressed because it is too large. Load diff
+442 -397
View File
File diff suppressed because it is too large. Load diff
+469 -423
View File
File diff suppressed because it is too large. Load diff
+442 -406
View File
File diff suppressed because it is too large. Load diff
+438 -397
View File
File diff suppressed because it is too large. Load diff
+441 -397
View File
File diff suppressed because it is too large. Load diff
+442 -406
View File
File diff suppressed because it is too large. Load diff
+438 -397
View File
File diff suppressed because it is too large. Load diff
-2
View File
@@ -1,2 +0,0 @@
Worry about IPv6 leases and DUID in script-storage.
+14 -1
View File
@@ -108,6 +108,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
return 0; /* need code for Solaris and MacOS*/
#endif
/* AF_LINK doesn't exist in Linux, so we can't use it in our API */
if (family == AF_LOCAL)
family = AF_LINK;
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
@@ -153,7 +157,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ifr = (struct ifreq *)ifreq.iov_base;
memcpy(ifr, ptr, len);
if (ifr->ifr_addr.sa_family == family)
{
if (family == AF_INET)
@@ -190,6 +194,15 @@ int iface_enumerate(int family, void *parm, int (*callback)())
goto err;
}
#endif
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
/* Assume ethernet again here */
struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
if (sdl->sdl_alen != 0 && !((*callback)(ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
goto err;
}
#endif
}
}
+71 -44
View File
@@ -635,7 +635,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
}
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
unsigned short flags, int index, struct crec **rhash)
unsigned short flags, int index, struct crec **rhash, int hashsz)
{
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
int i, nameexists = 0;
@@ -656,24 +656,21 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
/* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, The entries are kept in hash chains, linked
by ->next (which is unused at this point) held in hash buckets in
the array rhash. Note that rhash and the values in ->next are only valid
whilst reading hosts files: the buckets are then freed, and the
->next pointer used for other things.
the array rhash, hashed on address. Note that rhash and the values
in ->next are only valid whilst reading hosts files: the buckets are
then freed, and the ->next pointer used for other things.
Only insert each unique address one into this hashing structure.
Only insert each unique address once into this hashing structure.
This complexity avoids O(n^2) divergent CPU use whilst reading
large (10000 entry) hosts files. */
/* hash address */
for (j = 0, i = 0; i < addrlen; i++)
j += ((unsigned char *)addr)[i] + (j << 6) + (j << 16) - j;
j = j % RHASHSIZE;
j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
for (lookup = rhash[j]; lookup; lookup = lookup->next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
if ((lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
@@ -753,7 +750,7 @@ static int gettok(FILE *f, char *token)
}
}
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash)
static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
{
FILE *f = fopen(filename, "r");
char *token = daemon->namebuff, *domain_suffix = NULL;
@@ -785,7 +782,7 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix;
domain_suffix = get_domain6(&addr.addr.addr6);
}
#else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
@@ -833,13 +830,13 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
strcpy(cache->name.sname, canon);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash);
add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
name_count++;
}
free(canon);
@@ -861,9 +858,8 @@ static int read_hostsfile(char *filename, int index, int cache_size, struct crec
void cache_reload(void)
{
struct crec *cache, **up, *tmp;
int i, total_size = daemon->cachesize;
int revhashsz, i, total_size = daemon->cachesize;
struct hostsfile *ah;
struct crec **reverse_hash;
cache_inserted = cache_live_freed = 0;
@@ -896,22 +892,20 @@ void cache_reload(void)
my_syslog(LOG_INFO, _("cleared cache"));
return;
}
if (!(reverse_hash = whine_malloc(sizeof(struct crec *) * RHASHSIZE)))
return;
for (i = 0; i < RHASHSIZE; i++)
reverse_hash[i] = NULL;
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size, reverse_hash);
total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE))
total_size = read_hostsfile(ah->fname, ah->index, total_size, reverse_hash);
free(reverse_hash);
total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
}
char *get_domain(struct in_addr addr)
@@ -919,13 +913,33 @@ char *get_domain(struct in_addr addr)
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
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)
{
@@ -959,15 +973,24 @@ void cache_unhash_dhcp(void)
up = &cache->hash_next;
}
void cache_add_dhcp_entry(char *host_name,
struct in_addr *host_address, time_t ttd)
void cache_add_dhcp_entry(char *host_name, int prot,
struct all_addr *host_address, time_t ttd)
{
struct crec *crec = NULL, *aliasc;
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
unsigned short flags = F_IPV4;
int in_hosts = 0;
struct cname *a;
size_t addrlen = sizeof(struct in_addr);
#ifdef HAVE_IPV6
if (prot == AF_INET6)
{
flags = F_IPV6;
addrlen = sizeof(struct in6_addr);
}
#endif
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
while ((crec = cache_find_by_name(crec, host_name, 0, flags | F_CNAME)))
{
/* check all addresses associated with name */
if (crec->flags & F_HOSTS)
@@ -975,23 +998,25 @@ void cache_add_dhcp_entry(char *host_name,
/* if in hosts, don't need DHCP record */
in_hosts = 1;
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
if (crec->flags & F_CNAME)
my_syslog(MS_DHCP | LOG_WARNING,
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
host_name, inet_ntoa(*host_address));
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
host_name, daemon->addrbuff);
else if (memcmp(&crec->addr.addr, host_address, addrlen) != 0)
{
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
inet_ntop(prot, &crec->addr.addr, daemon->namebuff, MAXDNAME);
my_syslog(MS_DHCP | LOG_WARNING,
_("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"),
host_name, inet_ntoa(*host_address),
host_name, daemon->addrbuff,
record_source(crec->uid), daemon->namebuff);
}
}
else if (!(crec->flags & F_DHCP))
{
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
cache_scan_free(host_name, NULL, 0, crec->flags & (flags | F_CNAME | F_FORWARD));
/* scan_free deletes all addresses associated with name */
break;
}
@@ -1000,14 +1025,16 @@ void cache_add_dhcp_entry(char *host_name,
if (in_hosts)
return;
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, flags)))
{
if (crec->flags & F_NEG)
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE);
else
/* avoid multiple reverse mappings */
flags &= ~F_REVERSE;
{
flags |= F_REVERSE;
cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
}
}
else
flags |= F_REVERSE;
if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next;
@@ -1016,12 +1043,12 @@ void cache_add_dhcp_entry(char *host_name,
if (crec) /* malloc may fail */
{
crec->flags = flags;
crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
if (ttd == 0)
crec->flags |= F_IMMORTAL;
else
crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address;
crec->addr.addr = *host_address;
crec->name.namep = host_name;
crec->uid = uid++;
cache_hash(crec);
+1 -2
View File
@@ -15,7 +15,6 @@
*/
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define RHASHSIZE 1024 /* hash buckets for address lookup during hostfile read */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
@@ -117,7 +116,7 @@ RESOLVFILE
has no library dependencies other than libc */
#define HAVE_DHCP
/* #define HAVE_DHCP6 */
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_SCRIPT
/* #define HAVE_LUASCRIPT */
+361
View File
@@ -0,0 +1,361 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP
void dhcp_common_init(void)
{
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->dhcp_buff3 = safe_malloc(256);
/* dhcp_packet is used by v4 and v6, outpacket only by v6
sizeof(struct dhcp_packet) is as good an initial size as any,
even for v6 */
expand_buf(&daemon->dhcp_packet, sizeof(struct dhcp_packet));
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
#endif
}
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
{
ssize_t sz;
while (1)
{
msg->msg_flags = 0;
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return -1;
if (!(msg->msg_flags & MSG_TRUNC))
break;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return -1;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
break;
}
}
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
tags = list->list;
}
return tags;
}
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags, struct dhcp_opt *opts)
{
struct dhcp_netid *tagif = run_tag_if(tags);
struct dhcp_opt *opt;
/* flag options which are valid with the current tag set (sans context tags) */
for (opt = opts; opt; opt = opt->next)
{
opt->flags &= ~DHOPT_TAGOK;
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
match_netid(opt->netid, tagif, 0))
opt->flags |= DHOPT_TAGOK;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if (context_tags)
{
struct dhcp_netid *last_tag;
for (last_tag = context_tags; last_tag->next; last_tag = last_tag->next);
last_tag->next = tags;
tagif = run_tag_if(context_tags);
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
}
}
/* now flag untagged options which are not overridden by tagged ones */
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;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
else if (!tmp->netid)
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
return tagif;
}
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
{
struct dhcp_netid *tmp1;
if (!check && !tagnotneeded)
return 0;
for (; check; check = check->next)
{
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp(check->net, tmp1->net) == 0)
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp((check->net)+1, tmp1->net) == 0)
return 0;
}
return 1;
}
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
if (!dot)
return NULL;
*dot = 0; /* truncate */
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
void log_tags(struct dhcp_netid *netid, u32 xid)
{
if (netid && option_bool(OPT_LOG_OPTS))
{
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
struct dhcp_netid *n;
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
if (netid->next)
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
}
}
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), xid, s);
}
}
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
{
int i;
if (o->len > len)
return 0;
if (o->len == 0)
return 1;
if (o->flags & DHOPT_HEX)
{
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
return 1;
}
else
for (i = 0; i <= (len - o->len); )
{
if (memcmp(o->val, p + i, o->len) == 0)
return 1;
if (o->flags & DHOPT_STRING)
i++;
else
i += o->len;
}
return 0;
}
void check_dhcp_hosts(int fatal)
{
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop.
Also check that FQDNs match the domain we are using. */
struct dhcp_config *configs, *cp;
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
{
char *domain;
if ((configs->flags & DHOPT_BANK) || fatal)
{
for (cp = configs->next; cp; cp = cp->next)
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
{
if (fatal)
die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF);
else
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR;
}
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
configs->domain = domain;
}
}
}
void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches.
We take care to maintain the invariant that any IP address can appear
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
restore the status-quo ante first. */
struct dhcp_config *config;
struct crec *crec;
int prot = AF_INET;
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_ADDR_HOSTS)
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
#ifdef HAVE_DHCP6
again:
#endif
if (daemon->port != 0)
for (config = configs; config; config = config->next)
{
int conflags = CONFIG_ADDR;
int cacheflags = F_IPV4;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
{
conflags = CONFIG_ADDR6;
cacheflags = F_IPV6;
}
#endif
if (!(config->flags & conflags) &&
(config->flags & CONFIG_NAME) &&
(crec = cache_find_by_name(NULL, config->hostname, 0, cacheflags)) &&
(crec->flags & F_HOSTS))
{
if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
{
/* use primary (first) address */
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
if (!crec)
continue; /* should be never */
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, daemon->addrbuff);
}
if (prot == AF_INET && !config_find_by_address(configs, crec->addr.addr.addr.addr4))
{
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
continue;
}
#ifdef HAVE_DHCP6
if (prot == AF_INET6 && !config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 129, 0))
{
memcpy(config->hwaddr, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
continue;
}
#endif
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
daemon->addrbuff, config->hostname);
}
}
#ifdef HAVE_DHCP6
if (prot == AF_INET)
{
prot = AF_INET6;
goto again;
}
#endif
}
#endif
+1 -176
View File
@@ -119,43 +119,6 @@ void dhcp_init(void)
#endif
check_dhcp_hosts(1);
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
}
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
{
ssize_t sz;
while (1)
{
msg->msg_flags = 0;
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
if (sz == -1)
return -1;
if (!(msg->msg_flags & MSG_TRUNC))
break;
/* Very new Linux kernels return the actual size needed,
older ones always return truncated size */
if ((size_t)sz == daemon->dhcp_packet.iov_len)
{
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
return -1;
}
else
{
expand_buf(&daemon->dhcp_packet, sz);
break;
}
}
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
}
void dhcp_packet(time_t now, int pxe_fd)
@@ -611,50 +574,6 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
return NULL;
}
/* Is every member of check matched by a member of pool?
If tagnotneeded, untagged is OK */
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int tagnotneeded)
{
struct dhcp_netid *tmp1;
if (!check && !tagnotneeded)
return 0;
for (; check; check = check->next)
{
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp(check->net, tmp1->net) == 0)
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (strcmp((check->net)+1, tmp1->net) == 0)
return 0;
}
return 1;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
{
struct tag_if *exprs;
struct dhcp_netid_list *list;
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid(exprs->tag, tags, 1))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
tags = list->list;
}
return tags;
}
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now)
@@ -850,7 +769,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
is_addr_in_context(context, config))
return config;
/* use match with fewest wildcast octets */
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
@@ -1027,85 +946,6 @@ void dhcp_read_ethers(void)
my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
}
void check_dhcp_hosts(int fatal)
{
/* If the same IP appears in more than one host config, then DISCOVER
for one of the hosts will get the address, but REQUEST will be NAKed,
since the address is reserved by the other one -> protocol loop.
Also check that FQDNs match the domain we are using. */
struct dhcp_config *configs, *cp;
for (configs = daemon->dhcp_conf; configs; configs = configs->next)
{
char *domain;
if ((configs->flags & DHOPT_BANK) || fatal)
{
for (cp = configs->next; cp; cp = cp->next)
if ((configs->flags & cp->flags & CONFIG_ADDR) && configs->addr.s_addr == cp->addr.s_addr)
{
if (fatal)
die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF);
else
my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR;
}
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
configs->domain = domain;
}
}
}
void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
records which don't have an address and whose name matches.
We take care to maintain the invariant that any IP address can appear
in at most one dhcp-host. Since /etc/hosts can be re-read by SIGHUP,
restore the status-quo ante first. */
struct dhcp_config *config;
struct crec *crec;
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_ADDR_HOSTS)
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
if (daemon->port != 0)
for (config = configs; config; config = config->next)
if (!(config->flags & CONFIG_ADDR) &&
(config->flags & CONFIG_NAME) &&
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
{
if (cache_find_by_name(crec, config->hostname, 0, F_IPV4))
{
/* use primary (first) address */
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
if (!crec)
continue; /* should be never */
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
}
if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
else
{
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
}
}
}
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
for this address. If it has a domain part, that must match the set domain and
@@ -1146,20 +986,5 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
/* return domain or NULL if none. */
char *strip_hostname(char *hostname)
{
char *dot = strchr(hostname, '.');
if (!dot)
return NULL;
*dot = 0; /* truncate */
if (strlen(dot+1) != 0)
return dot+1;
return NULL;
}
#endif
+330 -32
View File
@@ -23,27 +23,39 @@ struct iface_param {
int ind;
};
struct listen_param {
int fd_or_iface;
struct listen_param *next;
};
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam);
int scope, int if_index, int dad, void *vparam);
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam);
int scope, int if_index, int dad, void *vparam);
static int make_duid1(unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void)
{
int fd;
struct sockaddr_in6 saddr;
struct listen_param *listenp, listen;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) ||
!set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
memset(&saddr, 0, sizeof(saddr));
#ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin6_len = sizeof(addr.in6);
saddr.sin6_len = sizeof(struct sockaddr_in6);
#endif
saddr.sin6_family = AF_INET6;
saddr.sin6_addr = in6addr_any;
@@ -53,29 +65,44 @@ void dhcp6_init(void)
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
/* join multicast groups on each interface we're interested in */
if (!iface_enumerate(AF_INET6, &fd, join_multicast))
listen.fd_or_iface = fd;
listen.next = NULL;
if (!iface_enumerate(AF_INET6, &listen, join_multicast))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
for (listenp = listen.next; listenp; )
{
struct listen_param *tmp = listenp->next;
free(listenp);
listenp = tmp;
}
daemon->dhcp6fd = fd;
}
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam)
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
struct in6_addr maddr;
int fd = *((int *)vparam);
struct listen_param *listenp, *param = vparam;
int fd = param->fd_or_iface;
struct dhcp_context *context;
struct iname *tmp;
(void)prefix;
(void)scope; /* warnings */
(void)scope;
(void)dad;
/* record which interfaces we join on, so
that we do it at most one per interface, even when they
have multiple addresses */
for (listenp = param->next; listenp; listenp = listenp->next)
if (if_index == listenp->fd_or_iface)
return 1;
if (!indextoname(fd, if_index, ifrn_name))
return 0;
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
@@ -85,7 +112,7 @@ static int join_multicast(struct in6_addr *local, int prefix,
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
@@ -93,23 +120,25 @@ static int join_multicast(struct in6_addr *local, int prefix,
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &maddr);
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &maddr);
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
listenp = whine_malloc(sizeof(struct listen_param));
listenp->fd_or_iface = if_index;
listenp->next = param->next;
param->next = listenp;
return 1;
}
void dhcp6_packet(time_t now)
{
struct dhcp_context *context;
@@ -135,7 +164,7 @@ void dhcp6_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4)
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1 || sz <= 4)
return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
@@ -153,7 +182,7 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
ls -l
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
return;
@@ -162,15 +191,15 @@ ls -l
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
break;
if (!context)
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
context->current = context;
parm.current = NULL;
@@ -182,26 +211,31 @@ ls -l
lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet;
sz = dhcp6_reply(parm.current, sz);
/* ifr.ifr_name, if_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, sz, IN6_IS_ADDR_MULTICAST(&from.in6.sin6_addr), now);
lease_update_file(now);
lease_update_dns();
if (sz != 0)
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, sz, &from, &dest, if_index);
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, sz, 0, (struct sockaddr *)&from, sizeof(from)) &&
retry_send());
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam)
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
(void)scope; /* warning */
(void)dad;
for (context = daemon->dhcp6; context; context = context->next)
{
if ((context->flags & CONTEXT_IPV6) &&
prefix == context->prefix &&
if (prefix == context->prefix &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local) &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -210,11 +244,275 @@ static int complete_context6(struct in6_addr *local, int prefix,
{
context->current = param->current;
param->current = context;
context->local6 = *local;
}
}
}
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
{
struct dhcp_config *config;
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_ADDR6) &&
is_same_net6(&config->addr6, net, prefix) &&
(prefix == 128 || addr6part(&config->addr6) == addr))
return config;
return NULL;
}
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
Try to return from contexts which match netids first.
Note that we assume the address prefix lengths are 64 or greater, so we can
get by with 64 bit arithmetic.
*/
u64 start, addr;
struct dhcp_context *c, *d;
int i, pass;
u64 j;
/* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids! */
for (j = 0, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
continue;
else if (!match_netid(c->filter, netids, pass))
continue;
else
{
if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */
addr = start;
do {
/* eliminate addresses in use by the server. */
for (d = context; d; d = d->current)
if (addr == addr6part(&d->router6))
break;
if (!d &&
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
{
*ans = c->start6;
setaddr6part (ans, addr);
return 1;
}
addr++;
if (addr == addr6part(&c->end6) + 1)
addr = addr6part(&c->start6);
} while (addr != start);
}
return 0;
}
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
u64 start, end, addr = addr6part(taddr);
struct dhcp_context *tmp;
for (tmp = context; tmp; tmp = tmp->current)
{
start = addr6part(&tmp->start6);
end = addr6part(&tmp->end6);
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
is_same_net6(&context->start6, taddr, context->prefix) &&
is_same_net6(&context->end6, taddr, context->prefix) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, 1))
return tmp;
}
return NULL;
}
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
if (!(tmp = address6_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
!(tmp->flags & CONTEXT_PROXY))
break;
}
/* Only one context allowed now */
if (tmp)
tmp->current = NULL;
return tmp;
}
static int is_addr_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR6))
return 1;
for (; context; context = context->current)
if (is_same_net6(&config->addr6, &context->start6, context->prefix))
return 1;
return 0;
}
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname)
{
int count, new;
struct dhcp_config *config;
struct hwaddr_config *conf_addr;
unsigned char *hwaddr = NULL;
int duid_type, hw_len = 0, hw_type = 0;
if (duid)
{
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == duid_len &&
memcmp(config->clid, duid, duid_len) == 0 &&
is_addr_in_context6(context, config))
return config;
}
/* DHCPv6 doesn't deal in MAC addresses per-se, but some DUIDs do include
MAC addresses, so we try and parse them out here. Not that there is only one
DUID per host and it's created using any one of the MACs, so this is no
good no good for multihomed hosts. */
hwaddr = duid;
GETSHORT(duid_type, hwaddr);
if (duid_type == 1 || duid_type == 3)
{
GETSHORT(hw_type, hwaddr);
if (duid_type == 1)
hwaddr += 4; /* skip time */
hw_len = duid_len - 8;
}
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context6(context, config))
return config;
}
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context6(context, config))
return config;
/* use match with fewest wildcard octets */
if (hwaddr)
{
struct dhcp_config *candidate;
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context6(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
return NULL;
}
void make_duid(time_t now)
{
/* rebase epoch to 1/1/2000 */
time_t newnow = now - 946684800;
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
if(!daemon->duid)
die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
}
static int make_duid1(unsigned int type, char *mac, size_t maclen, void *parm)
{
/* create DUID as specified in RFC3315. We use the MAC of the
first interface we find that isn't loopback or P-to-P */
unsigned char *p;
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
#ifdef HAVE_BROKEN_RTC
PUTSHORT(3, p); /* DUID_LL */
#else
PUTSHORT(1, p); /* DUID_LLT */
#endif
PUTSHORT(type, p); /* address type */
#ifndef HAVE_BROKEN_RTC
PUTLONG(*((time_t *)parm), p); /* time */
#endif
memcpy(p, mac, maclen);
return 0;
}
#endif
+12
View File
@@ -53,3 +53,15 @@
#define OPTION6_INTERFACE_ID 18
#define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1
#define DHCP6NOADDRS 2
#define DHCP6NOBINDING 3
#define DHCP6NOTONLINK 4
#define DHCP6USEMULTI 5
+74 -14
View File
@@ -87,15 +87,24 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP
if (!daemon->lease_file)
{
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
daemon->lease_file = LEASEFILE;
}
#endif
/* Close any file descriptors we inherited apart from std{in|out|err} */
/* Close any file descriptors we inherited apart from std{in|out|err}
Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
otherwise file descriptors we create can end up being 0, 1, or 2
and then get accidentally closed later when we make 0, 1, and 2
open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
but it's not guaranteed. By opening /dev/null three times, we
ensure that we're not using those fds for real stuff. */
for (i = 0; i < max_fd; i++)
if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
close(i);
else
open("/dev/null", O_RDWR);
#ifdef HAVE_LINUX_NETWORK
netlink_init();
@@ -137,13 +146,20 @@ int main (int argc, char **argv)
now = dnsmasq_time();
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. */
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now);
dhcp_init();
if (daemon->dhcp)
dhcp_init();
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
dhcp6_init();
#endif
}
#endif
@@ -189,7 +205,7 @@ int main (int argc, char **argv)
#if defined(HAVE_SCRIPT)
/* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->scriptuser &&
if ((daemon->dhcp || daemon->dhcp6) && daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript))
{
if ((ent_pw = getpwnam(daemon->scriptuser)))
@@ -341,7 +357,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifdef HAVE_SCRIPT
if (daemon->dhcp && (daemon->lease_change_command || daemon->luascript))
if ((daemon->dhcp || daemon->dhcp6) && (daemon->lease_change_command || daemon->luascript))
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -481,25 +497,53 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
struct dhcp_context *dhcp_tmp;
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
int family = AF_INET;
dhcp_tmp = daemon->dhcp;
#ifdef HAVE_DHCP6
again:
#endif
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6;
}
#endif
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"),
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->dhcp_buff2);
}
#ifdef HAVE_DHCP6
if (family == AF_INET)
{
family = AF_INET6;
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
}
#endif
#ifdef HAVE_TFTP
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
{
@@ -604,6 +648,14 @@ int main (int argc, char **argv)
}
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
}
#endif
#ifdef HAVE_LINUX_NETWORK
FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd);
@@ -699,6 +751,14 @@ int main (int argc, char **argv)
dhcp_packet(now, 1);
}
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
if (FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
}
#endif
# ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write();
@@ -860,7 +920,7 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
lease_prune(NULL, now);
lease_update_file(now);
@@ -1018,7 +1078,7 @@ void clear_cache_and_reload(time_t now)
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp)
if (daemon->dhcp || daemon->dhcp6)
{
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();
+84 -27
View File
@@ -54,6 +54,7 @@
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#include "dns_protocol.h"
#include "dhcp_protocol.h"
@@ -435,28 +436,30 @@ struct frec {
#define ACTION_OLD 3
#define ACTION_ADD 4
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
#define LEASE_AUX_CHANGED 4 /* CLID or expiry changed */
#define LEASE_AUTH_NAME 8 /* hostname came from config, not from client */
#define LEASE_USED 16 /* used this DHCPv6 transaction */
#define LEASE_NA 32 /* IPv6 no-temporary lease */
#define LEASE_TA 64 /* IPv6 temporary lease */
struct dhcp_lease {
int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */
char *hostname, *fqdn; /* name from client-hostname option or config */
char *old_hostname; /* hostname before it moved to another lease */
char auth_name; /* hostname came from config, not from client */
char new; /* newly created */
char changed; /* modified */
char aux_changed; /* CLID or expiry changed */
int flags;
time_t expires; /* lease expiry */
#ifdef HAVE_BROKEN_RTC
unsigned int length;
#endif
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
struct in_addr addr, override, giaddr;
unsigned char *extradata;
unsigned int extradata_len, extradata_size;
int last_interface;
#ifdef HAVE_DHCP6
char is_ipv6;
#endif
struct dhcp_lease *next;
};
@@ -489,6 +492,9 @@ struct dhcp_config {
unsigned char *clid; /* clientid */
char *hostname, *domain;
struct dhcp_netid_list *netid;
#ifdef HAVE_DHCP6
struct in6_addr addr6;
#endif
struct in_addr addr;
time_t decline_time;
unsigned int lease_time;
@@ -496,6 +502,8 @@ struct dhcp_config {
struct dhcp_config *next;
};
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define CONFIG_DISABLE 1
#define CONFIG_CLID 2
#define CONFIG_TIME 8
@@ -506,6 +514,7 @@ struct dhcp_config {
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
#define CONFIG_DECLINED 1024 /* address declined by client */
#define CONFIG_BANK 2048 /* from dhcp hosts file */
#define CONFIG_ADDR6 4096
struct dhcp_opt {
int opt, len, flags;
@@ -532,6 +541,7 @@ struct dhcp_opt {
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192
struct dhcp_boot {
char *file, *sname, *tftp_sname;
@@ -542,7 +552,7 @@ struct dhcp_boot {
struct pxe_service {
unsigned short CSA, type;
char *menu, *basename;
char *menu, *basename, *sname;
struct in_addr server;
struct dhcp_netid *netid;
struct pxe_service *next;
@@ -556,7 +566,8 @@ struct pxe_service {
/* vendorclass, userclass, remote-id or cicuit-id */
struct dhcp_vendor {
int len, match_type, option;
int len, match_type;
unsigned int enterprise;
char *data;
struct dhcp_netid netid;
struct dhcp_vendor *next;
@@ -578,6 +589,10 @@ struct dhcp_bridge {
struct cond_domain {
char *domain;
struct in_addr start, end;
#ifdef HAVE_IPV6
struct in6_addr start6, end6;
#endif
int is6;
struct cond_domain *next;
};
@@ -588,6 +603,7 @@ struct dhcp_context {
struct in_addr start, end; /* range of available addresses */
#ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6, router6;
int prefix;
#endif
int flags;
@@ -600,7 +616,6 @@ struct dhcp_context {
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
#define CONTEXT_IPV6 16
struct ping_result {
struct in_addr addr;
@@ -681,7 +696,7 @@ extern struct daemon {
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config;
@@ -771,12 +786,15 @@ void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_add_dhcp_entry(char *host_name, int prot, struct all_addr *host_address, time_t ttd);
struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
/* rfc1035.c */
unsigned int extract_request(struct dns_header *header, size_t qlen,
@@ -814,6 +832,8 @@ time_t dnsmasq_time(void);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
u64 addr6part(struct in6_addr *addr);
void setaddr6part(struct in6_addr *addr, u64 host);
#endif
int retry_send(void);
void prettyprint_time(char *buf, unsigned int t);
@@ -838,7 +858,8 @@ void flush_log(void);
/* option.c */
void read_opts (int argc, char **argv, char *compile_opts);
char *option_string(unsigned char opt, int *is_ip, int *is_name);
char *option_string(int prot, unsigned int opt, unsigned char *val,
int opt_len, char *buf, int buf_len);
void reread_dhcp(void);
void set_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list);
@@ -876,31 +897,24 @@ int set_ipv6pktinfo(int fd);
#ifdef HAVE_DHCP
void dhcp_init(void);
void dhcp_packet(time_t now, int pxe_fd);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr,
struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now);
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname);
void dhcp_update_configs(struct dhcp_config *configs);
void dhcp_read_ethers(void);
void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
#endif
/* lease.c */
@@ -908,13 +922,17 @@ char *get_domain(struct in_addr addr);
void lease_update_file(time_t now);
void lease_update_dns();
void lease_init(time_t now);
struct dhcp_lease *lease_allocate4(struct in_addr addr);
struct dhcp_lease *lease4_allocate(struct in_addr addr);
#ifdef HAVE_DHCP6
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp);
struct dhcp_lease *lease6_allocate(struct in6_addr *addrp, int lease_type);
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr);
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr);
u64 lease_find_max_addr6(struct dhcp_context *context);
#endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -925,6 +943,10 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim);
#endif
#endif
/* rfc2131.c */
@@ -991,8 +1013,43 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
int istcp, unsigned int *markp);
#endif
/* dhcp6.c */
#ifdef HAVE_DHCP6
void dhcp6_init(void);
void dhcp6_packet(time_t now);
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans);
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname);
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
int prefix, u64 addr);
void make_duid(time_t now);
#endif
/* rfc3315.c */
#ifdef HAVE_DHCP6
void make_duid(time_t now);
size_t dhcp6_reply(struct dhcp_context *context, size_t sz);
size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name, size_t sz, int is_multicast, time_t now);
#endif
/* dhcp-common.c */
#ifdef HAVE_DHCP
void dhcp_common_init(void);
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
struct dhcp_netid *run_tag_if(struct dhcp_netid *input);
struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *context_tags,
struct dhcp_opt *opts);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
char *strip_hostname(char *hostname);
void log_tags(struct dhcp_netid *netid, u32 xid);
int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
void dhcp_update_configs(struct dhcp_config *configs);
void check_dhcp_hosts(int fatal);
#endif
+144 -39
View File
@@ -46,8 +46,9 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
struct script_data
{
unsigned char action, hwaddr_len, hwaddr_type;
unsigned char clid_len, hostname_len, ed_len;
int flags;
int action, hwaddr_len, hwaddr_type;
int clid_len, hostname_len, ed_len;
struct in_addr addr, giaddr;
unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC
@@ -57,6 +58,7 @@ struct script_data
#endif
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
};
static struct script_data *buf = NULL;
@@ -173,7 +175,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *p, *action_str, *hostname = NULL, *domain = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *extradata, *alloc_buff = NULL;
int err = 0;
int is6, err = 0;
free(alloc_buff);
@@ -199,17 +201,34 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
action_str = "old";
else
continue;
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
if (!is6)
{
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{
p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
}
#ifdef HAVE_DHCP6
else
{
/* duid not MAC for IPv6 */
for (p = daemon->dhcp_buff, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
}
#endif
/* expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC
@@ -228,12 +247,26 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
/* CLID into packet */
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
if (!is6)
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
}
#ifdef HAVE_DHCP6
else
{
p += sprintf(p, "%.2x", buf[i]);
if (i != data.clid_len - 1)
p += sprintf(p, ":");
/* or IAID and server DUID for IPv6 */
sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
for (p = daemon->packet, i = 0; i < daemon->duid_len; i++)
{
p += sprintf(p, "%.2x", daemon->duid[i]);
if (i != daemon->duid_len - 1)
p += sprintf(p, ":");
}
}
#endif
buf += data.clid_len;
@@ -253,14 +286,29 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
extradata = buf + data.hostname_len;
if (!is6)
inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_DHCP6
else
inet_ntop(AF_INET6, &data.hwaddr, daemon->addrbuff, ADDRSTRLEN);
#endif
#ifdef HAVE_LUASCRIPT
if (daemon->luascript)
{
lua_getglobal(lua, "lease"); /* function to call */
lua_pushstring(lua, action_str); /* arg1 - action */
lua_newtable(lua); /* arg2 - data table */
if (data.clid_len != 0)
if (is6)
{
lua_pushstring(lua, daemon->packet);
lua_setfield(lua, -2, "duid");
lua_pushstring(lua, daemon->dhcp_buff3);
lua_setfield(lua, -2, "iaid");
}
if (!is6 && data.clid_len != 0)
{
lua_pushstring(lua, daemon->packet);
lua_setfield(lua, -2, "client_id");
@@ -294,20 +342,36 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
end = extradata + data.ed_len;
buf = extradata;
buf = grab_extradata_lua(buf, end, "vendor_class");
if (!is6)
buf = grab_extradata_lua(buf, end, "vendor_class");
#ifdef HAVE_DHCP6
else
for (i = 0; i < data.hwaddr_len; i++)
{
sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
#endif
buf = grab_extradata_lua(buf, end, "supplied_hostname");
buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial");
buf = grab_extradata_lua(buf, end, "cpewan_class");
if (!is6)
{
buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial");
buf = grab_extradata_lua(buf, end, "cpewan_class");
}
buf = grab_extradata_lua(buf, end, "tags");
for (i = 0; buf; i++)
{
sprintf(daemon->dhcp_buff2, "user_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
}
if (data.giaddr.s_addr != 0)
if (!is6 && data.giaddr.s_addr != 0)
{
lua_pushstring(lua, inet_ntoa(data.giaddr));
lua_setfield(lua, -2, "relay_address");
@@ -325,10 +389,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_setfield(lua, -2, "old_hostname");
}
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "mac_address");
lua_pushstring(lua, inet_ntoa(data.addr));
if (!is6)
{
lua_pushstring(lua, daemon->dhcp_buff);
lua_setfield(lua, -2, "mac_address");
}
lua_pushstring(lua, daemon->addrbuff);
lua_setfield(lua, -2, "ip_address");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
@@ -372,7 +439,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
continue;
}
if (data.clid_len != 0)
if (is6)
{
my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
my_setenv("DNSMASQ_DUID", daemon->packet, &err);
}
if (!is6 && data.clid_len != 0)
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
if (strlen(data.interface) != 0)
@@ -389,12 +462,37 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
end = extradata + data.ed_len;
buf = extradata;
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
if (!is6)
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
#ifdef HAVE_DHCP6
else
{
if (data.hwaddr_len != 0)
{
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
for (i = 0; i < data.hwaddr_len - 1; i++)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
}
}
}
#endif
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
if (!is6)
{
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
}
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
if (is6)
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
for (i = 0; buf; i++)
{
@@ -402,7 +500,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
}
if (data.giaddr.s_addr != 0)
if (!is6 && data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
if (data.action != ACTION_DEL && data.remaining_time != 0)
@@ -427,7 +525,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
execl(daemon->lease_change_command,
p ? p+1 : daemon->lease_change_command,
action_str, daemon->dhcp_buff, inet_ntoa(data.addr), hostname, (char*)NULL);
action_str, daemon->dhcp_buff, daemon->addrbuff, hostname, (char*)NULL);
err = errno;
}
/* failed, send event so the main process logs the problem */
@@ -493,7 +591,13 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
unsigned char *p;
size_t size;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6
if (!daemon->dhcp)
fd = daemon->dhcp6fd;
#endif
/* no script */
if (daemon->helperfd == -1)
return;
@@ -524,6 +628,7 @@ 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;
buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len;
@@ -531,8 +636,8 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->hostname_len = hostname_len;
buf->addr = lease->addr;
buf->giaddr = lease->giaddr;
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface))
memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
if (!indextoname(fd, lease->last_interface, buf->interface))
buf->interface[0] = 0;
#ifdef HAVE_BROKEN_RTC
+259 -103
View File
@@ -28,18 +28,9 @@ void lease_init(time_t now)
struct dhcp_lease *lease;
int clid_len, hw_len, hw_type;
FILE *leasestream;
#ifdef HAVE_DHCP6
int v6pass = 0;
#endif
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->dhcp_buff3 = safe_malloc(256);
leases_left = daemon->dhcp_max;
if (option_bool(OPT_LEASE_RO))
{
/* run "<lease_change_script> init" once to get the
@@ -73,45 +64,70 @@ void lease_init(time_t now)
rewind(leasestream);
}
#ifdef HAVE_DHCP6
again:
#endif
/* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes */
if (leasestream)
while (fscanf(leasestream, "%lu %255s %64s %255s %764s",
&ei, daemon->dhcp_buff2, daemon->namebuff,
daemon->dhcp_buff, daemon->packet) == 5)
while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
{
#ifdef HAVE_DHCP6
if (!v6pass)
#endif
if (strcmp(daemon->dhcp_buff3, "duid") == 0)
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explict MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
daemon->duid = safe_malloc(daemon->duid_len);
memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
continue;
}
#endif
#ifdef HAVE_DHCP6
if (v6pass)
inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6);
else
#endif
inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4);
ei = atol(daemon->dhcp_buff3);
if (fscanf(leasestream, " %64s %255s %764s",
daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
break;
clid_len = 0;
if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
if (inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4) &&
(lease = lease4_allocate(addr.addr.addr4)))
{
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
/* For backwards compatibility, no explict MAC address type means ether. */
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain(lease->addr), NULL);
}
#ifdef HAVE_DHCP6
if (v6pass)
lease = lease_allocate6(&addr.addr.addr6);
else
else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
{
char *s = daemon->dhcp_buff2;
int lease_type = LEASE_NA;
if (s[0] == 'T')
{
lease_type = LEASE_TA;
s++;
}
hw_type = atoi(s);
if ((lease = lease6_allocate(&addr.addr.addr6, lease_type)))
{
lease_set_hwaddr(lease, NULL, (unsigned char *)daemon->packet, 0, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0, get_domain6((struct in6_addr *)lease->hwaddr), NULL);
}
}
#endif
lease = lease_allocate4(addr.addr.addr4);
else
break;
if (!lease)
die (_("too many stored leases"), NULL, EC_MISC);
@@ -126,37 +142,11 @@ void lease_init(time_t now)
even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei;
#endif
#ifdef HAVE_DHCP6
if (!v6pass)
#endif
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
if (strcmp(daemon->dhcp_buff, "*") != 0)
lease_set_hostname(lease, daemon->dhcp_buff, 0);
/* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */
lease->new = lease->changed = 0;
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED);
}
#ifdef HAVE_DHCP6
if (!v6pass)
{
if (fscanf(leasestream, "duid %255s", daemon->dhcp_buff) == 1)
{
daemon->duid_len = parse_hex(daemon->dhcp_buff, (unsigned char *)daemon->dhcp_buff, 130, NULL, NULL);
daemon->duid = safe_malloc(daemon->duid_len);
memcpy(daemon->duid, daemon->dhcp_buff, daemon->duid_len );
v6pass = 1;
goto again;
}
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (daemon->dhcp6)
make_duid(now);
}
#endif
#ifdef HAVE_SCRIPT
if (!daemon->lease_stream)
@@ -185,6 +175,16 @@ void lease_init(time_t now)
file_dirty = 0;
lease_prune(NULL, now);
dns_dirty = 1;
#ifdef HAVE_DHCP6
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
if (!daemon->duid && daemon->dhcp6)
{
file_dirty = 1;
make_duid(now);
}
#endif
}
void lease_update_from_configs(void)
@@ -194,17 +194,17 @@ void lease_update_from_configs(void)
struct dhcp_lease *lease;
struct dhcp_config *config;
char *name;
for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, 1);
lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, 1); /* updates auth flag only */
lease_set_hostname(lease, name, 1, get_domain(lease->addr), NULL); /* updates auth flag only */
}
static void ourprintf(int *errp, char *format, ...)
{
va_list ap;
@@ -232,7 +232,7 @@ void lease_update_file(time_t now)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
@@ -277,7 +277,7 @@ void lease_update_file(time_t now)
for (lease = leases; lease; lease = lease->next)
{
if (!lease->is_ipv6)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
#ifdef HAVE_BROKEN_RTC
@@ -288,7 +288,8 @@ void lease_update_file(time_t now)
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
ourprintf(&err, "* %s ", daemon->addrbuff);
ourprintf(&err, "%s%u %s ", (lease->flags & LEASE_TA) ? "T" : "",
lease->hwaddr_type, daemon->addrbuff);
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0)
@@ -341,11 +342,21 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next)
{
int prot = AF_INET;
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6;
#endif
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->fqdn, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->hostname, prot,
prot == AF_INET ? (struct all_addr *)&lease->addr : (struct all_addr *)&lease->hwaddr,
lease->expires);
}
dns_dirty = 0;
@@ -389,7 +400,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (lease->clid && clid_len == lease->clid_len &&
@@ -400,7 +411,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if ((!lease->clid || !clid) &&
@@ -421,7 +432,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (lease->addr.s_addr == addr.s_addr)
@@ -431,6 +442,84 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
return NULL;
}
#ifdef HAVE_DHCP6
/* addr or clid may be NULL for "don't care, both NULL resets "USED" flags both
set activates USED check */
struct dhcp_lease *lease6_find(unsigned char *clid, int clid_len,
int lease_type, int iaid, struct in6_addr *addr)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
if (!(lease->flags & lease_type) || lease->hwaddr_type != iaid)
continue;
if (clid && addr && (lease->flags & LEASE_USED))
continue;
if (addr && memcmp(lease->hwaddr, addr, IN6ADDRSZ) != 0)
continue;
if (clid &&
(clid_len != lease->clid_len ||
memcmp(clid, lease->clid, clid_len) != 0))
continue;
if (clid || addr)
{
lease->flags |= LEASE_USED;
return lease;
}
else
lease->flags &= ~LEASE_USED;
}
return NULL;
}
struct dhcp_lease *lease6_find_by_addr(struct in6_addr *net, int prefix, u64 addr)
{
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
{
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
if (is_same_net6((struct in6_addr *)lease->hwaddr, net, prefix) &&
(prefix == 128 || addr6part((struct in6_addr *)lease->hwaddr) == addr))
return lease;
}
return NULL;
}
/* Find largest assigned address in context */
u64 lease_find_max_addr6(struct dhcp_context *context)
{
struct dhcp_lease *lease;
u64 addr = addr6part(&context->start6);
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue;
#endif
if (is_same_net6((struct in6_addr *)lease->hwaddr, &context->start6, 64) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr6part(&context->start6) &&
addr6part((struct in6_addr *)lease->hwaddr) <= addr6part(&context->end6) &&
addr6part((struct in6_addr *)lease->hwaddr) > addr)
addr = addr6part((struct in6_addr *)lease->hwaddr);
}
return addr;
}
#endif
/* Find largest assigned address in context */
struct in_addr lease_find_max_addr(struct dhcp_context *context)
{
@@ -441,7 +530,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
for (lease = leases; lease; lease = lease->next)
{
#ifdef HAVE_DHCP6
if (lease->is_ipv6)
if (lease->flags & (LEASE_TA | LEASE_NA))
continue;
#endif
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
@@ -460,7 +549,7 @@ static struct dhcp_lease *lease_allocate(void)
return NULL;
memset(lease, 0, sizeof(struct dhcp_lease));
lease->new = 1;
lease->flags = LEASE_NEW;
lease->expires = 1;
#ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */
@@ -474,7 +563,7 @@ static struct dhcp_lease *lease_allocate(void)
return lease;
}
struct dhcp_lease *lease_allocate4(struct in_addr addr)
struct dhcp_lease *lease4_allocate(struct in_addr addr)
{
struct dhcp_lease *lease = lease_allocate();
lease->addr = addr;
@@ -484,11 +573,11 @@ struct dhcp_lease *lease_allocate4(struct in_addr addr)
}
#ifdef HAVE_DHCP6
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp)
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->is_ipv6 = 1;
lease->flags |= lease_type;
return lease;
}
@@ -509,7 +598,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty = 1;
lease->expires = exp;
#ifndef HAVE_BROKEN_RTC
lease->aux_changed = file_dirty = 1;
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
#endif
}
@@ -529,10 +619,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
{
memcpy(lease->hwaddr, hwaddr, hw_len);
if (hw_len != 0)
memcpy(lease->hwaddr, hwaddr, hw_len);
lease->hwaddr_len = hw_len;
lease->hwaddr_type = hw_type;
lease->changed = file_dirty = 1; /* run script on change */
lease->flags |= LEASE_CHANGED;
file_dirty = 1; /* run script on change */
}
/* only update clid when one is available, stops packets
@@ -545,14 +637,18 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
if (lease->clid_len != clid_len)
{
lease->aux_changed = file_dirty = 1;
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len)))
return;
}
else if (memcmp(lease->clid, clid, clid_len) != 0)
lease->aux_changed = file_dirty = 1;
{
lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
}
lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len);
}
@@ -568,7 +664,7 @@ static void kill_name(struct dhcp_lease *lease)
free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqulaified name here. */
unqualified name from it, free the unqualified name here. */
if (lease->fqdn)
{
@@ -581,14 +677,18 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth, char *domain, char *config_domain)
{
struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL;
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, name);
if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
return;
}
@@ -598,19 +698,21 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
/* If a machine turns up on a new net without dropping the old lease,
or two machines claim the same name, then we end up with two interfaces with
the same name. Check for that here and remove the name from the old lease.
Note that IPv6 leases are different. All the leases to the same DUID are
allowed the same name.
Don't allow a name from the client to override a name from dnsmasq config. */
if (name)
{
if ((new_name = whine_malloc(strlen(name) + 1)))
{
char *suffix = get_domain(lease->addr);
strcpy(new_name, name);
if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
if (domain && (new_fqdn = whine_malloc(strlen(new_name) + strlen(domain) + 2)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
strcat(new_fqdn, domain);
}
}
@@ -619,7 +721,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{
if (option_bool(OPT_DHCP_FQDN))
{
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn))
continue;
}
else
@@ -627,8 +729,22 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue;
}
if (lease_tmp->auth_name && !auth)
if (lease->flags & (LEASE_TA | LEASE_NA))
{
if (!(lease_tmp->flags & (LEASE_TA | LEASE_NA)))
continue;
/* another lease for the same DUID is OK for IPv6 */
if (lease->clid_len == lease_tmp->clid_len &&
lease->clid && lease_tmp->clid &&
memcmp(lease->clid, lease_tmp->clid, lease->clid_len) == 0)
continue;
}
else if (lease_tmp->flags & (LEASE_TA | LEASE_NA))
continue;
if ((lease_tmp->flags & LEASE_AUTH_NAME) && !auth)
{
free(new_name);
free(new_fqdn);
@@ -645,11 +761,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
lease->hostname = new_name;
lease->fqdn = new_fqdn;
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
file_dirty = 1;
dns_dirty = 1;
lease->changed = 1; /* run script on change */
lease->flags |= LEASE_CHANGED; /* run script on change */
}
void lease_set_interface(struct dhcp_lease *lease, int interface)
@@ -658,7 +776,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
return;
lease->last_interface = interface;
lease->changed = 1;
lease->flags |= LEASE_CHANGED;
}
void rerun_scripts(void)
@@ -666,7 +784,7 @@ void rerun_scripts(void)
struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next)
lease->changed = 1;
lease->flags |= LEASE_CHANGED;
}
/* deleted leases get transferred to the old_leases list.
@@ -732,18 +850,18 @@ int do_script_run(time_t now)
}
for (lease = leases; lease; lease = lease->next)
if (lease->new || lease->changed ||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
{
#ifdef HAVE_SCRIPT
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
queue_script((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
emit_dbus_signal((lease->flags & LEASE_NEW) ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname);
#endif
lease->new = lease->changed = lease->aux_changed = 0;
lease->flags &= ~(LEASE_NEW | LEASE_CHANGED | LEASE_AUX_CHANGED);
/* this is used for the "add" call, then junked, since they're not in the database */
free(lease->extradata);
@@ -755,6 +873,44 @@ int do_script_run(time_t now)
return 0; /* nothing to do */
}
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data, unsigned int len, int delim)
{
unsigned int i;
/* check for embeded NULLs */
for (i = 0; i < len; i++)
if (data[i] == 0)
{
len = i;
break;
}
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
{
size_t newsz = lease->extradata_len + len + 100;
unsigned char *new = whine_malloc(newsz);
if (!new)
return;
if (lease->extradata)
{
memcpy(new, lease->extradata, lease->extradata_len);
free(lease->extradata);
}
lease->extradata = new;
lease->extradata_size = newsz;
}
if (len != 0)
memcpy(lease->extradata + lease->extradata_len, data, len);
lease->extradata[lease->extradata_len + len] = delim;
lease->extradata_len += len + 1;
}
#endif
#endif
+4 -3
View File
@@ -230,8 +230,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
if (addrp)
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index,
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
return 0;
}
#endif
@@ -282,7 +282,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1);
}
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm)))
if (mac && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
!((*callback)((unsigned int)link->ifi_type, mac, maclen, parm)))
return 0;
}
#endif
+4 -3
View File
@@ -274,9 +274,10 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
{
union mysockaddr addr;
struct in_addr netmask; /* dummy */
(void)prefix; /* warning */
netmask.s_addr = 0;
(void)prefix; /* warning */
(void)scope; /* warning */
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -285,7 +286,7 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_addr = *local;
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = scope;
addr.in6.sin6_scope_id = if_index;
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
}
+545 -109
View File
@@ -363,15 +363,16 @@ static struct {
};
#ifdef HAVE_DHCP
#define OT_ADDR_LIST 0x80
#define OT_RFC1035_NAME 0x40
#define OT_INTERNAL 0x20
#define OT_NAME 0x10
#define OT_ADDR_LIST 0x8000
#define OT_RFC1035_NAME 0x4000
#define OT_INTERNAL 0x2000
#define OT_NAME 0x1000
#define OT_CSTRING 0x0800
static const struct {
static const struct opttab_t {
char *name;
unsigned char val, size;
u16 val, size;
} opttab[] = {
{ "netmask", 1, OT_ADDR_LIST },
{ "time-offset", 2, 4 },
@@ -422,7 +423,7 @@ static const struct {
{ "T1", 58, OT_INTERNAL },
{ "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 },
{ "client-id", 61,OT_INTERNAL },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
{ "nis+-server", 65, OT_ADDR_LIST },
{ "tftp-server", 66, OT_NAME },
@@ -447,21 +448,149 @@ static const struct {
{ NULL, 0, 0 }
};
char *option_string(unsigned char opt, int *is_ip, int *is_name)
{
int i;
#ifdef HAVE_DHCP6
static const struct opttab_t opttab6[] = {
{ "client-id", 1, OT_INTERNAL },
{ "server-id", 2, OT_INTERNAL },
{ "ia-na", 3, OT_INTERNAL },
{ "ia-ta", 4, OT_INTERNAL },
{ "iaaddr", 5, OT_INTERNAL },
{ "oro", 6, OT_INTERNAL },
{ "preference", 7, OT_INTERNAL },
{ "unicast", 12, OT_INTERNAL },
{ "status-code", 13, OT_INTERNAL },
{ "rapid-commit", 14, OT_INTERNAL },
{ "user-class", 15, OT_INTERNAL | OT_CSTRING },
{ "vendor-class", 16, OT_INTERNAL | OT_CSTRING },
{ "vendor-opts", 17, OT_INTERNAL },
{ "sip-server-domain", 21, OT_RFC1035_NAME },
{ "sip-server", 22, OT_ADDR_LIST },
{ "dns-server", 23, OT_ADDR_LIST },
{ "domain-search", 24, OT_RFC1035_NAME },
{ "nis-server", 27, OT_ADDR_LIST },
{ "nis+-server", 28, OT_ADDR_LIST },
{ "nis-domain", 29, OT_RFC1035_NAME },
{ "nis+-domain", 30, OT_RFC1035_NAME },
{ "sntp-server", 31, OT_ADDR_LIST },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 }
};
#endif
for (i = 0; opttab[i].name; i++)
if (opttab[i].val == opt)
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
{
int o, i, j, nodecode = 0;
const struct opttab_t *ot = opttab;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
ot = opttab6;
#endif
for (o = 0; ot[o].name; o++)
if (ot[o].val == opt)
{
if (is_ip)
*is_ip = !!(opttab[i].size & OT_ADDR_LIST);
if (is_name)
*is_name = !!(opttab[i].size & OT_NAME);
return opttab[i].name;
if (buf)
{
memset(buf, 0, buf_len);
if (ot[o].size & OT_ADDR_LIST)
{
struct all_addr addr;
int addr_len = INADDRSZ;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
addr_len = IN6ADDRSZ;
#endif
for (buf[0]= 0, i = 0; i <= opt_len - addr_len; i += addr_len)
{
if (i != 0)
strncat(buf, ", ", buf_len - strlen(buf));
/* align */
memcpy(&addr, &val[i], addr_len);
inet_ntop(prot, &val[i], daemon->addrbuff, ADDRSTRLEN);
strncat(buf, daemon->addrbuff, buf_len - strlen(buf));
}
}
else if (ot[o].size & OT_NAME)
for (i = 0, j = 0; i < opt_len && j < buf_len ; i++)
{
char c = val[i];
if (isprint((int)c))
buf[j++] = c;
}
#ifdef HAVE_DHCP6
/* We don't handle compressed rfc1035 names, so no good in IPv4 land */
else if ((ot[o].size & OT_RFC1035_NAME) && prot == AF_INET6)
{
i = 0, j = 0;
while (i < opt_len && val[i] != 0)
{
int k, l = i + val[i] + 1;
for (k = i + 1; k < opt_len && k < l && j < buf_len ; k++)
{
char c = val[k];
if (isprint((int)c))
buf[j++] = c;
}
i = l;
if (val[i] != 0 && j < buf_len)
buf[j++] = '.';
}
}
else if ((ot[o].size & OT_CSTRING))
{
int k, len;
unsigned char *p;
i = 0, j = 0;
while (1)
{
p = &val[i];
GETSHORT(len, p);
for (k = 0; k < len && j < buf_len; k++)
{
char c = *p++;
if (isprint((int)c))
buf[j++] = c;
}
i += len +2;
if (i >= opt_len)
break;
if (j < buf_len)
buf[j++] = ',';
}
}
#endif
else
nodecode = 1;
}
break;
}
return NULL;
if (buf && (!ot[o].name || nodecode))
{
int trunc = 0;
if (opt_len > 13)
{
trunc = 1;
opt_len = 13;
}
print_mac(buf, val, opt_len);
if (trunc)
strncat(buf, "...", buf_len - strlen(buf));
}
return ot[o].name ? ot[o].name : "";
}
#endif
@@ -699,6 +828,19 @@ static void display_opts(void)
printf("%3d %s\n", opttab[i].val, opttab[i].name);
}
#ifdef HAVE_DHCP6
static void display_opts6(void)
{
int i;
printf(_("Known DHCPv6 options:\n"));
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL))
printf("%3d %s\n", opttab6[i].val, opttab6[i].name);
}
#endif
static int is_tag_prefix(char *arg)
{
if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
@@ -720,10 +862,11 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
struct dhcp_opt *new = opt_malloc(sizeof(struct dhcp_opt));
char lenchar = 0, *cp;
int i, addrs, digs, is_addr, is_hex, is_dec, is_string, dots;
int i, addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
char *comma = NULL, *problem = NULL;
struct dhcp_netid *np = NULL;
unsigned char opt_len = 0;
u16 opt_len = 0;
int is6 = 0;
new->len = 0;
new->flags = flags;
@@ -759,6 +902,32 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* option:<optname> must follow tag and vendor string. */
break;
}
#ifdef HAVE_DHCP6
else if (strstr(arg, "option6:") == arg)
{
for (cp = arg+8; *cp; cp++)
if (*cp < '0' || *cp > '9')
break;
if (!*cp)
{
new->opt = atoi(arg+8);
opt_len = 0;
}
else
for (i = 0; opttab6[i].name; i++)
if (!(opttab6[i].size & OT_INTERNAL) &&
strcasecmp(opttab6[i].name, arg+8) == 0)
{
new->opt = opttab6[i].val;
opt_len = opttab6[i].size;
break;
}
/* option6:<opt>|<optname> must follow tag and vendor string. */
is6 = 1;
break;
}
#endif
else if (strstr(arg, "vendor:") == arg)
{
new->u.vendor_class = (unsigned char *)opt_string_alloc(arg+7);
@@ -793,17 +962,36 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg = comma;
}
if (opt_len == 0 &&
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
for (i = 0; opttab[i].name; i++)
if (new->opt == opttab[i].val)
{
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
#ifdef HAVE_DHCP6
if (is6)
{
if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
problem = _("unsupported encapsulation for IPv6 option");
if (opt_len == 0 &&
!(new->flags & DHOPT_RFC3925))
for (i = 0; opttab6[i].name; i++)
if (new->opt == opttab6[i].val)
{
opt_len = opttab6[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
}
else
#endif
if (opt_len == 0 &&
!(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
for (i = 0; opttab[i].name; i++)
if (new->opt == opttab[i].val)
{
opt_len = opttab[i].size;
if (opt_len & OT_INTERNAL)
opt_len = 0;
break;
}
/* option may be missing with rfc3925 match */
if (new->opt == 0)
@@ -813,7 +1001,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
/* characterise the value */
char c;
int found_dig = 0;
is_addr = is_hex = is_dec = is_string = 1;
is_addr = is_addr6 = is_hex = is_dec = is_string = 1;
addrs = digs = 1;
dots = 0;
for (cp = comma; (c = *cp); cp++)
@@ -829,17 +1017,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
else if (c == '/')
{
is_dec = is_hex = 0;
is_addr6 = is_dec = is_hex = 0;
if (cp == comma) /* leading / means a pathname */
is_addr = 0;
}
else if (c == '.')
{
is_dec = is_hex = 0;
is_addr6 =is_dec = is_hex = 0;
dots++;
}
else if (c == '-')
is_hex = is_addr = 0;
is_hex = is_addr = is_addr6 = 0;
else if (c == ' ')
is_dec = is_hex = 0;
else if (!(c >='0' && c <= '9'))
@@ -856,25 +1044,33 @@ static char *parse_dhcp_opt(char *arg, int flags)
if (!((c >='A' && c <= 'F') ||
(c >='a' && c <= 'f') ||
(c == '*' && (flags & DHOPT_MATCH))))
is_hex = 0;
{
is_hex = 0;
if (c != '[' && c != ']')
is_addr6 = 0;
}
}
else
found_dig = 1;
if (!found_dig)
is_dec = is_addr = 0;
/* We know that some options take addresses */
if (opt_len & OT_ADDR_LIST)
{
is_string = is_dec = is_hex = 0;
if (!is_addr || dots == 0)
if (!is6 && (!is_addr || dots == 0))
problem = _("bad IP address");
if (is6 && !is_addr6)
problem = _("bad IPv6 address");
}
/* or names */
else if (opt_len & (OT_NAME | OT_RFC1035_NAME))
is_addr = is_dec = is_hex = 0;
else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
is_addr6 = is_addr = is_dec = is_hex = 0;
if (is_hex && digs > 1)
{
new->len = digs;
@@ -908,7 +1104,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
for (i=0; i<new->len; i++)
new->val[i] = val>>((new->len - i - 1)*8);
}
else if (is_addr)
else if (is_addr && !is6)
{
struct in_addr in;
unsigned char *op;
@@ -953,11 +1149,37 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
new->len = op - new->val;
}
else if (is_addr6 && is6)
{
unsigned char *op;
new->val = op = opt_malloc(16 * addrs);
new->flags |= DHOPT_ADDR6;
while (addrs--)
{
cp = comma;
comma = split(cp);
/* check for [1234::7] */
if (*cp == '[')
cp++;
if (strlen(cp) > 1 && cp[strlen(cp)-1] == ']')
cp[strlen(cp)-1] = 0;
if (inet_pton(AF_INET6, cp, op))
{
op += IN6ADDRSZ;
continue;
}
problem = _("bad IPv6 address");
}
new->len = op - new->val;
}
else if (is_string)
{
/* text arg */
/* text arg */
if ((new->opt == OPTION_DOMAIN_SEARCH || new->opt == OPTION_SIP_SERVER) &&
!(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
!is6 && !(new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
{
/* dns search, RFC 3397, or SIP, RFC 3361 */
unsigned char *q, *r, *tail;
@@ -1030,6 +1252,63 @@ static char *parse_dhcp_opt(char *arg, int flags)
new->len = (int) len + header_size;
new->val = m;
}
#ifdef HAVE_DHCP6
else if (comma && (opt_len & OT_CSTRING))
{
/* length fields are two bytes so need 16 bits for each string */
int commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
newp = opt_malloc(strlen(comma)+(2*commas));
p = newp;
arg = comma;
comma = split(arg);
while (arg && *arg)
{
u16 len = strlen(arg);
PUTSHORT(len, p);
memcpy(p, arg, len);
p += len;
arg = comma;
comma = split(arg);
}
new->val = newp;
new->len = p - newp;
}
else if (comma && (opt_len & OT_RFC1035_NAME))
{
int commas = 1;
unsigned char *p, *newp;
for(i = 0; comma[i]; i++)
if (comma[i] == ',')
commas++;
newp = opt_malloc(strlen(comma)+(2*commas));
p = newp;
arg = comma;
comma = split(arg);
while (arg && *arg)
{
p = do_rfc1035_name(p, arg);
*p++ = 0;
arg = comma;
comma = split(arg);
}
new->val = newp;
new->len = p - newp;
}
#endif
else
{
new->len = strlen(comma);
@@ -1040,9 +1319,10 @@ static char *parse_dhcp_opt(char *arg, int flags)
}
}
if ((new->len > 255) ||
if (!is6 &&
((new->len > 255) ||
(new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
(new->len > 250 && (new->flags & DHOPT_RFC3925)))
(new->len > 250 && (new->flags & DHOPT_RFC3925))))
problem = _("dhcp-option too long");
if (!problem)
@@ -1053,13 +1333,23 @@ static char *parse_dhcp_opt(char *arg, int flags)
!new->netid ||
new->netid->next)
problem = _("illegal dhcp-match");
else if (is6)
{
new->next = daemon->dhcp_match6;
daemon->dhcp_match6 = new;
}
else
{
new->next = daemon->dhcp_match;
daemon->dhcp_match = new;
}
}
else
else if (is6)
{
new->next = daemon->dhcp_opts6;
daemon->dhcp_opts6 = new;
}
else
{
new->next = daemon->dhcp_opts;
daemon->dhcp_opts = new;
@@ -1367,14 +1657,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
unhide_metas(comma);
if ((netpart = split_chr(comma, '/')))
{
int msize, mask;
int msize;
arg = split(netpart);
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
!atoi_check(netpart, &msize))
if (!atoi_check(netpart, &msize))
option = '?';
else
else if (inet_pton(AF_INET, comma, &new->start))
{
mask = (1 << (32 - msize)) - 1;
int mask = (1 << (32 - msize)) - 1;
new->is6 = 0;
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
new->end.s_addr = new->start.s_addr | htonl(mask);
if (arg)
@@ -1416,19 +1707,91 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
}
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, comma, &new->start6))
{
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);
if (msize < 64)
option = '?';
else if (arg)
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */
if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
option = '?';
else
{
struct server *serv = opt_malloc(sizeof(struct server));
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(73); /* strlen("32*<n.>ip6.arpa")+1 */
for (i = msize-1; i >= 0; i -= 4)
{
int dig = ((unsigned char *)&new->start6)[i>>3];
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
}
p += sprintf(p, "ip6.arpa");
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
serv->next = daemon->servers;
daemon->servers = serv;
}
}
}
#endif
else
option = '?';
}
else if ((arg = split(comma)))
else
{
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
(new->end.s_addr = inet_addr(arg)) == (in_addr_t)-1)
arg = split(comma);
if (inet_pton(AF_INET, comma, &new->start))
{
new->is6 = 0;
if (!arg)
new->end.s_addr = new->start.s_addr;
else if (!inet_pton(AF_INET, arg, &new->end))
option = '?';
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, comma, &new->start6))
{
new->is6 = 1;
if (!arg)
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
else if (!inet_pton(AF_INET6, arg, &new->end6))
option = '?';
}
#endif
else
option = '?';
}
else if ((new->start.s_addr = new->end.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
new->domain = d;
new->next = daemon->cond_domain;
daemon->cond_domain = new;
daemon->cond_domain = new;
}
else
daemon->domain_suffix = d;
@@ -1870,18 +2233,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
new->next = daemon->dhcp;
memset (new, 0, sizeof(*new));
new->lease_time = DEFLEASE;
new->addr_epoch = 0;
new->netmask.s_addr = 0;
new->broadcast.s_addr = 0;
new->router.s_addr = 0;
new->local.s_addr = 0;
new->netid.net = NULL;
new->filter = NULL;
new->flags = 0;
new->interface = NULL;
gen_prob = _("bad dhcp-range");
if (!arg)
@@ -1893,7 +2247,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
while(1)
{
for (cp = arg; *cp; cp++)
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
if (!(*cp == ' ' || *cp == '.' || *cp == ':' ||
(*cp >= 'a' && *cp <= 'f') || (*cp >= 'A' && *cp <= 'F') ||
(*cp >='0' && *cp <= '9')))
break;
if (*cp != ',' && (comma = split(arg)))
@@ -1929,44 +2285,87 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
if (!(a[k] = split(a[k-1])))
break;
if ((k < 2) || ((new->start.s_addr = inet_addr(a[0])) == (in_addr_t)-1))
if (k < 2)
option = '?';
else if (strcmp(a[1], "static") == 0)
else if (inet_pton(AF_INET, a[0], &new->start))
{
new->end = new->start;
new->flags |= CONTEXT_STATIC;
new->next = daemon->dhcp;
daemon->dhcp = new;
if (strcmp(a[1], "static") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_STATIC;
}
else if (strcmp(a[1], "proxy") == 0)
{
new->end = new->start;
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
{
struct in_addr tmp = new->start;
new->start = new->end;
new->end = tmp;
}
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_NETMASK;
leasepos = 3;
if (!is_same_net(new->start, new->end, new->netmask))
problem = _("inconsistent DHCP range");
}
if (k >= 4 && strchr(a[3], '.') &&
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
}
}
else if (strcmp(a[1], "proxy") == 0)
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, a[0], &new->start6))
{
new->end = new->start;
new->flags |= CONTEXT_PROXY;
}
else if ((new->end.s_addr = inet_addr(a[1])) == (in_addr_t)-1)
option = '?';
if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
{
struct in_addr tmp = new->start;
new->start = new->end;
new->end = tmp;
}
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_NETMASK;
leasepos = 3;
if (!is_same_net(new->start, new->end, new->netmask))
problem = _("inconsistent DHCP range");
}
daemon->dhcp = new;
if (k >= 4 && strchr(a[3], '.') &&
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
new->next = daemon->dhcp6;
new->prefix = 64; /* default */
daemon->dhcp6 = new;
if (strcmp(a[1], "static") == 0)
{
memcpy(&new->end6, &new->start6, IN6ADDRSZ);
new->flags |= CONTEXT_STATIC;
}
else if (!inet_pton(AF_INET6, a[1], &new->end6))
option = '?';
/* bare integer < 128 is prefix value */
if (option != '?' && k >= 3)
{
int pref;
for (cp = a[2]; *cp; cp++)
if (!(*cp >= '0' && *cp <= '9'))
break;
if (!*cp && (pref = atoi(a[2])) <= 128)
{
new->prefix = pref;
leasepos = 3;
if (new->prefix < 64)
problem = _("prefix must be at least 64");
}
}
if (!problem && !is_same_net6(&new->start6, &new->end6, new->prefix))
problem = _("inconsistent DHCPv6 range");
else if (addr6part(&new->start6) > addr6part(&new->end6))
{
struct in6_addr tmp = new->start6;
new->start6 = new->end6;
new->end6 = tmp;
}
}
#endif
if (k >= leasepos+1)
{
@@ -2074,6 +2473,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
else if (strstr(arg, "tag:") == arg)
problem = _("cannot match tags in --dhcp-host");
#ifdef HAVE_DHCP6
else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
{
arg[strlen(arg)-1] = 0;
arg++;
if (!inet_pton(AF_INET6, arg, &new->addr6))
problem = _("bad IPv6 address");
new->flags |= CONFIG_ADDR6;
}
#endif
else
{
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
@@ -2349,6 +2760,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
static int boottype = 32768;
new->netid = NULL;
new->sname = NULL;
new->server.s_addr = 0;
while (is_tag_prefix(arg))
@@ -2395,10 +2807,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
new->basename = opt_string_alloc(arg);
}
if (comma && (new->server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
option = '?';
if (comma)
{
if (!inet_pton(AF_INET, comma, &new->server))
{
new->server.s_addr = 0;
new->sname = opt_string_alloc(comma);
}
}
}
/* Order matters */
new->next = NULL;
if (!daemon->pxe_services)
@@ -2457,6 +2876,18 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
new->netid.net = opt_string_alloc(set_prefix(arg));
/* check for hex string - must digits may include : must not have nothing else,
only allowed for agent-options. */
arg = comma;
if ((comma = split(arg)))
{
if (option != 'U' || strstr(arg, "enterprise:") != arg)
option = '?';
else
new->enterprise = atoi(arg+11);
}
else
comma = arg;
for (p = (unsigned char *)comma; *p; p++)
if (isxdigit(*p))
dig = 1;
@@ -3303,12 +3734,17 @@ void read_opts(int argc, char **argv, char *compile_opts)
testmode = 1;
else if (option == 'w')
{
if (argc != 3 || strcmp(argv[2], "dhcp") != 0)
do_usage();
#ifdef HAVE_DHCP
else
if (argc == 3 && strcmp(argv[2], "dhcp") == 0)
display_opts();
#ifdef HAVE_DHCP6
else if (argc == 3 && strcmp(argv[2], "dhcp6") == 0)
display_opts6();
#endif
else
#endif
do_usage();
exit(0);
}
else if (option == 'v')
+45 -211
View File
@@ -18,16 +18,13 @@
#ifdef HAVE_DHCP
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
#ifdef HAVE_SCRIPT
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
#endif
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
static int sanitise(unsigned char *opt, char *buf);
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
static unsigned int calc_time(struct dhcp_context *context, struct dhcp_config *config, unsigned char *opt);
@@ -35,13 +32,11 @@ static void option_put(struct dhcp_packet *mess, unsigned char *end, int opt, in
static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt);
static struct in_addr option_addr_arr(unsigned char *opt, int offset);
static unsigned int option_uint(unsigned char *opt, int i, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid);
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
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 void do_options(struct dhcp_context *context,
@@ -49,7 +44,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *real_end,
unsigned char *req_options,
char *hostname,
char *domain, char *config_domain,
char *config_domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
@@ -63,7 +58,7 @@ static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
static int do_encap_opts(struct dhcp_opt *opts, int encap, int flag, struct dhcp_packet *mess, unsigned char *end, int null_term);
static void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local);
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now);
struct dhcp_boot *find_boot(struct dhcp_netid *netid);
@@ -468,7 +463,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if(&context->netid);
}
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
if (!message && !nailed)
{
@@ -481,7 +476,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!message &&
!lease &&
(!(lease = lease_allocate4(mess->yiaddr))))
(!(lease = lease4_allocate(mess->yiaddr))))
message = _("no leases left");
if (!message)
@@ -490,7 +485,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname)
lease_set_hostname(lease, hostname, 1);
lease_set_hostname(lease, hostname, 1, get_domain(lease->addr), domain);
/* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
@@ -499,7 +494,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now);
netid, subnet_addr, 0, 0, 0, NULL, 0, now);
}
}
@@ -799,7 +794,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
mess->yiaddr = mess->ciaddr;
mess->ciaddr.s_addr = 0;
if (service->server.s_addr != 0)
if (service->sname)
mess->siaddr = a_record_from_hosts(service->sname, now);
else if (service->server.s_addr != 0)
mess->siaddr = service->server;
else
mess->siaddr = context->local;
@@ -819,7 +816,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
return dhcp_packet_size(mess, agent_id, real_end);
}
@@ -868,10 +865,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid);
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local, now), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
}
}
@@ -1009,7 +1006,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if(&context->netid);
}
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
@@ -1025,7 +1022,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
}
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1189,7 +1186,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
else if (!lease)
{
if ((lease = lease_allocate4(mess->yiaddr)))
if ((lease = lease4_allocate(mess->yiaddr)))
do_classes = 1;
else
message = _("no leases left");
@@ -1223,7 +1220,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
tagif_netid = run_tag_if( &context->netid);
}
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
#ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command)
@@ -1233,7 +1230,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr;
lease->changed = 1;
lease->flags |= LEASE_CHANGED;
free(lease->extradata);
lease->extradata = NULL;
lease->extradata_size = lease->extradata_len = 0;
@@ -1256,7 +1253,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (strcmp(n->net, n1->net) == 0)
break;
if (!n1)
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
}
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
@@ -1266,7 +1263,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
/* If the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0)
ucp++, len--;
add_extradata_data(lease, ucp, len, 0);
lease_add_extradata(lease, ucp, len, 0);
}
}
#endif
@@ -1310,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
if (hostname)
lease_set_hostname(lease, hostname, hostname_auth);
lease_set_hostname(lease, hostname, hostname_auth, get_domain(lease->addr), domain);
lease_set_expires(lease, time, now);
lease_set_interface(lease, int_index);
@@ -1334,7 +1331,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
}
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1364,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (context && context->netid.net)
{
context->netid.next = netid;
tagif_netid = run_tag_if( &context->netid);
tagif_netid = run_tag_if(&context->netid);
}
log_tags(tagif_netid, mess);
log_tags(tagif_netid, ntohl(mess->xid));
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
@@ -1394,7 +1391,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
}
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
*is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end);
@@ -1403,37 +1400,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return 0;
}
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
{
int i;
if (o->len > len)
return 0;
if (o->len == 0)
return 1;
if (o->flags & DHOPT_HEX)
{
if (memcmp_masked(o->val, p, o->len, o->u.wildcard_mask))
return 1;
}
else
for (i = 0; i <= (len - o->len); )
{
if (memcmp(o->val, p + i, o->len) == 0)
return 1;
if (o->flags & DHOPT_STRING)
i++;
else
i += o->len;
}
return 0;
}
/* find a good value to use as MAC address for logging and address-allocation hashing.
This is normally just the chaddr field from the DHCP packet,
but eg Firewire will have hlen == 0 and use the client-id instead.
@@ -1519,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
}
#ifdef HAVE_SCRIPT
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim)
{
if ((lease->extradata_size - lease->extradata_len) < (len + 1))
{
size_t newsz = lease->extradata_len + len + 100;
unsigned char *new = whine_malloc(newsz);
if (!new)
return;
if (lease->extradata)
{
memcpy(new, lease->extradata, lease->extradata_len);
free(lease->extradata);
}
lease->extradata = new;
lease->extradata_size = newsz;
}
if (len != 0)
memcpy(lease->extradata + lease->extradata_len, data, len);
lease->extradata[lease->extradata_len + len] = delim;
lease->extradata_len += len + 1;
}
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
{
if (!opt)
add_extradata_data(lease, NULL, 0, 0);
lease_add_extradata(lease, NULL, 0, 0);
else
{
size_t i, len = option_len(opt);
unsigned char *ucp = option_ptr(opt, 0);
/* check for embeded NULLs */
for (i = 0; i < len; i++)
if (ucp[i] == 0)
{
len = i;
break;
}
add_extradata_data(lease, ucp, len, 0);
}
lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
}
#endif
@@ -1601,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
{
while (*start != OPTION_END)
{
int is_ip, is_name, i;
char *text = option_string(start[0], &is_ip, &is_name);
unsigned char trunc = option_len(start);
char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
if (is_ip)
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ)
{
if (i != 0)
strncat(daemon->namebuff, ", ", 256 - strlen(daemon->namebuff));
strncat(daemon->namebuff, inet_ntoa(option_addr_arr(start, i)), 256 - strlen(daemon->namebuff));
}
else if (!is_name || !sanitise(start, daemon->namebuff))
{
if (trunc > 13)
trunc = 13;
print_mac(daemon->namebuff, option_ptr(start, 0), trunc);
}
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d%s%s%s%s%s",
ntohl(xid), option_len(start), start[0],
text ? ":" : "", text ? text : "",
trunc == 0 ? "" : " ",
trunc == 0 ? "" : daemon->namebuff,
trunc == option_len(start) ? "" : "...");
my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
start += start[1] + 2;
}
}
@@ -1679,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
return NULL;
}
static struct in_addr option_addr_arr(unsigned char *opt, int offset)
static struct in_addr option_addr(unsigned char *opt)
{
/* this worries about unaligned data in the option. */
/* this worries about unaligned data in the option. */
/* struct in_addr is network byte order */
struct in_addr ret;
memcpy(&ret, option_ptr(opt, offset), INADDRSZ);
memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
return ret;
}
static struct in_addr option_addr(unsigned char *opt)
{
return option_addr_arr(opt, 0);
}
static unsigned int option_uint(unsigned char *opt, int offset, int size)
{
/* this worries about unaligned data and byte order */
@@ -1729,31 +1631,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
return NULL;
}
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
{
if (netid && option_bool(OPT_LOG_OPTS))
{
char *s = daemon->namebuff;
for (*s = 0; netid; netid = netid->next)
{
/* kill dupes. */
struct dhcp_netid *n;
for (n = netid->next; n; n = n->next)
if (strcmp(netid->net, n->net) == 0)
break;
if (!n)
{
strncat (s, netid->net, (MAXDNAME-1) - strlen(s));
if (netid->next)
strncat (s, ", ", (MAXDNAME-1) - strlen(s));
}
}
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
}
}
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
{
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
@@ -2048,7 +1925,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
return force;
}
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local)
static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct in_addr local, time_t now)
{
#define NUM_OPTS 4
@@ -2105,8 +1982,9 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct
return daemon->dhcp_opts;
}
boot_server = service->basename ? local : service->server;
boot_server = service->basename ? local :
(service->sname ? a_record_from_hosts(service->sname, now) : service->server);
if (boot_server.s_addr != 0)
{
if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
@@ -2197,7 +2075,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *end,
unsigned char *req_options,
char *hostname,
char *domain, char *config_domain,
char *domain,
struct dhcp_netid *netid,
struct in_addr subnet_addr,
unsigned char fqdn_flags,
@@ -2216,65 +2094,21 @@ static void do_options(struct dhcp_context *context,
struct dhcp_netid *tagif;
struct dhcp_netid_list *id_list;
/* flag options which are valid with the current tag set (sans context tags) */
tagif = run_tag_if(netid);
for (opt = config_opts; opt; opt = opt->next)
{
opt->flags &= ~DHOPT_TAGOK;
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
match_netid(opt->netid, tagif, 0))
opt->flags |= DHOPT_TAGOK;
}
/* now flag options which are valid, including the context tags,
otherwise valid options are inhibited if we found a higher priotity one above */
if (context && context->netid.net)
{
context->netid.next = netid;
tagif = run_tag_if(&context->netid);
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
match_netid(opt->netid, tagif, 0))
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
}
}
/* now flag untagged options which are not overridden by tagged ones */
for (opt = config_opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = config_opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
if (!tmp)
opt->flags |= DHOPT_TAGOK;
else if (!tmp->netid)
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif = option_filter(netid, &context->netid, config_opts);
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
/* logging */
if (option_bool(OPT_LOG_OPTS) && req_options)
{
char *q = daemon->namebuff;
for (i = 0; req_options[i] != OPTION_END; i++)
{
char *s = option_string(req_options[i], NULL, NULL);
char *s = option_string(AF_INET, req_options[i], NULL, 0, NULL, 0);
q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
"%d%s%s%s",
req_options[i],
s ? ":" : "",
s ? s : "",
strlen(s) != 0 ? ":" : "",
s,
req_options[i+1] == OPTION_END ? "" : ", ");
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
{
@@ -2511,8 +2345,8 @@ static void do_options(struct dhcp_context *context,
/* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,.......
Also hand vendor-identifying vendor-encapsulated options,
dhcp-option = rfc3925-encap:13,17,.......
Also handle vendor-identifying vendor-encapsulated options,
dhcp-option = vi-encap:13,17,.......
The may be more that one "outer" to do, so group
all the options which match each outer in turn. */
for (opt = config_opts; opt; opt = opt->next)
@@ -2579,7 +2413,7 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1)
{
pxe_misc(mess, end, uuid);
config_opts = pxe_opts(pxe_arch, tagif, context->local);
config_opts = pxe_opts(pxe_arch, tagif, context->local, now);
}
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
+1319 -156
View File
File diff suppressed because it is too large. Load diff
+23
View File
@@ -336,6 +336,29 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
return 0;
}
/* return least signigicant 64 bits if IPv6 address */
u64 addr6part(struct in6_addr *addr)
{
int i;
u64 ret = 0;
for (i = 8; i < 16; i++)
ret = (ret << 8) + addr->s6_addr[i];
return ret;
}
void setaddr6part(struct in6_addr *addr, u64 host)
{
int i;
for (i = 15; i >= 8; i--)
{
addr->s6_addr[i] = host;
host = host >> 8;
}
}
#endif