mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57f460de2f | ||
|
|
6caacacf6d | ||
|
|
60ac5af682 | ||
|
|
caa94380ac | ||
|
|
0793380b40 | ||
|
|
1adadf585d | ||
|
|
e5ffdb9c77 | ||
|
|
6da5201092 | ||
|
|
b36ae19434 | ||
|
|
2307eac613 | ||
|
|
127ea40ae7 | ||
|
|
6aef600d48 | ||
|
|
98d76a0326 | ||
|
|
6ea6dcf05b | ||
|
|
627797800d | ||
|
|
c6cc03ed0c | ||
|
|
3d7b550f52 | ||
|
|
751d6f4ae6 | ||
|
|
a5c72ab51d | ||
|
|
9bbc88762b | ||
|
|
ceae00dddf | ||
|
|
3634c54e8d | ||
|
|
d74942a03d | ||
|
|
70c5e3e076 | ||
|
|
4cb1b32009 | ||
|
|
3268e90f5e | ||
|
|
e98170816a | ||
|
|
52b92f4db8 | ||
|
|
be2daf4ad5 |
No files matched your search
@@ -37,6 +37,27 @@ version 2.60
|
||||
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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
Vendored
+8
-2
@@ -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.
|
||||
Vendored
+18
-10
@@ -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
|
||||
|
||||
+132
-40
@@ -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_SERVER_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).
|
||||
@@ -1058,8 +1115,43 @@ leases will be called with "del" and others with "old". When dnsmasq
|
||||
receives a HUP signal, the script will be invoked for existing leases
|
||||
with an "old " event.
|
||||
.TP
|
||||
.B --dhcp-luascript=<path>
|
||||
Specify a script written in Lua, to be run when leases are created,
|
||||
destroyed or changed. To use this option, dnsmasq must be compiled
|
||||
with the correct support. The Lua interpreter is intialised once, when
|
||||
dnsmasq starts, so that global variables persist between lease
|
||||
events. The Lua code must define a
|
||||
.B lease
|
||||
function, and may provide
|
||||
.B init
|
||||
and
|
||||
.B shutdown
|
||||
functions, which are called, without arguments when dnsmasq starts up
|
||||
and terminates.
|
||||
|
||||
The
|
||||
.B lease
|
||||
method receives the information detailed in
|
||||
.B --dhcp-script.
|
||||
It gets two arguments, firstly the action, which is a string
|
||||
containing, "add", "old" or "del", and secondly a table of tag value
|
||||
pairs. The tags mostly correspond to the environment variables
|
||||
detailed above, for instance the tag "domain" holds the same data as
|
||||
the environment variable DNSMASQ_DOMAIN. There are a few extra tags
|
||||
which hold the data supplied as arguments to
|
||||
.B --dhcp-script.
|
||||
These are
|
||||
.B mac_address, ip_address
|
||||
and
|
||||
.B hostname
|
||||
for IPv4, and
|
||||
.B client_duid, ip_address
|
||||
and
|
||||
.B hostname
|
||||
for IPv6.
|
||||
.TP
|
||||
.B --dhcp-scriptuser
|
||||
Specify the user as which to run the lease-change script. This defaults to root, but can be changed to another user using this flag.
|
||||
Specify the user as which to run the lease-change script or Lua script. This defaults to root, but can be changed to another user using this flag.
|
||||
.TP
|
||||
.B \-9, --leasefile-ro
|
||||
Completely suppress use of the lease database file. The file will not
|
||||
|
||||
+442
-406
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+51
-18
@@ -782,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)
|
||||
@@ -913,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)
|
||||
{
|
||||
@@ -953,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)
|
||||
@@ -969,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;
|
||||
}
|
||||
@@ -994,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;
|
||||
@@ -1010,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
-1
@@ -116,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 */
|
||||
|
||||
@@ -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 priority 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
@@ -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
|
||||
|
||||
+284
-32
@@ -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,229 @@ 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)
|
||||
{
|
||||
struct dhcp_config *config;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+64
-13
@@ -87,7 +87,7 @@ 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
|
||||
@@ -146,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
|
||||
|
||||
@@ -198,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)))
|
||||
@@ -350,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
|
||||
|
||||
@@ -490,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)
|
||||
{
|
||||
@@ -613,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);
|
||||
@@ -708,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();
|
||||
@@ -869,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);
|
||||
@@ -1027,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
@@ -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
|
||||
+152
-48
@@ -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,22 @@ 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, ":");
|
||||
}
|
||||
}
|
||||
|
||||
/* expiry or length into dhcp_buff2 */
|
||||
#ifdef HAVE_BROKEN_RTC
|
||||
@@ -228,12 +235,34 @@ 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, ":");
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
||||
buf += data.clid_len;
|
||||
|
||||
@@ -253,14 +282,31 @@ 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->dhcp_buff);
|
||||
lua_setfield(lua, -2, "client_duid");
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "server_duid");
|
||||
lua_pushstring(lua, daemon->dhcp_buff3);
|
||||
lua_setfield(lua, -2, "iaid");
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
{
|
||||
lua_pushstring(lua, daemon->packet);
|
||||
lua_setfield(lua, -2, "client_id");
|
||||
@@ -294,25 +340,43 @@ 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");
|
||||
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata_lua(buf, end, "relay_address");
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||
}
|
||||
|
||||
if (data.giaddr.s_addr != 0)
|
||||
{
|
||||
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||
lua_setfield(lua, -2, "relay_address");
|
||||
}
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
lua_pushnumber(lua, data.remaining_time);
|
||||
@@ -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_SERVER_DUID", daemon->packet, &err);
|
||||
}
|
||||
|
||||
if (!is6 && data.clid_len != 0)
|
||||
my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
|
||||
|
||||
if (strlen(data.interface) != 0)
|
||||
@@ -389,22 +462,46 @@ 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);
|
||||
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);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &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);
|
||||
|
||||
if (!is6)
|
||||
{
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
|
||||
}
|
||||
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
|
||||
|
||||
if (is6)
|
||||
buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
|
||||
else if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
|
||||
for (i = 0; buf; i++)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
|
||||
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
|
||||
}
|
||||
|
||||
if (data.giaddr.s_addr != 0)
|
||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||
|
||||
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||
{
|
||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||
@@ -427,7 +524,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 +590,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 +627,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 +635,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
|
||||
|
||||
+258
-103
@@ -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,83 @@ 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)
|
||||
{
|
||||
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
|
||||
continue;
|
||||
|
||||
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 +529,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 +548,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 +562,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 +572,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 +597,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 +618,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 +636,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 +663,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 +676,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 +697,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 +720,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 +728,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 +760,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 +775,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 +783,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 +849,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 +872,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
@@ -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
@@ -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
@@ -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')
|
||||
|
||||
+46
-211
@@ -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,22 @@ 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 */
|
||||
context->netid.next = NULL;
|
||||
tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, 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 +2346,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 +2414,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
File diff suppressed because it is too large.
Load diff
+23
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user