Compare commits

...
92 Commits
Author SHA1 Message Date
Simon Kelley 2a82db4caf Supply zero preference in advertise and reply messages 2012-03-10 21:40:10 +00:00
Simon Kelley dd88c17f15 Add status code containing "success" to all IA_TA and IA_NA
which have IAADDR options. This communicates zero information and
RFC3315 is unclear that it's needed, but at least one client seems
to require it.
2012-03-10 20:46:57 +00:00
Simon Kelley 8b37270410 Implement --dhcp-duid 2012-03-09 17:45:10 +00:00
Simon Kelley 760169fc43 Debian updates. 2012-03-09 14:27:49 +00:00
Simon Kelley 7023e38294 Docs changes for ra-names. 2012-03-09 12:05:49 +00:00
Simon Kelley a7cf58cc47 Merge branch 'ra-names' 2012-03-09 11:37:42 +00:00
Simon Kelley e25d1a2ea2 Fix prefix-map build code logic. 2012-03-08 13:24:17 +00:00
Simon Kelley 70969c1757 move #include for Solaris and Apple. 2012-03-07 20:46:28 +00:00
Simon Kelley 3803437dcc tidying 2012-03-07 20:39:40 +00:00
Simon Kelley eabc6dd76a Use getifaddrs on *BSD. 2012-03-07 20:28:20 +00:00
Simon Kelley e28d2e2b77 Merge branch 'getifaddrs' 2012-03-07 20:26:23 +00:00
Simon Kelley 96fafe2ed6 Fixed typos and tested. 2012-03-07 20:25:39 +00:00
Simon Kelley c81d390f84 Update man page to reflect the existance of DHCPv6 and RA. 2012-03-07 19:10:19 +00:00
Simon Kelley 08456c61f6 Use getifaddrs to find interfaces on *BSD 2012-03-07 19:08:11 +00:00
Simon Kelley bc26f9a03f Handle firewire and EUI-64 addresses in the SLAAC code. 2012-03-07 13:13:56 +00:00
Simon Kelley 6ffeff86be Teach emit_dbus_signal() about IPv6 DHCPv6 leases. 2012-03-07 10:32:35 +00:00
Simon Kelley f444cddbaf Don't waste time calculating EUI-64 when a lease doesn't have a name. 2012-03-07 10:15:57 +00:00
Simon Kelley d13191a46c Bump Debian version number. 2012-03-06 19:57:39 +00:00
Simon Kelley 801ca9a7b7 Add ra-names SLAAC-hostnames from DHCPv4 option. 2012-03-06 19:30:17 +00:00
Simon Kelley df66e341de Update polish translation. 2012-03-04 20:04:22 +00:00
Simon Kelley 71ee7ee254 Update French translation. 2012-03-03 18:06:49 +00:00
Simon Kelley a156cae901 Typos in man page. 2012-03-02 21:10:39 +00:00
Simon Kelley 22b135a116 Fix paretheses in ADD_RDLEN - it always returned 1 before. 2012-03-01 19:54:50 +00:00
Simon Kelley 0f08983d85 Be more picly about the MAC address we use for DUID-creation. 2012-03-01 13:43:39 +00:00
Simon Kelley e3e86343fc Fix DUID generation with HAVE_BROKEN_RTC. 2012-03-01 10:35:34 +00:00
Simon Kelley 7b6dd880f7 Fix socklen_t/size_t confusion in radv.c 2012-03-01 10:26:16 +00:00
Simon Kelley b7f4020133 Fix FTBFS when HAVE_BROKEN_RTC defined. 2012-02-29 21:43:37 +00:00
Simon Kelley c46c7c7584 tweak portable get-cwd trick code to work on GNU-make 3.82 2012-02-29 21:37:14 +00:00
Simon Kelley 552af8b988 Fix --localise-queries via interface lo bug. 2012-02-29 20:10:31 +00:00
Simon Kelley 4f8ff361dc Tiny makefile tweak. 2012-02-29 16:01:17 +00:00
Simon Kelley 0010b47439 RA configuration tweaks and documentation improvements. 2012-02-29 12:18:30 +00:00
Simon Kelley 4b86b65d07 Substitute local address for [::] DHCPv6 options, like DHCPv4. 2012-02-29 11:45:37 +00:00
Simon Kelley 248489401a Makefile cleanup - use lower case variables for internal use. 2012-02-29 11:23:41 +00:00
Simon Kelley bc5992daf6 Merge messages files prior to rc1. 2012-02-28 18:07:15 +00:00
Simon Kelley fdacfb0119 Makefile: support absolute paths in BUILDDIR 2012-02-28 15:20:25 +00:00
Simon Kelley 0d5d35d052 RA lifetimes must be at least 2 hours 2012-02-27 20:24:40 +00:00
Simon Kelley 843c96b4b3 Make RA without DHCPv6 possible. 2012-02-27 17:42:38 +00:00
Simon Kelley 58dc02ebf2 Order of fields in DHCPv6 log lines now consistent with DHCPv4 2012-02-27 11:49:37 +00:00
Simon Kelley c239f7de25 rename header files. 2012-02-27 10:56:18 +00:00
Simon Kelley ac8540c3c5 CHANGELOG entry to RA. 2012-02-26 20:57:31 +00:00
Simon Kelley 22d904db95 Fix RA on *BSD (missing sa_len) 2012-02-26 20:13:45 +00:00
Simon Kelley 741c2952d4 Tidy up RA scheduling. 2012-02-25 13:09:18 +00:00
Simon Kelley 96f6979c4f OpenBSD-friendly bld/get-version script 2012-02-25 11:31:15 +00:00
Simon Kelley c5379c1ab6 Don't send hoplimit 1 when multicasting RAs 2012-02-24 20:05:52 +00:00
Simon Kelley a4a5205fd7 Fix ordering problem in multicast setup. 2012-02-24 19:44:05 +00:00
Simon Kelley c5ad4e7998 Router Advertisement 2012-02-24 16:06:20 +00:00
Simon Kelley 270dc2e199 Fix wrong fallback address in DHCPv6 2012-02-19 20:53:20 +00:00
Simon Kelley 948a0b6e81 don't use -m flag to grep - it's unavailable in OpenBSD 2012-02-19 20:25:01 +00:00
Simon Kelley 87b8ecb13a Fixed code passing tags to helper to work when there are no context tags.
Fixed call to sendto() in dhcp6.c. How did it every work before?
2012-02-18 21:23:16 +00:00
Simon Kelley e44ddcac63 Fix hang at startup when DHCPv6 enabled on a complex network
configuration - we have to read all the MAC addresses from netlink,
not bail when we find a suitable one.

Fix thinko in dhcp_update_configs - thanks to Hartmut for spotting
that.

Get a sensible address for the default DNS server even when using a
relay.
2012-02-18 17:08:50 +00:00
Simon Kelley 00e9ad5217 Fixes for DHCPv6 tag system. 2012-02-16 21:53:11 +00:00
Simon Kelley 96c3879bed Change Debian rules file to relect the fact that we build DHCPv6 by default. 2012-02-16 20:07:17 +00:00
Simon Kelley 57f460de2f tweak Lua script argument passing and add --dhcp-luascript sectino to manpage. 2012-02-16 20:00:32 +00:00
Simon Kelley 6caacacf6d Putative fix to crash in IPv4 DHCP, introduced whilst
generalising the DHCP option filter code:
don't match options against context tag  when
context->netid.net == NULL, since there's no tag then.
2012-02-15 21:58:33 +00:00
Simon Kelley 60ac5af682 Remove extact-MAC address from DUID code. 2012-02-15 10:41:03 +00:00
Simon Kelley caa94380ac bugs in IPv6 script calling - wrong DUID and lua relay_address 2012-02-15 10:29:50 +00:00
Simon Kelley 0793380b40 Implement dhcp-ignore-names and DNSMASQ_RELAY_ADDRESS for IPv6
Build DHCPv6 by default.
2012-02-14 20:55:25 +00:00
Simon Kelley 1adadf585d Tweak Makefile so it works again in BSD make.
First cut at man page changes for DHCPv6
2012-02-13 22:15:58 +00:00
Simon Kelley e5ffdb9c77 BUILD_DIR -> BUILDDIR, for consistency. 2012-02-13 14:28:13 +00:00
Simon Kelley 6da5201092 Merge branch 'makefile' 2012-02-13 12:55:33 +00:00
Simon Kelley b36ae19434 Add BUILD_DIR variable to makefile. 2012-02-13 12:54:34 +00:00
Simon Kelley 2307eac613 Fix code parsing --domain, broken whilst added IPv6 stuff. 2012-02-13 10:13:13 +00:00
Simon Kelley 127ea40ae7 Don't build DHCPv6 by default, except when build Debian package. 2012-02-11 22:14:52 +00:00
Simon Kelley 6aef600d48 Correct duid generate on FreeBSD 2012-02-11 22:01:50 +00:00
Simon Kelley 98d76a0326 Tweaks to fix compilation on FreeBSD. 2012-02-10 22:16:45 +00:00
Simon Kelley 6ea6dcf05b Update Debian readme for new build options and (belatedly) for the
introduction of dnsmasq-utils.
2012-02-10 21:26:52 +00:00
Simon Kelley 627797800d Report correct error if prefix in dhcp-range is less than 64
Update debian/rules to provide no_dhcp6 and use_lua build opts.
Log DHCPv6 information request packets.
2012-02-10 21:19:25 +00:00
Simon Kelley c6cc03ed0c Merge branch 'dhcpv6' 2012-02-10 17:36:20 +00:00
Simon Kelley 3d7b550f52 missed DHCP6 conditional compilation. 2012-02-10 17:35:37 +00:00
Simon Kelley 751d6f4ae6 Allow the TFP server or boot server in --pxe-service, to
be a domain name instead of an IP address. This allows for
 round-robin to multiple servers, in the same way as
 --dhcp-boot.
2012-02-10 15:24:51 +00:00
Simon Kelley a5c72ab51d DHCPv6 vendor class option includes an enterprise number. Handle that. 2012-02-10 13:42:47 +00:00
Simon Kelley 9bbc88762b Fix shell scripting bug in bug scripts. 2012-02-09 21:33:09 +00:00
Simon Kelley ceae00dddf lease script should work with IPv6 now. 2012-02-09 21:28:14 +00:00
Simon Kelley 3634c54e8d dhcp-ignore and dhcp-match implemented for DHCPv6 now. 2012-02-08 14:22:37 +00:00
Simon Kelley d74942a03d IPv6 address range parsing for --domain.
Counted string DHCP option type printing
2012-02-07 20:51:56 +00:00
Simon Kelley 70c5e3e076 DHCPDECLINE handling, domain handling, more complete address selection. 2012-02-06 22:05:15 +00:00
Simon Kelley 4cb1b32009 Clean compile, basic DHCPv6 functionality is there.
TODO
     hostname handling.
     update DHCP6 configs from dns
     parse domain=<domain>,<IPv6 range>
     pretty-print counted string options.
     DECLINE messages
     lease-script fro DHCPv6
2012-02-06 14:30:41 +00:00
Simon Kelley 3268e90f5e Make default NO_DHCP6 and remove compiler warning. 2012-01-22 16:15:02 +00:00
Simon Kelley e98170816a Merge branch 'dhcpv6' 2012-01-22 16:07:22 +00:00
Simon Kelley 52b92f4db8 It compiles and it allocates a lease! No renewals yet. 2012-01-22 16:05:15 +00:00
Simon Kelley a2761754da Fix problem if dnsmasq is started without the stdin,
stdout and stderr file descriptors open. This can manifest
itself as 100% CPU use. Thanks to Chris Moore for finding
this.
2012-01-18 16:07:21 +00:00
Simon Kelley 805a11345c We don't need to check that a cache record is F_HOST in the
duplicate address code, since we're now searching a temporary hash
which holds only F_HOST records.
2012-01-13 11:51:46 +00:00
Simon Kelley 1ab62aec37 Further tuning of the fast hostfile reading code.
Use the packet buffer for hash-buckets, better hash function.
2012-01-12 11:33:16 +00:00
Simon Kelley 915363f976 Tweaks to hostfile performance work. 2012-01-11 22:00:48 +00:00
Simon Kelley 205fafa577 Improve performance when reading large hostfiles. 2012-01-11 21:31:51 +00:00
Simon Kelley be2daf4ad5 Enable DHCPv6 compilation 2012-01-07 17:51:57 +00:00
Simon Kelley 8ecfaa4adf Tidied up usage strings. 2012-01-07 15:29:48 +00:00
Simon Kelley 03bfcf6462 FAQ and example config additions for Windows 7 WPAD problem. 2012-01-07 14:37:37 +00:00
Simon Kelley 39bec5ff32 Remove duplicate tags in data supplied to lease script. 2012-01-06 22:36:58 +00:00
Simon Kelley 246839d64a Minimal update of doc.html - remove broken links and add git info. 2012-01-06 20:39:54 +00:00
Simon Kelley 3862deb398 Debian bug #654897 2012-01-06 20:16:07 +00:00
Simon Kelley 5954608577 Updated copyright notices. Happy new year! 2012-01-06 20:02:04 +00:00
56 changed files with 10569 additions and 6192 deletions

No files matched your search

+64 -1
View File
@@ -1,3 +1,15 @@
version 2.61
Re-write interface discovery code on *BSD to use
getifaddrs. This is more portable, more straightforward,
and allows us to find the prefix length for IPv6
addresses.
Add ra-names DHCPv6 keyword which adds AAAA records
for dual-stack hosts which get IPv6 addresses via SLAAC.
Add --dhcp-duid to allow DUID-EN uids to be used.
version 2.60 version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf Fix compilation problem in Mac OS X Lion. Thanks to Olaf
Flebbe for the patch. Flebbe for the patch.
@@ -29,7 +41,58 @@ version 2.60
Determine VERSION automatically based on git magic: Determine VERSION automatically based on git magic:
release tags or hash values. release tags or hash values.
Improve start-up speed when reading large hosts files
containing many distinct addresses.
Fix problem if dnsmasq is started without the stdin,
stdout and stderr file descriptors open. This can manifest
itself as 100% CPU use. Thanks to Chris Moore for finding
this.
Fix shell-scripting bug in bld/pkg-wrapper. Thanks to
Mark Mitchell for the patch.
Allow the TFP server or boot server in --pxe-service, to
be a domain name instead of an IP address. This allows for
round-robin to multiple servers, in the same way as
--dhcp-boot. A good suggestion from Cristiano Cumer.
Support BUILDDIR variable in the Makefile. Allows builds
for multiple archs from the same source tree with eg.
make BUILDDIR=linux (relative to dnsmasq tree)
make BUILDDIR=/tmp/openbsd (absolute path)
If BUILDDIR is not set, compilation happens in the src
directory, as before. Suggestion from Mark Mitchell.
Support DHCPv6. Support is there for the sort of things
the existing v4 server does, including tags, options,
static addresses and relay support. Missing is prefix
delegation, which is probably not required in the dnsmasq
niche, and an easy way to accept prefix delegations from
an upstream DHCPv6 server, which is. Future plans include
support for DHCPv6 router option and MAC address option
(to make selecting clients by MAC address work like IPv4).
These will be added as the standards mature.
This code has been tested, but this is the first release,
so don't bet the farm on it just yet. Many thanks to all
testers who have got it this far.
Support IPv6 router advertisements. This is a
simple-minded implementation, aimed at providing the
vestigial RA needed to go alongside IPv6. Is picks up
configuration from the DHCPv6 conf, and should just need
enabling with --enable-ra.
Fix long-standing wrinkle with --localise-queries that
could result in wrong answers when DNS packets arrive
via an interface other than the expected one. Thanks to
Lorenzo Milesi and John Hanks for spotting this one.
Update French translation. Thanks to Gildas Le Nadan.
Update Polish translation. Thanks to Jan Psota.
version 2.59 version 2.59
Fix regression in 2.58 which caused failure to start up Fix regression in 2.58 which caused failure to start up
with some combinations of dnsmasq config and IPv6 kernel with some combinations of dnsmasq config and IPv6 kernel
+10
View File
@@ -467,8 +467,18 @@ A: The DHCP client on windows Vista (and possibly later versions)
work). work).
Q: DHCP doesn't work with windows 7 but everything else is fine.
A: There seems to be a problem if Windows 7 doesn't get a value for
DHCP option 252 in DHCP packets it gets from the server. The
symtoms have beeen variously reported as continual DHCPINFORM
requests in an attempt to get an option-252, or even ignoring DHCP
offers completely (and failing to get an IP address) if there is no
option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy
Auto Detection and if you don't want or need to use that, then
simplest fix seems to be to supply an empty option with:
dhcp-option=252,"\n"
+83 -53
View File
@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2011 Simon Kelley # dnsmasq is Copyright (c) 2000-2012 Simon Kelley
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@@ -13,92 +13,122 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
PREFIX = /usr/local # NOTE: Building the i18n targets requires GNU-make
BINDIR = ${PREFIX}/sbin
MANDIR = ${PREFIX}/share/man
LOCALEDIR = ${PREFIX}/share/locale
PKG_CONFIG = pkg-config
INSTALL = install
MSGMERGE = msgmerge
MSGFMT = msgfmt
XGETTEXT = xgettext
CFLAGS = -Wall -W -O2 # Variables you may well want to override.
PREFIX = /usr/local
BINDIR = $(PREFIX)/sbin
MANDIR = $(PREFIX)/share/man
LOCALEDIR = $(PREFIX)/share/locale
BUILDDIR = $(SRC)
DESTDIR =
CFLAGS = -Wall -W -O2
LDFLAGS =
COPTS =
RPM_OPT_FLAGS =
LIBS =
################################################################# #################################################################
# Variables you might want to override.
PKG_CONFIG = pkg-config
INSTALL = install
MSGMERGE = msgmerge
MSGFMT = msgfmt
XGETTEXT = xgettext
SRC = src SRC = src
PO = po PO = po
MAN = man MAN = man
DBUS_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1` #################################################################
DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
LUA_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
LUA_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
VERSION= -DVERSION='\"`../bld/get-version`\"'
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \ # pmake way. (NB no spaces to keep gmake 3.82 happy)
top!=pwd
# GNU make way.
top?=$(CURDIR)
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \ dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o
all : hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
@cd $(SRC) && $(MAKE) \ dns-protocol.h radv-protocol.h
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS)" \
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS)" \ all : $(BUILDDIR)
-f ../Makefile dnsmasq @cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
-f $(top)/Makefile dnsmasq
clean : clean :
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
rm -f $(SRC)/*.o $(SRC)/dnsmasq.a $(SRC)/dnsmasq core */core rm -f $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq core */core
install : all install-common install : all install-common
install-common : install-common :
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8 $(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(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 : all-i18n : $(BUILDDIR)
@cd $(SRC) && $(MAKE) \ @cd $(BUILDDIR) && $(MAKE) \
I18N=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \ top="$(top)" \
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \ i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \ build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
-f ../Makefile dnsmasq build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`" \
@cd $(PO); for f in *.po; do \ -f $(top)/Makefile dnsmasq
cd ../$(SRC) && $(MAKE) \ for f in `cd $(PO); echo *.po`; do \
-f ../Makefile $${f%.po}.mo; \ cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
done done
install-i18n : all-i18n install-common install-i18n : all-i18n install-common
cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL) cd $(BUILDDIR); $(top)/bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL) cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
merge : merge :
@cd $(SRC) && $(MAKE) -f ../Makefile dnsmasq.pot @cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
@cd $(PO); for f in *.po; do \ for f in `cd $(PO); echo *.po`; do \
echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \ echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
done done
$(BUILDDIR):
mkdir -p $(BUILDDIR)
# rules below are targets in recusive makes with cwd=$(SRC) # rules below are targets in recusive makes with cwd=$(SRC)
$(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ .
.c.o: .c.o:
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $< $(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(OBJS) dnsmasq : $(hdrs) $(objs)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS) $(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) $(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(objs:.o=.c)
%.mo : ../po/%.po dnsmasq.pot %.mo : $(top)/$(PO)/%.po dnsmasq.pot
$(MSGMERGE) -o - ../po/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo - $(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
.PHONY : all clean install install-common all-i18n install-i18n merge .PHONY : all clean install install-common all-i18n install-i18n merge
+3 -1
View File
@@ -6,7 +6,9 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
forward.c helper.c lease.c log.c \ forward.c helper.c lease.c log.c \
netlink.c network.c option.c rfc1035.c \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq
+8 -8
View File
@@ -9,18 +9,18 @@
# If we can find one which matches $v[0-9].* then we assume it's # 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. # a version-number tag, else we just use the whole string.
# we're called with pwd == src if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
cd .. cd $1; git describe
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
if [ -d .git ]; then # unsubstituted VERSION, but no git available.
git describe echo UNKNOWN
else else
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]` vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo ${vers#v} echo "${vers}" | head -n 1 | tail -c +2
else else
cat VERSION cat $1/VERSION
fi fi
fi fi
+1 -1
View File
@@ -4,6 +4,6 @@ for f in *; do
if [ -d $f ]; then if [ -d $f ]; then
$2 -m 755 -d $1/$f/man8 $2 -m 755 -d $1/$f/man8
$2 -m 644 $f/dnsmasq.8 $1/$f/man8 $2 -m 644 $f/dnsmasq.8 $1/$f/man8
echo installing $1/$f/man8/dnsmasq.8 echo installing $f/man8/dnsmasq.8
fi fi
done done
+1 -1
View File
@@ -3,7 +3,7 @@
for f in *.mo; do for f in *.mo; do
$2 -m 755 -d $1/${f%.mo}/LC_MESSAGES $2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
$2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo $2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo echo installing ${f%.mo}/LC_MESSAGES/dnsmasq.mo
done done
+2 -2
View File
@@ -3,8 +3,8 @@
search=$1 search=$1
shift shift
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h 2>&1 >/dev/null || \ if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
grep $search 2>&1 >/dev/null ; then grep $search >/dev/null 2>&1; then
exec $* exec $*
fi fi
+9
View File
@@ -1,7 +1,16 @@
dnsmasq (2.61-1) unstable; urgency=low
* New upstream.
* Provide "dump-stats" initscript method. (closes: #654656)
* Add (empty) build-indep and build-arch rules targets.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Mar 2012 19:45:43 +0000
dnsmasq (2.60-1) unstable; urgency=low dnsmasq (2.60-1) unstable; urgency=low
* New upstream. * New upstream.
* Bump standards-version to 3.9.2 * Bump standards-version to 3.9.2
* Fix typo in example config file. (closes: #654897)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 1 Dec 2011 15:49:33 +0000 -- Simon Kelley <simon@thekelleys.org.uk> Thu, 1 Dec 2011 15:49:33 +0000
+1 -1
View File
@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2010 Simon Kelley dnsmasq is Copyright (c) 2000-2012 Simon Kelley
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/ It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
Vendored
+4 -1
View File
@@ -256,8 +256,11 @@ case "$1" in
*) log_success_msg "(unknown)" ; exit 4 ;; *) log_success_msg "(unknown)" ; exit 4 ;;
esac esac
;; ;;
dump-stats)
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
;;
*) *)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2 echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3 exit 3
;; ;;
esac esac
+8 -2
View File
@@ -52,7 +52,10 @@ Notes on configuring dnsmasq as packaged for Debian.
nodocs : omit documentation. nodocs : omit documentation.
notftp : omit TFTP support. notftp : omit TFTP support.
nodhcp : omit DHCP support. nodhcp : omit DHCP support.
nodhcp6 : omit DHCPv6 support.
noscript : omit lease-change script support. noscript : omit lease-change script support.
use_lua : provide support for lease-change scripts written
in Lua.
noipv6 : omit IPv6 support. noipv6 : omit IPv6 support.
nodbus : omit DBus support. nodbus : omit DBus support.
noconntrack : omit connection tracking support. noconntrack : omit connection tracking support.
@@ -60,11 +63,14 @@ Notes on configuring dnsmasq as packaged for Debian.
noi18n : omit translations and internationalisation support. noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be noidn : omit international domain name support, must be
combined with noi18n to be effective. combined with noi18n to be effective.
(9) Dnsmasq comes as two packages - dnsmasq-base and (9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. dnsmasq-base provides the dnsmasq executable and dnsmasq. Dnsmasq-base provides the dnsmasq executable and
documentation (including this file). Dnsmasq, which depends on documentation (including this file). Dnsmasq, which depends on
dnsmasq-base, provides the init script and configuration dnsmasq-base, provides the init script and configuration
infrastructure. This file assumes that both are installed. It is infrastructure. This file assumes that both are installed. It is
possible to install only dnsmasq-base and use dnsmasq as a possible to install only dnsmasq-base and use dnsmasq as a
non-"system" daemon. Libvirt, for instance, does this. non-"system" daemon. Libvirt, for instance, does this.
Dnsmasq-utils provides the utilities dhcp_release and
dhcp_lease_time.
+21 -10
View File
@@ -12,7 +12,7 @@
package=dnsmasq-base package=dnsmasq-base
# policy manual, section 10.1 # policy manual, section 10.1
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS = -g -O0 -Wall -W CFLAGS = -g -O0 -Wall -W
else else
CFLAGS = -g -O2 -Wall -W CFLAGS = -g -O2 -Wall -W
@@ -23,43 +23,51 @@ TARGET = install-i18n
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) 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 COPTS += -DHAVE_DBUS
endif endif
ifeq (,$(findstring noconntrack,$(DEB_BUILD_OPTIONS))) ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_BUILD_ARCH_OS),linux) ifeq ($(DEB_BUILD_ARCH_OS),linux)
COPTS += -DHAVE_CONNTRACK COPTS += -DHAVE_CONNTRACK
endif endif
endif endif
ifneq (,$(findstring noipv6,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP6
endif
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_IPV6 COPTS += -DNO_IPV6
endif endif
ifneq (,$(findstring notftp,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_TFTP COPTS += -DNO_TFTP
endif endif
ifneq (,$(findstring nodhcp,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_DHCP COPTS += -DNO_DHCP
endif endif
ifneq (,$(findstring noscript,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
COPTS += -DNO_SCRIPT COPTS += -DNO_SCRIPT
endif endif
ifneq (,$(findstring nortc,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_BROKEN_RTC COPTS += -DHAVE_BROKEN_RTC
endif endif
ifneq (,$(findstring noi18n,$(DEB_BUILD_OPTIONS))) ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install TARGET = install
ifeq (,$(findstring noidn, $(DEB_BUILD_OPTIONS))) ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_IDN COPTS += -DHAVE_IDN
endif endif
endif endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_LUASCRIPT
endif
clean: clean:
$(checkdir) $(checkdir)
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
@@ -176,7 +184,10 @@ endef
# Below here is fairly generic really # Below here is fairly generic really
binary: binary-arch binary-indep binary: binary-arch binary-indep
build: build:
build-arch:
build-indep:
checkroot: checkroot:
test root = "`whoami`" test root = "`whoami`"
+37 -1
View File
@@ -157,6 +157,26 @@
# an explicit netmask instead. # an explicit netmask instead.
#dhcp-range=192.168.0.0,static #dhcp-range=192.168.0.0,static
# Enable DHCPv6. Note that the prefix-length does not need to be specified
# and defaults to 64 if missing/
#dhcp-range=1234::2, 1234::500, 64, 12h
# Do Router Advertisements, BUT NOT DHCP for this subnet.
#dhcp-range=1234::, ra-only
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
# hosts. Use the DHCPv4 lease to derive the name, network segment and
# MAC address and assume that the host will also have an
# IPv6 address calculated using the SLAAC alogrithm.
# This will generate an erroneous AAAA record if a host is using privacy
# extensions or does not support IPv6. Use with care.
#dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet.
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
#dhcp-range=1234::, ra-only, 48h
# Supply parameters for specified hosts using DHCP. There are lots # Supply parameters for specified hosts using DHCP. There are lots
# of valid alternatives, so we will give examples of each. Note that # of valid alternatives, so we will give examples of each. Note that
# IP addresses DO NOT have to be in the range given above, they just # IP addresses DO NOT have to be in the range given above, they just
@@ -219,7 +239,13 @@
# any machine with Ethernet address starting 11:22:33: # any machine with Ethernet address starting 11:22:33:
#dhcp-host=11:22:33:*:*:*,set:red #dhcp-host=11:22:33:*:*:*,set:red
# Ignore any clients which are specified in dhcp-host lines # Give a fixed IPv6 address and name to client with
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
# Note also the they [] around the IPv6 address are obilgatory.
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
# Ignore any clients which are not specified in dhcp-host lines
# or /etc/ethers. Equivalent to ISC "deny unknown-clients". # or /etc/ethers. Equivalent to ISC "deny unknown-clients".
# This relies on the special "known" tag which is set when # This relies on the special "known" tag which is set when
# a host is matched. # a host is matched.
@@ -270,6 +296,13 @@
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5 # Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5 #dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
# Send DHCPv6 option. Note [] around IPv6 addresses.
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
# Send DHCPv6 option for namservers as the machine running
# dnsmasq and another.
#dhcp-option=option6:dns-server,[::],[1234::88]
# Set the NTP time server address to be the same machine as # Set the NTP time server address to be the same machine as
# is running dnsmasq # is running dnsmasq
#dhcp-option=42,0.0.0.0 #dhcp-option=42,0.0.0.0
@@ -304,6 +337,9 @@
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server #dhcp-option=45,0.0.0.0 # netbios datagram distribution server
#dhcp-option=46,8 # netbios node type #dhcp-option=46,8 # netbios node type
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
#dhcp-option=252,"\n"
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client # Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
# probably doesn't support this...... # probably doesn't support this......
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com #dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
+10 -15
View File
@@ -27,7 +27,7 @@ connection but would be a good choice for any smallish network (up to
1000 clients is known to work) where low 1000 clients is known to work) where low
resource use and ease of configuration are important. resource use and ease of configuration are important.
<P> <P>
Supported platforms include Linux (with glibc and uclibc), *BSD, Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
Solaris and Mac OS X. Solaris and Mac OS X.
Dnsmasq is included in at least the following Linux distributions: Dnsmasq is included in at least the following Linux distributions:
Gentoo, Debian, Slackware, Suse, Fedora, Gentoo, Debian, Slackware, Suse, Fedora,
@@ -88,24 +88,19 @@ for any or all local machines.
</LI> </LI>
</DIR> </DIR>
<H2>Download.</H2> <H2>Get code.</H2>
<A HREF="http://www.thekelleys.org.uk/dnsmasq/"> Download</A> dnsmasq here. <A HREF="http://www.thekelleys.org.uk/dnsmasq/">Download</A> dnsmasq here.
The tarball includes this documentation, source, and manpage. The tarball includes this documentation, source, and manpage.
There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>. There is also a <A HREF="CHANGELOG"> CHANGELOG</A> and a <A HREF="FAQ">FAQ</A>.
Dnsmasq is part of the Debian distribution, it can be downloaded from
<A HREF="http://ftp.debian.org/debian/pool/main/d/dnsmasq/"> here</A> or installed using <TT>apt</TT>.
<H2>Links.</H2> Dnsmasq has a git repository which contains the complete release
Damien Raude-Morvan has an article in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A> history of version 2 and development history from 2.60. You can
There is a good article about dnsmasq at <A <A HREF="http://thekelleys.org.uk/gitweb/?p=dnsmasq.git;a=summary">browse</A>
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A> the repo, or get a copy using git protocol with the command
and another at <A
HREF="http://www.linux.com/articles/149040">http://www.linux.com/articles/149040</A> <PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
and Ilya Evseev has an article in Russian about dnsmasq to be found at
<A HREF="http://ilya-evseev.narod.ru/articles/dnsmasq">
http://ilya-evseev.narod.ru/articles/dnsmasq</A>. Ismael Ull has an
article about dnsmasq in Spanish at <A HREF="http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq">http://www.mey-online.com.ar/blog/index.php/archives/guia-rapida-de-dnsmasq</A>
<H2>License.</H2> <H2>License.</H2>
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
for details. for details.
+189 -44
View File
@@ -23,7 +23,7 @@ options. It includes a secure, read-only,
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP. TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
.PP .PP
Dnsmasq Dnsmasq
supports IPv6 for DNS and TFTP, but not DHCP. supports IPv6 for all functions and a minimal router-advertisemnet daemon.
.SH OPTIONS .SH OPTIONS
Note that in general missing parameters are allowed and switch off Note that in general missing parameters are allowed and switch off
functions, for instance "--pid-file" disables writing a PID file. On functions, for instance "--pid-file" disables writing a PID file. On
@@ -495,6 +495,9 @@ included and configured. This option cannot be combined with
--query-port. --query-port.
.TP .TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>] .B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<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 Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given <start-addr> to <end-addr> and from statically defined addresses given
in in
@@ -515,19 +518,29 @@ C) of the network address. The broadcast address is
always optional. It is always always optional. It is always
allowed to have more than one dhcp-range in a single subnet. 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 The optional
.B set:<tag> .B set:<tag>
sets an alphanumeric label which marks this network so that sets an alphanumeric label which marks this network so that
dhcp options may be specified on a per-network basis. dhcp options may be specified on a per-network basis.
When it is prefixed with 'tag:' instead, then its meaning changes from setting When it is prefixed with 'tag:' instead, then its meaning changes from setting
a tag to matching it. Only one tag may be set, but more than one tag may be matched. a tag to matching it. Only one tag may be set, but more than one tag
may be matched.
The end address may be replaced by the keyword The end address may be replaced by the keyword
.B static .B static
which tells dnsmasq to enable DHCP for the network specified, but not which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses: only hosts which have static to dynamically allocate IP addresses: only hosts which have static
addresses given via addresses given via
.B dhcp-host .B dhcp-host
or from /etc/ethers will be served. The end address may be replaced by or from /etc/ethers will be served.
The end address may be replaced by
the keyword the keyword
.B proxy .B proxy
in which case dnsmasq will provide proxy-DHCP on the specified in which case dnsmasq will provide proxy-DHCP on the specified
@@ -535,7 +548,26 @@ subnet. (See
.B pxe-prompt .B pxe-prompt
and and
.B pxe-service .B pxe-service
for details.) for details, applies to IPv4 only.)
The end address may be replaced by
the keyword
.B ra-only
which tells dnsmasq to offer Router Advertisement only on this subnet,
and not DHCP. This applies to IPv6 only, see
.B enable-ra
for details. Instead, the keyword
.B ra-names
may be used. This does the same at ra-only, but also enables a mode
which gives DNS names to dual-stack hosts which do SLAAC for
IPv6. Dnsmasq uses the hosts IPv4 lease to derive the name, network
segment and MAC address and assumes that the host will also have an
IPv6 address calculated using the SLAAC alogrithm, on the same network
segment. An AAAA record is added to the DNS for this IPv6
address. Note that this is only happens for directly-connected
networks, (not one doing DHCP via a relay) and it will generate an
erroneous AAAA record if a host is using privacy extensions or does
not support IPv6. Use with care.
The interface:<interface name> section is not normally used. See the The interface:<interface name> section is not normally used. See the
NOTES section for details of this. NOTES section for details of this.
@@ -570,6 +602,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: allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,..... .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 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 and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others. but not others.
@@ -617,7 +655,7 @@ will only match a
Token-Ring hardware address, since the ARP-address type for token ring Token-Ring hardware address, since the ARP-address type for token ring
is 6. 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: hardware address. eg:
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2 .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 This allows an IP address to be associated with
@@ -655,14 +693,14 @@ hostname or dotted-quad IP address. When read by dnsmasq these lines
have exactly the same effect as have exactly the same effect as
.B --dhcp-host .B --dhcp-host
options containing the same information. /etc/ethers is re-read when 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 .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, Specify different or extra options to DHCP clients. By default,
dnsmasq sends some standard options to DHCP clients, the netmask and dnsmasq sends some standard options to DHCP clients, the netmask and
broadcast address are set to the same as the host running dnsmasq, 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 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, This configuration allows these defaults to be overridden,
or other options specified. The option, to be sent may be given as a 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 decimal number or as "option:<option-name>" The option numbers are
@@ -677,7 +715,7 @@ and to set the time-server address to 192.168.0.4, do
.B --dhcp-option = 42,192.168.0.4 .B --dhcp-option = 42,192.168.0.4
or or
.B --dhcp-option = option:ntp-server, 192.168.0.4 .B --dhcp-option = option:ntp-server, 192.168.0.4
The special address 0.0.0.0 is taken to mean "the address of the The special address 0.0.0.0 (or [::] for DHCPv6) is taken to mean "the address of the
machine running dnsmasq". Data types allowed are comma separated machine running dnsmasq". Data types allowed are comma separated
dotted-quad IP addresses, a decimal number, colon-separated hex digits dotted-quad IP addresses, a decimal number, colon-separated hex digits
and a text string. If the optional tags are given then and a text string. If the optional tags are given then
@@ -689,6 +727,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 which are followed by a slash and then a netmask size are encoded as
described in RFC 3442. 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 Be careful: no checking is done that the correct type of data for the
option number is sent, it is quite possible to option number is sent, it is quite possible to
persuade dnsmasq to generate illegal DHCP packets with injudicious use persuade dnsmasq to generate illegal DHCP packets with injudicious use
@@ -704,7 +750,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 a literal IP address as TFTP server name, it is necessary to do
.B --dhcp-option=66,"1.2.3.4" .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 --dhcp-option: for instance
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0 .B --dhcp-option=vendor:PXEClient,1,0.0.0.0
sends the encapsulated vendor sends the encapsulated vendor
@@ -716,9 +762,9 @@ for selecting encapsulated options in preference to any sent by the
client. It is client. It is
possible to omit the vendorclass completely; possible to omit the vendorclass completely;
.B --dhcp-option=vendor:,1,0.0.0.0 .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" .B --dhcp-option=encap:175, 190, "iscsi-client0"
will send option 175, within which is the option 190. If multiple will send option 175, within which is the option 190. If multiple
options are given which are encapsulated with the same option number options are given which are encapsulated with the same option number
@@ -729,8 +775,9 @@ The final variant on encapsulated options is "Vendor-Identifying
Vendor Options" as specified by RFC3925. These are denoted like this: Vendor Options" as specified by RFC3925. These are denoted like this:
.B --dhcp-option=vi-encap:2, 10, "text" .B --dhcp-option=vi-encap:2, 10, "text"
The number in the vi-encap: section is the IANA enterprise number 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 The address 0.0.0.0 is not treated specially in
encapsulated options. encapsulated options.
.TP .TP
@@ -742,14 +789,14 @@ not ask for it in the parameter request list. This is sometimes
needed, for example when sending options to PXELinux. needed, for example when sending options to PXELinux.
.TP .TP
.B --dhcp-no-override .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 option space. If it can, dnsmasq moves the boot server and filename
information (from dhcp-boot) out of their dedicated fields into information (from dhcp-boot) out of their dedicated fields into
DHCP options. This make extra space available in the DHCP packet for DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case. forces "simple and safe" behaviour to avoid problems in such a case.
.TP .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 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 "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 maps vendor classes to tags, so that DHCP options may be selectively delivered
@@ -759,7 +806,13 @@ will allow options to be set only for HP printers like so:
.B --dhcp-option=tag:printers,3,192.168.4.4 .B --dhcp-option=tag:printers,3,192.168.4.4
The vendor-class string is The vendor-class string is
substring matched against the vendor-class supplied by the client, to 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 .TP
.B \-j, --dhcp-userclass=set:<tag>,<user-class> .B \-j, --dhcp-userclass=set:<tag>,<user-class>
Map from a user-class string to a tag (with substring Map from a user-class string to a tag (with substring
@@ -771,7 +824,7 @@ this to set a different printer server for hosts in the class
"accounts" than for hosts in the class "engineering". "accounts" than for hosts in the class "engineering".
.TP .TP
.B \-4, --dhcp-mac=set:<tag>,<MAC address> .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 wildcards. For example
.B --dhcp-mac=set:3com,01:34:23:*:*:* .B --dhcp-mac=set:3com,01:34:23:*:*:*
will set the tag "3com" for any host whose MAC address matches the pattern. will set the tag "3com" for any host whose MAC address matches the pattern.
@@ -781,13 +834,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 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 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 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 .TP
.B --dhcp-subscrid=set:<tag>,<subscriber-id> .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 .TP
.B --dhcp-proxy[=<ip addr>]...... .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 a DHCP interaction to the DHCP server. Once a client is configured, it
communicates directly with the server. This is undesirable if the communicates directly with the server. This is undesirable if the
relay agent is addding extra information to the DHCP packets, such as relay agent is addding extra information to the DHCP packets, such as
@@ -847,7 +903,7 @@ dhcp-host configuration in dnsmasq and the contents of /etc/hosts and
/etc/ethers. /etc/ethers.
.TP .TP
.B --dhcp-generate-names=tag:<tag>[,tag:<tag>] .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 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, if a host provides a name, it will be used by preference to this,
unless unless
@@ -855,14 +911,14 @@ unless
is set. is set.
.TP .TP
.B --dhcp-broadcast[=tag:<tag>[,tag:<tag>]] .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 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 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 need broadcast replies set a flag in their requests so that this
happens automatically, some old BOOTP clients do not. happens automatically, some old BOOTP clients do not.
.TP .TP
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]] .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 are optional: if not provided, the name is left empty, and the
address set to the address of the machine running dnsmasq. If dnsmasq address set to the address of the machine running dnsmasq. If dnsmasq
is providing a TFTP service (see is providing a TFTP service (see
@@ -888,7 +944,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 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. likely to move IP address; for this reason it should not be generally used.
.TP .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 Most uses of PXE boot-ROMS simply allow the PXE
system to obtain an IP address and then download the file specified by system to obtain an IP address and then download the file specified by
.B dhcp-boot .B dhcp-boot
@@ -904,17 +960,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, boot server and directs the PXE client to download the file by TFTP,
either from itself ( either from itself (
.B enable-tftp .B enable-tftp
must be set for this to work) or another TFTP server if the final IP must be set for this to work) or another TFTP server if the final server
address is given. address/name is given.
Note that the "layer" Note that the "layer"
suffix (normally ".0") is supplied by PXE, and should not be added to 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 the basename. If an integer boot service type, rather than a basename
is given, then the PXE client will search for a is given, then the PXE client will search for a
suitable boot service for that type on the network. This search may be done 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) 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 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 .TP
.B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>] .B --pxe-prompt=[tag:<tag>,]<prompt>[,<timeout>]
Setting this provides a prompt to be displayed after PXE boot. If the Setting this provides a prompt to be displayed after PXE boot. If the
@@ -947,7 +1005,7 @@ create thousands of leases and use lots of memory in the dnsmasq
process. process.
.TP .TP
.B \-K, --dhcp-authoritative .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 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 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 to get a lease without a tedious timeout under all circumstances. It also
@@ -955,7 +1013,7 @@ allows dnsmasq to rebuild its lease database without each client needing to
reacquire a lease, if the database is lost. reacquire a lease, if the database is lost.
.TP .TP
.B --dhcp-alternate-port[=<server port>[,<client port>]] .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 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 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 port number is used for the server and the port number plus one used
@@ -963,7 +1021,7 @@ for the client. Finally, two port numbers allows arbitrary
specification of both server and client ports for DHCP. specification of both server and client ports for DHCP.
.TP .TP
.B \-3, --bootp-dynamic[=<network-id>[,<network-id>]] .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 with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by forever, and therefore becomes permanently unavailable for re-use by
other hosts. if this is given without tags, then it unconditionally other hosts. if this is given without tags, then it unconditionally
@@ -971,7 +1029,7 @@ enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets. set. It may be repeated with different tag sets.
.TP .TP
.B \-5, --no-ping .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 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 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 a reply, then the address must already be in use, and another is
@@ -984,13 +1042,23 @@ the tags used to determine them.
.B \-l, --dhcp-leasefile=<path> .B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information. Use the specified file to store DHCP lease information.
.TP .TP
.B --dhcp-duid=<enterprise-id>,<uid>
(IPv6 only) Specify the server persistent UID which the DHCPv6 server
will use. This option is not normally required as dnsmasq creates a
DUID automatically when it is first needed. When given, this option
provides dnsmasq the data required to create a DUID-EN type DUID. Note
that once set, the DUID is stored in the lease database, so to change between DUID-EN and
automatically created DUIDs or vice-versa, the lease database must be
re-intialised. The enterprise-id is assigned by IANA, and the uid is a
string of hex octets unique to a particular device.
.TP
.B \-6 --dhcp-script=<path> .B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the Whenever a new DHCP lease is created, or an old one destroyed, the
executable specified by this option is run. <path> executable specified by this option is run. <path>
must be an absolute pathname, no PATH search occurs. must be an absolute pathname, no PATH search occurs.
The arguments to the process The arguments to the process
are "add", "old" or "del", the MAC 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 if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing dnsmasq starts or a change to MAC address or hostname of an existing
@@ -1001,21 +1069,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. 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 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 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 known, this is set to the domain part. (Note that the hostname passed
to the script as an argument is never fully-qualified.) to the script as an argument is never fully-qualified.)
If the client provides vendor-class, hostname or user-class, If the client provides a hostname, DNSMASQ_SUPPLIED_HOSTNAME
these are provided in DNSMASQ_VENDOR_CLASS
DNSMASQ_SUPPLIED_HOSTNAME and If the client provides user-classes, DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn
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 dnsmasq was compiled with HAVE_BROKEN_RTC, then If dnsmasq was compiled with HAVE_BROKEN_RTC, then
the length of the lease (in seconds) is stored in the length of the lease (in seconds) is stored in
@@ -1039,6 +1103,32 @@ is known.
DNSMASQ_TAGS contains all the tags set during the DNSMASQ_TAGS contains all the tags set during the
DHCP transaction, separated by spaces. DHCP transaction, separated by spaces.
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 All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode). (except in debug mode).
@@ -1058,8 +1148,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 receives a HUP signal, the script will be invoked for existing leases
with an "old " event. with an "old " event.
.TP .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 .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 .TP
.B \-9, --leasefile-ro .B \-9, --leasefile-ro
Completely suppress use of the lease database file. The file will not Completely suppress use of the lease database file. The file will not
@@ -1142,6 +1267,26 @@ added into dnsmasq's DNS view. This flag suppresses that behaviour,
this is useful, for instance, to allow Windows clients to update this is useful, for instance, to allow Windows clients to update
Active Directory servers. See RFC 4702 for details. Active Directory servers. See RFC 4702 for details.
.TP .TP
.B --enable-ra
Enable dnsmasq's IPv6 Router Advertisement feature. DHCPv6 doesn't
handle complete network configuration in the same way as DHCPv4. Router
discovery and (possibly) prefix discovery for autonomous address
creation are handled by a different protocol. When DHCP is in use,
only a subset of this is needed, and dnsmasq can handle it, using
existing DHCP configuration to provide most data. When RA is enabled,
dnsmasq will advertise a prefix for each dhcp-range, with default
router and recursive DNS server as the relevant link-local address on
the machine running dnsmasq. The "managed address" bits are set,
except for a dhcp-range which is marked as "ra-only", in which case RA
is provided but no DHCPv6 service and the managed address bits are
cleared.
.B enable-ra
enables router advertisement for prefixes where dnsmasq is doing
DHCPv6. It is not needed to "ra-only" prefixes. Creating an "ra-only"
prefix and not setting
.B enable-ra
sends advertisements only to "ra-only" prefixes.
.TP
.B --enable-tftp[=<interface>] .B --enable-tftp[=<interface>]
Enable the TFTP server function. This is deliberately limited to that Enable the TFTP server function. This is deliberately limited to that
needed to net-boot a client. Only reading is allowed; the tsize and needed to net-boot a client. Only reading is allowed; the tsize and
+219 -87
View File
@@ -579,7 +579,9 @@ avec le support conntrack, le noyau doit également inclure conntrack et être
configuré pour cela. Cette option ne peut pas être combinée avec configuré pour cela. Cette option ne peut pas être combinée avec
--query-port. --query-port.
.TP .TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>] .B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
.TP
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label>],]<addresse IPv6 de début>,<adresse IPv6 de fin>[,<longueur de préfixe>][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies <adresse de début> et <adresse de fin> et à partir des adresses définies
statiquement dans l'option statiquement dans l'option
@@ -604,6 +606,14 @@ est toujours optionnelle.
Il est toujours possible d'avoir plus d'une plage DHCP pour un même Il est toujours possible d'avoir plus d'une plage DHCP pour un même
sous-réseau. sous-réseau.
Pour IPv6, les paramètres sont légèrement différents : au lieu d'un masque de
réseau et d'une adresse de broadcast, il existe une longueur de préfixe
optionnelle. Si elle est omise, la valeur par défaut est 64. À la différence
d'IPv4, la longueur de préfixe n'est pas automatiquement déduite de la
configuration de l'interface. La taille minimale pour la longueur de préfixe
est 64.
L'identifiant de label optionnel L'identifiant de label optionnel
.B set:<label> .B set:<label>
fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre fournie une étiquette alphanumérique qui identifie ce réseau, afin de permettre
@@ -627,7 +637,15 @@ spécifié. (voir
.B pxe-prompt .B pxe-prompt
et et
.B pxe-service .B pxe-service
pour plus de détails). pour plus de détails, s'applique à IPv4 seulement).
L'adresse de fin peut être remplacée par le mot-clef
.B ra-only
qui indique à dnsmasq de n'effectuer que des annonces de routeur (Router
Advertisement, RA) sur ce sous-réseau, et de ne pas faire de DHCP. Ceci
s'applique uniquement à IPv6, voir
.B enable-ra
pour plus de détails.
La section interface:<nom d'interface> n'est normalement pas utilisée. Se La section interface:<nom d'interface> n'est normalement pas utilisée. Se
référer aux indications de la section NOTES pour plus de détail à ce sujet. référer aux indications de la section NOTES pour plus de détail à ce sujet.
@@ -663,6 +681,15 @@ spécifier l'identifiant client sous la forme d'une chaîne de caractères, comm
ceci : ceci :
.B --dhcp-host=id:identifiantclientsousformedechaine,..... .B --dhcp-host=id:identifiantclientsousformedechaine,.....
Un seul
.B dhcp-host
peut contenir une adresse IPv4, une adresse IPv6, ou les deux en même temps.
Les adresses IPv6 doivent-être mises entre crochets comme suit :
.B --dhcp-host=laptop,[1234::56]
A noter que pour le DHCP IPv6, l'adresse matérielle n'est en principe pas
disponible, aussi un client doit-être identifié par un identifiant de client
(appellé "DUID client") ou un nom d'hôte.
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
que l'adresse matérielle". Cela est utile lorsqu'un client présente un que l'adresse matérielle". Cela est utile lorsqu'un client présente un
identifiant client mais pas les autres. identifiant client mais pas les autres.
@@ -709,7 +736,7 @@ ARP en les précédant du type ARP (en Hexadécimal) et de "-". Ainsi
coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type
ARP pour une adresse Token-Ring est 6. ARP pour une adresse Token-Ring est 6.
Un cas spécial correspond à l'inclusion d'une ou plusieurs adresses Un cas spécial, pour IPv4, correspond à l'inclusion d'une ou plusieurs adresses
matérielles, c-à-d : matérielles, c-à-d :
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2. .B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2.
Cela permet à une adresse IP d'être associé à plusieurs adresses Cela permet à une adresse IP d'être associé à plusieurs adresses
@@ -750,22 +777,22 @@ une adresse IP sous la forme de 4 chiffres séparés par des points. Lorsque lu
par Dnsmasq, ces lignes ont exactement le même effet que l'option par Dnsmasq, ces lignes ont exactement le même effet que l'option
.B --dhcp-host .B --dhcp-host
contenant les mêmes informations. /etc/ethers est relu à la réception d'un contenant les mêmes informations. /etc/ethers est relu à la réception d'un
signal SIGHUP par Dnsmasq. signal SIGHUP par Dnsmasq. Les adresses IPv6 ne sont PAS lues dans /etc/ethers.
.TP .TP
.B \-O, --dhcp-option=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>],[<valeur>[,<valeur>]] .B \-O, --dhcp-option=[tag:<label>,[tag:<label>]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>|option6:<option>|option6:<nom d'option>],[<valeur>[,<valeur>]]
Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par
défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le
masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte
sur lequel tourne Dnsmasq, et le serveur DNS ainsi que la route par défaut sur lequel tourne Dnsmasq, et le serveur DNS ainsi que la route par défaut
prennent comme valeur l'adresse de la machine sur laquelle tourne Dnsmasq. Si prennent comme valeur l'adresse de la machine sur laquelle tourne Dnsmasq.
une option de nom de domaine a été définie, son contenu est transmis. Cette (Des règles équivalentes s'appliquent en IPv6). Si une option de nom de domaine
option de configuration permet de changer toutes ces valeurs par défaut, ou de a été définie, son contenu est transmis. Cette option de configuration permet
spécifier d'autres options. L'option DHCP à transmettre peut être fournie sous de changer toutes ces valeurs par défaut, ou de spécifier d'autres options.
forme d'un nombre décimal ou sous la forme "option:<nom d'option>". Les nombres L'option DHCP à transmettre peut être fournie sous forme d'un nombre décimal
correspondants aux options sont définis dans la RFC2132 et suivants. Les noms ou sous la forme "option:<nom d'option>". Les nombres correspondants aux options
d'options connus par Dnsmasq peuvent être obtenus via "Dnsmasq --help dhcp". sont définis dans la RFC2132 et suivants. Les noms d'options connus par Dnsmasq
Par exemple, pour définir la route par défaut à 192.168.4.4, il est possible de peuvent être obtenus via "Dnsmasq --help dhcp". Par exemple, pour définir la
faire route par défaut à 192.168.4.4, il est possible de faire
.B --dhcp-option=3,192.168.4.4 .B --dhcp-option=3,192.168.4.4
ou ou
.B --dhcp-option = option:router, 192.168.4.4 .B --dhcp-option = option:router, 192.168.4.4
@@ -788,6 +815,13 @@ de l'option 120 sont traités conforméments à la RFC 3361. Les adresses IP sou
forme de 4 chiffres séparés par des points suivies par une barre montante "/", forme de 4 chiffres séparés par des points suivies par une barre montante "/",
puis une taille de masque sont encodés conforméments à la RFC 3442. puis une taille de masque sont encodés conforméments à la RFC 3442.
Les options IPv6 sont fournies en utilisant le mot-clef
.B option6:
suivi par le numéro d'option ou le nom d'option. L'espace de nommage des options
IPv6 est disjint de l'espace de nommage des options IPv4. Les adresses IPv6
en option doivent être entourées de crochets, comme par exemple :
.B --dhcp-option=option6:ntp-server,[1234::56]
Attention : aucun test n'étant fait pour vérifier que des données d'un type Attention : aucun test n'étant fait pour vérifier que des données d'un type
adéquat sont envoyées pour un numéro d'option donné, il est tout à fait possible adéquat sont envoyées pour un numéro d'option donné, il est tout à fait possible
de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation de persuader Dnsmasq de générer des paquets DHCP illégaux par une utilisation
@@ -806,8 +840,8 @@ d'une chaîne de caractères comme nom de serveur TFTP, il est nécessaire de fa
comme suit : comme suit :
.B --dhcp-option=66,"1.2.3.4" .B --dhcp-option=66,"1.2.3.4"
Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées en Les options encapsulées de classes de vendeurs peuvent-être aussi spécifiées
utilisant (pour IPv4 seulement) en utilisant
.B --dhcp-option .B --dhcp-option
: par exemple : par exemple
.B --dhcp-option=vendor:PXEClient,1,0.0.0.0 .B --dhcp-option=vendor:PXEClient,1,0.0.0.0
@@ -823,7 +857,7 @@ par le client. Il est possible d'omettre complètement une classe de vendeur :
.B --dhcp-option=vendor:,1,0.0.0.0 .B --dhcp-option=vendor:,1,0.0.0.0
Dans ce cas l'option encapsulée est toujours envoyée. Dans ce cas l'option encapsulée est toujours envoyée.
Les options peuvent-être encapsulées au sein d'autres options : En IPv4, les options peuvent-être encapsulées au sein d'autres options :
par exemple par exemple
.B --dhcp-option=encap:175, 190, "iscsi-client0" .B --dhcp-option=encap:175, 190, "iscsi-client0"
enverra l'option 175, au sein de laquelle se trouve l'option 190. enverra l'option 175, au sein de laquelle se trouve l'option 190.
@@ -836,7 +870,8 @@ identifiant le vendeur" ("Vendor-Identifying Vendor Options") telle que
décrite dans le RFC3925. Celles-ci sont spécifiées comme suit : décrite dans le RFC3925. Celles-ci sont spécifiées comme suit :
.B --dhcp-option=vi-encap:2, 10, "text" .B --dhcp-option=vi-encap:2, 10, "text"
Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant
à identifier cette option. à identifier cette option. Cette forme d'encapsulation est également supportée
en IPv6.
L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans
une option encapsulée. une option encapsulée.
@@ -849,8 +884,8 @@ dans la liste de paramêtres requis. Cela est parfois nécessaire, par exemple l
de la fourniture d'options à PXELinux. de la fourniture d'options à PXELinux.
.TP .TP
.B --dhcp-no-override .B --dhcp-no-override
Désactive la réutilisation des champs DHCP nom de serveur et nom de (IPv4 seulement) Désactive la réutilisation des champs DHCP nom de serveur et
fichier comme espace supplémentaire pour les options. Si cela est nom de fichier comme espace supplémentaire pour les options. Si cela est
possible, dnsmasq déplace les informations sur le serveur de démarrage possible, dnsmasq déplace les informations sur le serveur de démarrage
et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs et le nom de fichier (fournis par 'dhcp-boot') en dehors des champs
dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est dédiés à cet usage dans les options DHCP. Cet espace supplémentaire est
@@ -859,7 +894,8 @@ quelques rares cas, perturber des clients vieux ou défectueux. Cette
option force le comportement à l'utilisation des valeurs "simples et sûres" option force le comportement à l'utilisation des valeurs "simples et sûres"
afin d'éviter des problèmes dans de tels cas. afin d'éviter des problèmes dans de tels cas.
.TP .TP
.B \-U, --dhcp-vendorclass=set:<label>,<classe de vendeur> .B \-U, --dhcp-vendorclass=set:<label>,[enterprise:<numéro IANA d'enterprise>,]<classe de vendeur>
Associe une chaîne de classe de vendeur à un label. La plupart Associe une chaîne de classe de vendeur à un label. La plupart
des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui des clients DHCP fournissent une "classe de vendeur" ("vendor class") qui
représente, d'une certaine façon, le type d'hôte. Cette option associe des représente, d'une certaine façon, le type d'hôte. Cette option associe des
@@ -875,6 +911,11 @@ en temps que sous-chaîne de caractères au sein de la classe de vendeur fournie
par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne par le client, de façon à permettre la recherche d'un sous-ensemble de la chaîne
de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé de caractères ("fuzzy matching"). Le préfixe set: est optionnel mais autorisé
afin de conserver une certaine homogénéité. afin de conserver une certaine homogénéité.
Notez qu'en IPv6 (et seulement en IPv6), les noms de classes de vendeurs
sont dans un espace de nom associé au numéro attribué à l'entreprise par
l'IANA. Ce numéro est fourni par le biais du mot-clef enterprise: et seules
les classes de vendeurs associées au numéro spécifié seront cherchées.
.TP .TP
.B \-j, --dhcp-userclass=set:<label>,<classe utilisateur> .B \-j, --dhcp-userclass=set:<label>,<classe utilisateur>
Associe une chaîne de classe d'utilisateur à un label (effectue la Associe une chaîne de classe d'utilisateur à un label (effectue la
@@ -887,7 +928,7 @@ d'impression différent pour les hôtes de la classe "comptes" et ceux de la
classe "ingénierie". classe "ingénierie".
.TP .TP
.B \-4, --dhcp-mac=set:<label>,<adresse MAC> .B \-4, --dhcp-mac=set:<label>,<adresse MAC>
Associe une adresse matérielle (MAC) à un label. L'adresse (IPv4 uniquement) Associe une adresse matérielle (MAC) à un label. L'adresse
matérielle peut inclure des jokers. Par exemple matérielle peut inclure des jokers. Par exemple
.B --dhcp-mac=set:3com,01:34:23:*:*:* .B --dhcp-mac=set:3com,01:34:23:*:*:*
permet de définir le label "3com" pour n'importe quel hôte dont l'adresse permet de définir le label "3com" pour n'importe quel hôte dont l'adresse
@@ -901,16 +942,19 @@ chaîne de valeurs hexadécimales séparées par des ":", mais il est également
possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si possible qu'elle le soit sous la forme d'une simple chaîne de caractères. Si
l'identifiant de circuit ou d'agent correspond exactement à celui fourni par le l'identifiant de circuit ou d'agent correspond exactement à celui fourni par le
relais DHCP, alors le label est apposé. relais DHCP, alors le label est apposé.
.B dhcp-remoteid
est supporté en IPv6 (mais non dhcp-circuitid).
.TP .TP
.B --dhcp-subscrid=set:<label>,<identifiant d'abonné> .B --dhcp-subscrid=set:<label>,<identifiant d'abonné>
Associe des options de relais DHCP issues de la RFC3993 à des labels. (IPv4 et IPv6) Associe des options de relais DHCP issues de la RFC3993 à des
labels.
.TP .TP
.B --dhcp-proxy[=<adresse ip>]...... .B --dhcp-proxy[=<adresse ip>]......
Un agent relai DHCP normal est uniquement utilisé pour faire suivre les (IPv4 seulement) Un agent relai DHCP normal est uniquement utilisé pour faire
éléments initiaux de l'interaction avec le serveur DHCP. Une fois que le suivre les éléments initiaux de l'interaction avec le serveur DHCP. Une fois
client est configuré, il communique directement avec le serveur. Cela n'est pas que le client est configuré, il communique directement avec le serveur. Cela
souhaitable si le relais rajoute des informations supplémentaires aux paquets n'est pas souhaitable si le relais rajoute des informations supplémentaires
DHCP, telles que celles utilisées dans aux paquets DHCP, telles que celles utilisées dans
.B dhcp-circuitid .B dhcp-circuitid
et et
.B dhcp-remoteid. .B dhcp-remoteid.
@@ -973,26 +1017,28 @@ configuration dhcp-host de Dnsmasq, ainsi que le contenu des fichiers /etc/hosts
et /etc/ethers. et /etc/ethers.
.TP .TP
.B --dhcp-generate-names=tag:<label>[,tag:<label>] .B --dhcp-generate-names=tag:<label>[,tag:<label>]
Générer un nom pour les clients DHCP qui autrement n'en aurait pas, en (IPv4 seulement) Générer un nom pour les clients DHCP qui autrement n'en aurait
utilisant l'adresse MAC sous sa forme hexadécimale, séparée par des tirets. pas, en utilisant l'adresse MAC sous sa forme hexadécimale, séparée par des
tirets.
Noter que si un hôte fourni un nom, celui-ci sera utilisé de préférence au nom Noter que si un hôte fourni un nom, celui-ci sera utilisé de préférence au nom
autogénéré, à moins que autogénéré, à moins que
.B --dhcp-ignore-names .B --dhcp-ignore-names
ne soit positionné. ne soit positionné.
.TP .TP
.B --dhcp-broadcast=[tag:<label>[,tag:<label>]] .B --dhcp-broadcast=[tag:<label>[,tag:<label>]]
Lorsque tous les labels fournis dans l'option sont présents, toujours utiliser (IPv4 seulement) Lorsque tous les labels fournis dans l'option sont présents,
le broadcast pour communiquer avec l'hôte lorsque celui-ci n'est toujours utiliser le broadcast pour communiquer avec l'hôte lorsque celui-ci
pas configuré. Il est possible de ne spécifier aucun label, auquel cas cette n'est pas configuré. Il est possible de ne spécifier aucun label, auquel cas
option s'applique inconditionnellement. La plupart des clients DHCP nécessitant une réponse par le biais cette option s'applique inconditionnellement. La plupart des clients DHCP
d'un broadcast activent une option dans leur requête, ce qui fait que cela nécessitant une réponse par le biais d'un broadcast activent une option dans
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP. leur requête, ce qui fait que cela se fait automatiquement, mais ce n'est pas
le cas de certains vieux clients BOOTP.
.TP .TP
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]] .B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de (IPv4 seulement) Spécifie les options BOOTP devant être retournées par le
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom serveur DHCP. Le nom de serveur ainsi que l'adresse sont optionnels : s'ils
est laissé vide et l'adresse fournie est celle de la machine sur laquelle ne sont pas fournis, le nom est laissé vide et l'adresse fournie est celle de
s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir la machine sur laquelle s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
.B --enable-tftp .B --enable-tftp
), alors seul un nom de fichier est requis ici pour permettre un démarrage par ), alors seul un nom de fichier est requis ici pour permettre un démarrage par
le réseau. le réseau.
@@ -1018,7 +1064,7 @@ Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
cette option ne devrait pas être utilisée dans un cas général. cette option ne devrait pas être utilisée dans un cas général.
.TP .TP
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>] .B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>|<nom de serveur>]
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
obtention d'une adresse IP, le téléchargement du fichier spécifié dans obtention d'une adresse IP, le téléchargement du fichier spécifié dans
.B dhcp-boot .B dhcp-boot
@@ -1036,17 +1082,20 @@ client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
(l'option (l'option
.B enable-tftp .B enable-tftp
doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP
si une adresse de serveur est fournie. si une adresse ou un nom de serveur est fournie.
Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE
et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière
est fournir pour le type de démarrage, en remplacement du nom de fichier, le est fournir pour le type de démarrage, en remplacement du nom de fichier, le
client PXE devra chercher un service de démarrage de ce type sur le réseau. client PXE devra chercher un service de démarrage de ce type sur le réseau.
Cette recherche peut être faite via broadcast ou directement auprès d'un Cette recherche peut être faite via broadcast ou directement auprès d'un
serveur si son adresse IP est fournie dans l'option. serveur si son adresse IP ou son nom sont fournis dans l'option.
Si aucun nom de fichier n'est donné ni aucune valeur de type de service de Si aucun nom de fichier n'est donné ni aucune valeur de type de service de
démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
service), alors l'entrée de menu provoque l'interruption du démarrage par service), alors l'entrée de menu provoque l'interruption du démarrage par
le réseau et la poursuite du démarrage sur un média local. le réseau et la poursuite du démarrage sur un média local. L'adresse de serveur
peut être donnée sous la forme de nom de domaine qui est recherché dans
/etc/hosts. Ce nom peut-être associé à plusieurs adresses IP, qui dans ce cas
sont utilisées à tour de rôle (en "round-robin").
.TP .TP
.B --pxe-prompt=[tag:<label>,]<invite>[,<délai>] .B --pxe-prompt=[tag:<label>,]<invite>[,<délai>]
Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un
@@ -1079,38 +1128,39 @@ créant des milliers de baux et utilisant beaucoup de mémoire dans le processus
Dnsmasq. Dnsmasq.
.TP .TP
.B \-K, --dhcp-authoritative .B \-K, --dhcp-authoritative
Cette option doit être donnée lorsque Dnsmasq est le seul serveur DHCP sur le (IPv4 seulement) Cette option doit être donnée lorsque Dnsmasq est le seul
réseau. Cela change le comportement par défaut qui est celui d'un strict respect serveur DHCP sur le réseau. Cela change le comportement par défaut qui est
des RFC, afin que les requêtes DHCP pour des baux inconnus par des hôtes celui d'un strict respect des RFC, afin que les requêtes DHCP pour des baux
inconnus ne soient pas ignorées. Cela permet à de nouveaux hôtes d'obtenir des inconnus par des hôtes inconnus ne soient pas ignorées. Cela permet à de
baux sans tenir compte de fastidieuses temporisations ("timeout"). Cela permet nouveaux hôtes d'obtenir des baux sans tenir compte de fastidieuses
également à Dnsmasq de reconstruire sa base de donnée contenant les baux sans temporisations ("timeout"). Cela permet également à Dnsmasq de reconstruire
que les clients n'aient besoin de redemander un bail, si celle-ci est perdue. sa base de données contenant les baux sans que les clients n'aient besoin de
redemander un bail, si celle-ci est perdue.
.TP .TP
.B --dhcp-alternate-port[=<port serveur>[,<port client>]] .B --dhcp-alternate-port[=<port serveur>[,<port client>]]
Change les ports utilisés par défaut pour le DHCP. Si cette option est donnée (IPv4 seulement) Change les ports utilisés par défaut pour le DHCP. Si cette
toute seule sans arguments, alors change les ports utilisés pour le DHCP option est donnée seule sans argument, alors change les ports utilisés pour le
de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce DHCP de 67 et 68 respectivement à 1067 et 1068. Si un seul argument est donné, ce
numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour le
port client. Enfin, en fournissant deux numéros de ports, il est possible de port client. Enfin, en fournissant deux numéros de ports, il est possible de
spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP. spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
.TP .TP
.B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]] .B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]]
Permet l'allocation dynamique d'adresses IP à des clients BOOTP. Utiliser cette (IPv4 seulement) Permet l'allocation dynamique d'adresses IP à des clients BOOTP.
option avec précaution, une adresse allouée à un client BOOTP étant perpétuelle, Utiliser cette option avec précaution, une adresse allouée à un client BOOTP
et de fait n'est plus disponibles pour d'autres hôtes. Si aucun argument n'est étant perpétuelle, et de fait n'est plus disponibles pour d'autres hôtes. Si
donné, alors cette option permet une allocation dynamique dans tous les cas. Si aucun argument n'est donné, alors cette option permet une allocation dynamique
des arguments sont spécifiés, alors l'allocation ne se fait que lorsque tous dans tous les cas. Si des arguments sont spécifiés, alors l'allocation ne se
les identifiants coïncident. Il est possible de répeter cette option avec fait que lorsque tous les identifiants coïncident. Il est possible de répeter
plusieurs jeux d'arguments. cette option avec plusieurs jeux d'arguments.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
Par défaut, le serveur DHCP tente de s'assurer qu'une adresse n'est pas utilisée (IPv4 seulement) Par défaut, le serveur DHCP tente de s'assurer qu'une adresse
avant de l'allouer à un hôte. Cela est fait en envoyant une requête ICMP de type n'est pas utilisée avant de l'allouer à un hôte. Cela est fait en envoyant une
"echo request" (aussi connue sous le nom de "ping") à l'adresse en question. Si requête ICMP de type "echo request" (aussi connue sous le nom de "ping") à
le serveur obtient une réponse, alors l'adresse doit déjà être utilisée et une l'adresse en question. Si le serveur obtient une réponse, alors l'adresse doit
autre est essayée. Cette option permet de supprimer cette vérification. A déjà être utilisée et une autre est essayée. Cette option permet de supprimer
utiliser avec précaution. cette vérification. A utiliser avec précaution.
.TP .TP
.B --log-dhcp .B --log-dhcp
Traces additionnelles pour le service DHCP : enregistre toutes les options Traces additionnelles pour le service DHCP : enregistre toutes les options
@@ -1127,11 +1177,11 @@ chemin est spécifié est exécuté. Le <chemin de fichier> doit être un chemi
absolu, aucune recherche n'est effectuée via la variable d'environnement PATH. absolu, aucune recherche n'est effectuée via la variable d'environnement PATH.
Les arguments fournis à celui-ci sont soit Les arguments fournis à celui-ci sont soit
"add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse "add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse
MAC de l'hôte puis l'adresse IP et le nom d'hôte si celui-ci est MAC de l'hôte (ou le DUID pour IPv6) puis l'adresse IP et le nom d'hôte si
connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a été supprimé, celui-ci est connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a
"old" notifie que le bail existait au lancement de Dnsmasq, ou un changement été supprimé, "old" notifie que le bail existait au lancement de Dnsmasq, ou un
d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas où changement d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas
leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant où leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant
d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est
nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab" nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab"
pour du token ring. Le processus est exécuté en temps que super-utilisateur pour du token ring. Le processus est exécuté en temps que super-utilisateur
@@ -1141,18 +1191,16 @@ pour changer son UID pour celle d'un utilisateur non-privilégié.
L'environnement est hérité de celui de l'invocation du processus Dnsmasq, L'environnement est hérité de celui de l'invocation du processus Dnsmasq,
auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous : auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client. Pour IPv4 et IPv6 :
DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
argument au script n'est jamais pleinement qualifié). argument au script n'est jamais pleinement qualifié).
Si le client fournit une information de classe de vendeur, un nom d'hôte, ou Si le client fournit un nom d'hôte, DNSMASQ_SUPPLIED_HOSTNAME.
des classes d'utilisateur, celles-ci sont fournies dans les
variables DNSMASQ_VENDOR_CLASS et DNSMASQ_USER_CLASS0 à DNSMASQ_USER_CLASSn Si le client fournit des classes d'utilisateur, DNSMASQ_USER_CLASS0 à
et DNSMASQ_SUPPLIED_HOSTNAME respectivement, mais seulement pour les actions DNSMASQ_USER_CLASSn.
"add" et "old" lorsqu'un hôte reprend un bail existant, ces variables n'étant
pas stockées dans la base de baux de Dnsmasq.
Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC ("horloge RTC Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC ("horloge RTC
défectueuse"), alors la durée du bail (en secondes) est stockée dans la défectueuse"), alors la durée du bail (en secondes) est stockée dans la
@@ -1175,6 +1223,29 @@ relai DHCP pour contacter Dnsmasq, si l'adresse IP du relai est connue.
DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP, DNSMASQ_TAGS contient tous les labels fournis pendant la transaction DHCP,
séparés par des espaces. séparés par des espaces.
Pour IPv4 seulement :
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
Si le client fournit une information de classe de vendeur, DNSMASQ_VENDOR_CLASS.
Pour IPv6 seulement :
Si le client fournit une classe de vendeur (vendor-class), positionne
DNSMASQ_VENDOR_CLASS_ID avec comme contenu le numéro IANA de l'entreprise pour
la classe, et DNSMASQ_VENDOR_CLASS0..DNSMASQ_VENDOR_CLASSn pour les données.
DNSMASQ_SERVER_DUID contient le DUID du serveur : cette valeur est la même
pour chaque appel au script.
DNSMASQ_IAID contenant l'IAID pour le bail. Si le bail est une allocation
temporaire, cela est préfixé par le caractère 'T'.
A noter que le nom d'hôte fourni, la classe de vendeur ou les données de classe
d'utilisateur sont uniquement fournies pour les actions "add" ou l'action "old"
lorsqu'un hôte reprend un bail existant, puisque ces informations ne sont pas
conservées dans la base de baux de dnsmasq.
Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
sont ouverts sur /dev/null (sauf en mode déverminage). sont ouverts sur /dev/null (sauf en mode déverminage).
@@ -1191,11 +1262,50 @@ Au démarrage de Dnsmasq, le script sera invoqué pour chacun des baux existants
dans le fichier des baux. Le script sera lancé avec l'action "del" pour les dans le fichier des baux. Le script sera lancé avec l'action "del" pour les
baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP, baux expirés, et "old" pour les autres. Lorsque Dnsmasq reçoit un signal HUP,
le script sera invoqué avec une action "old" pour tous les baux existants. le script sera invoqué avec une action "old" pour tous les baux existants.
.TP .TP
.B --dhcp-luascript=<chemin>
Spécifie un script écrit en Lua, devant être exécuté lorsque des baux sont
créés, détruits ou modifiés. Pour utiliser cette option, dnsmasq doit être
compilé avec avec le support de Lua. L'interpréteur Lua est initialisé une
seule fois, lorsque dnsmasq démarre, ce qui fait que les variables globales
persistent entre les évênements liés aux baux. Le code Lua doit définir une
fonction
.B lease
et peut fournir des fonctions
.B init
et
.B shutdown
qui sont appellées, sans arguments, lorsque dnsmasq démarre ou s'arrête.
La méthode
.B lease
reçoit les informations détaillées dans
.B --dhcp-script.
Il reçoit deux arguments. Le premier spécifie l'action, qui est une chaîne de
caractères contenant les valeurs "add" (ajout), "old" (réactivation d'un bail
existant) ou "del" (suppression). Le deuxième est une table contenant des
paires de valeurs de labels. Les labels correspondent pour l'essentiel aux
valeurs d'environnement détaillées ci-dessus, ainsi le label "domain" (domaine)
contient les mêmes données que la variable d'environnement DNSMASQ_DOMAIN. Il
existe quelques labels supplémentaires contenant les données fournies comme
arguments à
.B --dhcp-script.
Ces labels sont
.B mac_address, ip_address
(pour respectivement l'adresse MAC et l'adresse IP)
et
.B hostname
(le nom d'hôte) dans le cas d'IPv4, et
.B client_duid, ip_address
(valeur DUID du client et adresse IP respectivement)
ainsi que
.B hostname
(le nom d'hôte) dans le cas d'IPv6.
.TP
.B --dhcp-scriptuser .B --dhcp-scriptuser
Spécifie l'utilisateur sous lequel le script lease-change doit être exécuté. La Spécifie l'utilisateur sous lequel le script shell lease-change ou le script
valeur par défaut correspond à l'utilisateur root mais peut-être changée par le doivent être exécutés. La valeur par défaut correspond à l'utilisateur root
biais de cette option. mais peut-être changée par le biais de cette option.
.TP .TP
.B \-9, --leasefile-ro .B \-9, --leasefile-ro
Supprimer complètement l'usage du fichier servant de base de donnée pour les Supprimer complètement l'usage du fichier servant de base de donnée pour les
@@ -1280,6 +1390,32 @@ sans gamme d'adresses de spécifié lorsque l'option
.B --dhcp-fqdn .B --dhcp-fqdn
est configurée. est configurée.
.TP .TP
.B --dhcp-client-update
Normalement, lorsque dnsmasq fournit un bail DHCP, il positionne un label
dans l'option FQDN pour indiquer au client qu'il ne doit pas tenter de faire
une mise à jour DDNS avec son nom et son adresse IP. Ceci parce que la paire
Nom-IP est rajoutée automatiquement dans la partie DNS de dnsmasq. Cette option
inhibe ce comportement ce qui est utile, par exemple, pour permettre aux clients
Windows de la mise à jour de serveurs Active Directory. Voir la RFC 4702 pour
plus de détails.
.TP
.B --enable-ra
Active la fonctionalité d'annonces routeurs IPv6 ("IPv6 Router Advertisement").
DHCPv6 ne gère pas la configuration complète du réseau de la même façon que
DHCPv4. La découverte de routeurs et la découverte (éventuelle) de préfixes pour
la création autonome d'adresse sont gérées par un protocole différent.
Lorsque DHCP est utilisé, seul un sous-ensemble de tout ceci est nécessaire et
dnsmasq est à même de le gérer, en utilisant la configuration DHCP présente pour
fournir la majorité des données. Lorsque les annonces routeurs (RA pour "Router
Advertisement") sont activées, dnsmasq va annoncer un préfixe pour chaque
dhcp-range et, par défaut, fournir comme valeur de routeur et de DNS récursif
la valeur d'adresse link-local appropriée parmi celles de la machine sur
laquelle tourne dnsmasq.
Les bits "managed address" sont positionnés, sauf pour un dhcp-range marqué
comme "ra-only" (annonce routeur uniquement). Dans ce cas le service d'annonce
routeur est rendu mais aucun service DHCPv6 n'est assuré, et les bits "managed
address" ne sont pas positionnés.
.TP
.B --enable-tftp[=<interface>] .B --enable-tftp[=<interface>]
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul fonctions nécessaires au démarrage par le réseau ("net-boot") d'un client. Seul
@@ -1547,10 +1683,6 @@ ligne de commande au lieu d'un fichier de configuration, ne pas oublier
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
shell). shell).
+When selecting dhcp-options, a tag from dhcp-range is second class
+relative to other tags, to make it easy to override options for
+individual hosts, so
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
passe après les autres étiquettes, ce qui permet de facilement remplacer des passe après les autres étiquettes, ce qui permet de facilement remplacer des
option génériques pour des hôtes spécifiques, ainsi : option génériques pour des hôtes spécifiques, ainsi :
+421 -357
View File
File diff suppressed because it is too large. Load diff
+538 -474
View File
File diff suppressed because it is too large. Load diff
+537 -478
View File
File diff suppressed because it is too large. Load diff
+553 -495
View File
File diff suppressed because it is too large. Load diff
+569 -501
View File
File diff suppressed because it is too large. Load diff
+537 -478
View File
File diff suppressed because it is too large. Load diff
+535 -474
View File
File diff suppressed because it is too large. Load diff
+584 -495
View File
File diff suppressed because it is too large. Load diff
+537 -478
View File
File diff suppressed because it is too large. Load diff
+535 -474
View File
File diff suppressed because it is too large. Load diff
-2
View File
@@ -1,2 +0,0 @@
Worry about IPv6 leases and DUID in script-storage.
+62 -95
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -17,19 +17,9 @@
#include "dnsmasq.h" #include "dnsmasq.h"
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) #if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
#include <ifaddrs.h>
static struct iovec ifconf = {
.iov_base = NULL,
.iov_len = 0
};
static struct iovec ifreq = {
.iov_base = NULL,
.iov_len = 0
};
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
#include <sys/sysctl.h> #include <sys/sysctl.h>
#include <net/route.h> #include <net/route.h>
#include <net/if_dl.h> #include <net/if_dl.h>
@@ -50,8 +40,12 @@ int arp_enumerate(void *parm, int (*callback)())
struct rt_msghdr *rtm; struct rt_msghdr *rtm;
struct sockaddr_inarp *sin2; struct sockaddr_inarp *sin2;
struct sockaddr_dl *sdl; struct sockaddr_dl *sdl;
struct iovec buff;
int rc; int rc;
buff.iov_base = NULL;
buff.iov_len = 0;
mib[0] = CTL_NET; mib[0] = CTL_NET;
mib[1] = PF_ROUTE; mib[1] = PF_ROUTE;
mib[2] = 0; mib[2] = 0;
@@ -67,9 +61,9 @@ int arp_enumerate(void *parm, int (*callback)())
while (1) while (1)
{ {
if (!expand_buf(&ifconf, needed)) if (!expand_buf(&buff, needed))
return 0; return 0;
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 || if ((rc = sysctl(mib, 6, buff.iov_base, &needed, NULL, 0)) == 0 ||
errno != ENOMEM) errno != ENOMEM)
break; break;
needed += needed / 8; needed += needed / 8;
@@ -77,7 +71,7 @@ int arp_enumerate(void *parm, int (*callback)())
if (rc == -1) if (rc == -1)
return 0; return 0;
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen) for (next = buff.iov_base ; next < (char *)buff.iov_base + needed; next += rtm->rtm_msglen)
{ {
rtm = (struct rt_msghdr *)next; rtm = (struct rt_msghdr *)next;
sin2 = (struct sockaddr_inarp *)(rtm + 1); sin2 = (struct sockaddr_inarp *)(rtm + 1);
@@ -88,19 +82,14 @@ int arp_enumerate(void *parm, int (*callback)())
return 1; return 1;
} }
#endif #endif
int iface_enumerate(int family, void *parm, int (*callback)()) int iface_enumerate(int family, void *parm, int (*callback)())
{ {
char *ptr; struct ifaddrs *head, *addrs;
struct ifreq *ifr; int errsav, ret = 0;
struct ifconf ifc;
int fd, errsav, ret = 0;
int lastlen = 0;
size_t len = 0;
if (family == AF_UNSPEC) if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) #if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
return arp_enumerate(parm, callback); return arp_enumerate(parm, callback);
@@ -108,88 +97,69 @@ int iface_enumerate(int family, void *parm, int (*callback)())
return 0; /* need code for Solaris and MacOS*/ return 0; /* need code for Solaris and MacOS*/
#endif #endif
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) /* AF_LINK doesn't exist in Linux, so we can't use it in our API */
if (family == AF_LOCAL)
family = AF_LINK;
if (getifaddrs(&head) == -1)
return 0; return 0;
while(1)
{
len += 10*sizeof(struct ifreq);
if (!expand_buf(&ifconf, len))
goto err;
ifc.ifc_len = len;
ifc.ifc_buf = ifconf.iov_base;
if (ioctl(fd, SIOCGIFCONF, &ifc) == -1)
{
if (errno != EINVAL || lastlen != 0)
goto err;
}
else
{
if (ifc.ifc_len == lastlen)
break; /* got a big enough buffer now */
lastlen = ifc.ifc_len;
}
}
for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
{
/* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about
unaligned accesses. */
len = sizeof(struct ifreq); for (addrs = head; addrs; addrs = addrs->ifa_next)
{
#ifdef HAVE_SOCKADDR_SA_LEN if (addrs->ifa_addr->sa_family == family)
ifr = (struct ifreq *)ptr;
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#endif
if (!expand_buf(&ifreq, len))
goto err;
ifr = (struct ifreq *)ifreq.iov_base;
memcpy(ifr, ptr, len);
if (ifr->ifr_addr.sa_family == family)
{ {
int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0)
continue;
if (family == AF_INET) if (family == AF_INET)
{ {
struct in_addr addr, netmask, broadcast; struct in_addr addr, netmask, broadcast;
broadcast.s_addr = 0; addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1) broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
continue; if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
if (!((*callback)(addr,
(int)if_nametoindex(ifr->ifr_name),
netmask, broadcast,
parm)))
goto err; goto err;
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (family == AF_INET6) else if (family == AF_INET6)
{ {
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr; struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
int i, j, prefix = 0;
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
break;
/* voodoo to clear interface field in address */ /* voodoo to clear interface field in address */
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr)) if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
{ {
addr->s6_addr[2] = 0; addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0; addr->s6_addr[3] = 0;
} }
/* We have no way to determine the prefix, so we assume it's 64 for now....... */
if (!((*callback)(addr, 64, if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id, goto err;
(int)if_nametoindex(ifr->ifr_name), 0, }
parm))) #endif
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
/* Assume ethernet again here */
struct sockaddr_dl *sdl = (struct sockaddr_dl *) addrs->ifa_addr;
if (sdl->sdl_alen != 0 &&
!((*callback)(iface_index, ARPHRD_ETHER, LLADDR(sdl), sdl->sdl_alen, parm)))
goto err; goto err;
} }
#endif #endif
} }
} }
@@ -197,7 +167,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
err: err:
errsav = errno; errsav = errno;
close(fd); freeifaddrs(head);
errno = errsav; errno = errsav;
return ret; return ret;
@@ -214,13 +184,10 @@ void init_bpf(void)
while (1) while (1)
{ {
/* useful size which happens to be sufficient */ sprintf(daemon->dhcp_buff, "/dev/bpf%d", i++);
if (expand_buf(&ifreq, sizeof(struct ifreq))) if ((daemon->dhcp_raw_fd = open(daemon->dhcp_buff, O_RDWR, 0)) != -1)
{ return;
sprintf(ifreq.iov_base, "/dev/bpf%d", i++);
if ((daemon->dhcp_raw_fd = open(ifreq.iov_base, O_RDWR, 0)) != -1)
return;
}
if (errno != EBUSY) if (errno != EBUSY)
die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET); die(_("cannot create DHCP BPF socket: %s"), NULL, EC_BADNET);
} }
+96 -60
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -635,11 +635,12 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
} }
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
unsigned short flags, int index, int addr_dup) unsigned short flags, int index, struct crec **rhash, int hashsz)
{ {
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6)); struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
int i, nameexists = 0; int i, nameexists = 0;
struct cname *a; struct cname *a;
unsigned int j;
/* Remove duplicates in hosts files. */ /* Remove duplicates in hosts files. */
if (lookup && (lookup->flags & F_HOSTS)) if (lookup && (lookup->flags & F_HOSTS))
@@ -653,33 +654,39 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
} }
/* Ensure there is only one address -> name mapping (first one trumps) /* Ensure there is only one address -> name mapping (first one trumps)
We do this by steam here, first we see if the address is the same as We do this by steam here, The entries are kept in hash chains, linked
the last one we saw, which eliminates most in the case of an ad-block by ->next (which is unused at this point) held in hash buckets in
file with thousands of entries for the same address. the array rhash, hashed on address. Note that rhash and the values
Then we search and bail at the first matching address that came from in ->next are only valid whilst reading hosts files: the buckets are
a HOSTS file. Since the first host entry gets reverse, we know then freed, and the ->next pointer used for other things.
then that it must exist without searching exhaustively for it. */
Only insert each unique address once into this hashing structure.
This complexity avoids O(n^2) divergent CPU use whilst reading
large (10000 entry) hosts files. */
if (addr_dup) /* hash address */
flags &= ~F_REVERSE; for (j = 0, i = 0; i < addrlen; i++)
else j = (j*2 +((unsigned char *)addr)[i]) % hashsz;
for (i=0; i<hash_size; i++)
for (lookup = rhash[j]; lookup; lookup = lookup->next)
if ((lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{ {
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next) flags &= ~F_REVERSE;
if ((lookup->flags & F_HOSTS) && break;
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break;
}
if (lookup)
break;
} }
/* maintain address hash chain, insert new unique address */
if (!lookup)
{
cache->next = rhash[j];
rhash[j] = cache;
}
cache->flags = flags; cache->flags = flags;
cache->uid = index; cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen); memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache); cache_hash(cache);
/* don't need to do alias stuff for second and subsequent addresses. */ /* don't need to do alias stuff for second and subsequent addresses. */
@@ -743,14 +750,14 @@ static int gettok(FILE *f, char *token)
} }
} }
static int read_hostsfile(char *filename, int index, int cache_size) static int read_hostsfile(char *filename, int index, int cache_size, struct crec **rhash, int hashsz)
{ {
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "r");
char *token = daemon->namebuff, *domain_suffix = NULL; char *token = daemon->namebuff, *domain_suffix = NULL;
int addr_count = 0, name_count = cache_size, lineno = 0; int addr_count = 0, name_count = cache_size, lineno = 0;
unsigned short flags = 0, saved_flags = 0; unsigned short flags = 0;
struct all_addr addr, saved_addr; struct all_addr addr;
int atnl, addrlen = 0, addr_dup; int atnl, addrlen = 0;
if (!f) if (!f)
{ {
@@ -762,7 +769,6 @@ static int read_hostsfile(char *filename, int index, int cache_size)
while ((atnl = gettok(f, token)) != EOF) while ((atnl = gettok(f, token)) != EOF)
{ {
addr_dup = 0;
lineno++; lineno++;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@@ -776,7 +782,7 @@ static int read_hostsfile(char *filename, int index, int cache_size)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ; addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix; domain_suffix = get_domain6(&addr.addr.addr6);
} }
#else #else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1) if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
@@ -794,14 +800,6 @@ static int read_hostsfile(char *filename, int index, int cache_size)
continue; continue;
} }
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++; addr_count++;
/* rehash every 1000 names. */ /* rehash every 1000 names. */
@@ -832,14 +830,13 @@ static int read_hostsfile(char *filename, int index, int cache_size)
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
strcat(cache->name.sname, "."); strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix); strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup); add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
addr_dup = 1;
name_count++; name_count++;
} }
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME))) if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{ {
strcpy(cache->name.sname, canon); strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup); add_hosts_entry(cache, &addr, addrlen, flags, index, rhash, hashsz);
name_count++; name_count++;
} }
free(canon); free(canon);
@@ -861,7 +858,7 @@ static int read_hostsfile(char *filename, int index, int cache_size)
void cache_reload(void) void cache_reload(void)
{ {
struct crec *cache, **up, *tmp; struct crec *cache, **up, *tmp;
int i, total_size = daemon->cachesize; int revhashsz, i, total_size = daemon->cachesize;
struct hostsfile *ah; struct hostsfile *ah;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
@@ -895,14 +892,20 @@ void cache_reload(void)
my_syslog(LOG_INFO, _("cleared cache")); my_syslog(LOG_INFO, _("cleared cache"));
return; return;
} }
/* borrow the packet buffer for a temporary by-address hash */
memset(daemon->packet, 0, daemon->packet_buff_sz);
revhashsz = daemon->packet_buff_sz / sizeof(struct crec *);
/* we overwrote the buffer... */
daemon->srv_save = NULL;
if (!option_bool(OPT_NO_HOSTS)) if (!option_bool(OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, 0, total_size); total_size = read_hostsfile(HOSTSFILE, 0, total_size, (struct crec **)daemon->packet, revhashsz);
daemon->addn_hosts = expand_filelist(daemon->addn_hosts); daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
for (ah = daemon->addn_hosts; ah; ah = ah->next) for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE)) if (!(ah->flags & AH_INACTIVE))
total_size = read_hostsfile(ah->fname, ah->index, total_size); total_size = read_hostsfile(ah->fname, ah->index, total_size, (struct crec **)daemon->packet, revhashsz);
} }
char *get_domain(struct in_addr addr) char *get_domain(struct in_addr addr)
@@ -910,13 +913,33 @@ char *get_domain(struct in_addr addr)
struct cond_domain *c; struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next) 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)) ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain; return c->domain;
return daemon->domain_suffix; 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 #ifdef HAVE_DHCP
struct in_addr a_record_from_hosts(char *name, time_t now) struct in_addr a_record_from_hosts(char *name, time_t now)
{ {
@@ -950,15 +973,24 @@ void cache_unhash_dhcp(void)
up = &cache->hash_next; up = &cache->hash_next;
} }
void cache_add_dhcp_entry(char *host_name, void cache_add_dhcp_entry(char *host_name, int prot,
struct in_addr *host_address, time_t ttd) struct all_addr *host_address, time_t ttd)
{ {
struct crec *crec = NULL, *aliasc; 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; int in_hosts = 0;
struct cname *a; 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 */ /* check all addresses associated with name */
if (crec->flags & F_HOSTS) if (crec->flags & F_HOSTS)
@@ -966,23 +998,25 @@ void cache_add_dhcp_entry(char *host_name,
/* if in hosts, don't need DHCP record */ /* if in hosts, don't need DHCP record */
in_hosts = 1; in_hosts = 1;
inet_ntop(prot, host_address, daemon->addrbuff, ADDRSTRLEN);
if (crec->flags & F_CNAME) if (crec->flags & F_CNAME)
my_syslog(MS_DHCP | LOG_WARNING, my_syslog(MS_DHCP | LOG_WARNING,
_("%s is a CNAME, not giving it to the DHCP lease of %s"), _("%s is a CNAME, not giving it to the DHCP lease of %s"),
host_name, inet_ntoa(*host_address)); host_name, daemon->addrbuff);
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr) 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, my_syslog(MS_DHCP | LOG_WARNING,
_("not giving name %s to the DHCP lease of %s because " _("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"), "the name exists in %s with address %s"),
host_name, inet_ntoa(*host_address), host_name, daemon->addrbuff,
record_source(crec->uid), daemon->namebuff); record_source(crec->uid), daemon->namebuff);
} }
} }
else if (!(crec->flags & F_DHCP)) 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 */ /* scan_free deletes all addresses associated with name */
break; break;
} }
@@ -991,14 +1025,16 @@ void cache_add_dhcp_entry(char *host_name,
if (in_hosts) if (in_hosts)
return; 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) if (crec->flags & F_NEG)
cache_scan_free(NULL, (struct all_addr *)host_address, 0, F_IPV4 | F_REVERSE); {
else flags |= F_REVERSE;
/* avoid multiple reverse mappings */ cache_scan_free(NULL, (struct all_addr *)host_address, 0, flags);
flags &= ~F_REVERSE; }
} }
else
flags |= F_REVERSE;
if ((crec = dhcp_spare)) if ((crec = dhcp_spare))
dhcp_spare = dhcp_spare->next; dhcp_spare = dhcp_spare->next;
@@ -1007,12 +1043,12 @@ void cache_add_dhcp_entry(char *host_name,
if (crec) /* malloc may fail */ if (crec) /* malloc may fail */
{ {
crec->flags = flags; crec->flags = flags | F_NAMEP | F_DHCP | F_FORWARD;
if (ttd == 0) if (ttd == 0)
crec->flags |= F_IMMORTAL; crec->flags |= F_IMMORTAL;
else else
crec->ttd = ttd; crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address; crec->addr.addr = *host_address;
crec->name.namep = host_name; crec->name.namep = host_name;
crec->uid = uid++; crec->uid = uid++;
cache_hash(crec); cache_hash(crec);
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -116,7 +116,7 @@ RESOLVFILE
has no library dependencies other than libc */ has no library dependencies other than libc */
#define HAVE_DHCP #define HAVE_DHCP
/* #define HAVE_DHCP6 */ #define HAVE_DHCP6
#define HAVE_TFTP #define HAVE_TFTP
#define HAVE_SCRIPT #define HAVE_SCRIPT
/* #define HAVE_LUASCRIPT */ /* #define HAVE_LUASCRIPT */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
+19 -10
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -396,7 +396,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
DBusConnection *connection = (DBusConnection *)daemon->dbus; DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL; DBusMessage* message = NULL;
DBusMessageIter args; DBusMessageIter args;
char *action_str, *addr, *mac = daemon->namebuff; char *action_str, *mac = daemon->namebuff;
unsigned char *p; unsigned char *p;
int i; int i;
@@ -406,10 +406,21 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
if (!hostname) if (!hostname)
hostname = ""; hostname = "";
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len, #ifdef HAVE_DHCP6
lease->hwaddr, lease->clid_len, lease->clid, &i); if (lease->flags & (LEASE_TA | LEASE_NA))
print_mac(mac, p, i); {
print_mac(mac, lease->clid, lease->clid_len);
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
}
else
#endif
{
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
}
if (action == ACTION_DEL) if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted"; action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD) else if (action == ACTION_ADD)
@@ -419,14 +430,12 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
else else
return; return;
addr = inet_ntoa(lease->addr);
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str))) if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return; return;
dbus_message_iter_init_append(message, &args); dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) && if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &daemon->addrbuff) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) && dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname)) dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL); dbus_connection_send(connection, message, NULL);
+447
View File
@@ -0,0 +1,447 @@
/* 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 == msg->msg_iov->iov_len)
{
if (!expand_buf(msg->msg_iov, sz + 100))
return -1;
}
else
{
expand_buf(msg->msg_iov, 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, 128, 0))
{
memcpy(&config->addr6, &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
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct dhcp_context *context;
struct iname *tmp;
(void)prefix;
(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. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
if (!context)
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
#endif
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
+2 -177
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -119,43 +119,6 @@ void dhcp_init(void)
#endif #endif
check_dhcp_hosts(1); 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) 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; 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, int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now) 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)) is_addr_in_context(context, config))
return 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) for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config)) if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next) 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); 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 /* 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 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 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 #endif
+13 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -53,3 +53,15 @@
#define OPTION6_INTERFACE_ID 18 #define OPTION6_INTERFACE_ID 18
#define OPTION6_RECONFIGURE_MSG 19 #define OPTION6_RECONFIGURE_MSG 19
#define OPTION6_RECONF_ACCEPT 20 #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
+289 -87
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -20,30 +20,34 @@
struct iface_param { struct iface_param {
struct dhcp_context *current; struct dhcp_context *current;
struct in6_addr fallback;
int ind; int ind;
}; };
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam);
static int complete_context6(struct in6_addr *local, int prefix, 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(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void) void dhcp6_init(void)
{ {
int fd; int fd;
struct sockaddr_in6 saddr; struct sockaddr_in6 saddr;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6; int class = IPTOS_CLASS_CS6;
#endif
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 || 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 || setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
#endif
!fix_fd(fd) || !fix_fd(fd) ||
!set_ipv6pktinfo(fd)) !set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET); die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
memset(&saddr, 0, sizeof(saddr)); memset(&saddr, 0, sizeof(saddr));
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin6_len = sizeof(addr.in6); saddr.sin6_len = sizeof(struct sockaddr_in6);
#endif #endif
saddr.sin6_family = AF_INET6; saddr.sin6_family = AF_INET6;
saddr.sin6_addr = in6addr_any; saddr.sin6_addr = in6addr_any;
@@ -52,64 +56,9 @@ void dhcp6_init(void)
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6))) if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET); 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))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
daemon->dhcp6fd = fd; daemon->dhcp6fd = fd;
} }
static int join_multicast(struct in6_addr *local, int prefix,
int scope, int if_index, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
struct in6_addr maddr;
int fd = *((int *)vparam);
struct dhcp_context *context;
struct iname *tmp;
(void)prefix;
(void)scope; /* warnings */
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;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp; context; context = context->next)
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
break;
if (!context)
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &maddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &maddr);
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
return 1;
}
void dhcp6_packet(time_t now) void dhcp6_packet(time_t now)
{ {
struct dhcp_context *context; struct dhcp_context *context;
@@ -121,7 +70,7 @@ void dhcp6_packet(time_t now)
struct cmsghdr align; /* this ensures alignment */ struct cmsghdr align; /* this ensures alignment */
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u; } control_u;
union mysockaddr from; struct sockaddr_in6 from;
struct all_addr dest; struct all_addr dest;
ssize_t sz; ssize_t sz;
struct ifreq ifr; struct ifreq ifr;
@@ -135,7 +84,7 @@ void dhcp6_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet; msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4) if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1 || sz <= 4)
return; return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr)) for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
@@ -153,7 +102,7 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name)) if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return; return;
ls -l
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name)) if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
return; return;
@@ -162,59 +111,312 @@ ls -l
return; return;
/* weird libvirt-inspired access control */ /* 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) if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
break; break;
if (!context) if (!context)
return; return;
/* unlinked contexts are marked by context->current == context */ /* 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; {
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
parm.current = NULL; parm.current = NULL;
parm.ind = if_index; parm.ind = if_index;
memset(&parm.fallback, 0, IN6ADDRSZ);
if (!iface_enumerate(AF_INET6, &parm, complete_context6)) if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return; return;
lease_prune(NULL, now); /* lose any expired leases */ lease_prune(NULL, now); /* lose any expired leases */
msg.msg_iov = &daemon->dhcp_packet; sz = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz = dhcp6_reply(parm.current, sz); sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
/* ifr.ifr_name, if_index, (size_t)sz,
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
if (sz != 0) 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)) == -1 &&
retry_send());
} }
static int complete_context6(struct in6_addr *local, int prefix, 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 dhcp_context *context;
struct iface_param *param = vparam; struct iface_param *param = vparam;
(void)scope; /* warning */
(void)dad;
for (context = daemon->dhcp6; context; context = context->next) if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{ {
if ((context->flags & CONTEXT_IPV6) && /* Determine a globally address on the arrival interface, even
prefix == context->prefix && if we have no matching dhcp-context, because we're only
is_same_net6(local, &context->start6, prefix) && allocating on remote subnets via relays. This
is_same_net6(local, &context->end6, prefix)) is used as a default for the DNS server option. */
{ param->fallback = *local;
/* link it onto the current chain if we've not seen it before */
if (if_index == param->ind && context->current == context) for (context = daemon->dhcp6; context; context = context->next)
{ {
context->current = param->current; if (prefix == context->prefix &&
param->current = context; is_same_net6(local, &context->start6, prefix) &&
} is_same_net6(local, &context->end6, prefix))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
context->current = param->current;
param->current = context;
context->local6 = *local;
}
}
} }
} }
return 1; 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->local6))
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)
{
if (daemon->duid_config)
{
unsigned char *p;
daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
daemon->duid_len = daemon->duid_config_len + 6;
PUTSHORT(2, p); /* DUID_EN */
PUTLONG(daemon->duid_enterprise, p);
memcpy(p, daemon->duid_config, daemon->duid_config_len);
}
else
{
/* 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(int index, 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 and
has address-type < 256. Address types above 256 are things like
tunnels which don't have usable MAC addresses. */
unsigned char *p;
(void)index;
if (type >= 256)
return 1;
#ifdef HAVE_BROKEN_RTC
daemon->duid = p = safe_malloc(maclen + 4);
daemon->duid_len = maclen + 4;
PUTSHORT(3, p); /* DUID_LL */
PUTSHORT(type, p); /* address type */
#else
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
PUTSHORT(1, p); /* DUID_LLT */
PUTSHORT(type, p); /* address type */
PUTLONG(*((time_t *)parm), p); /* time */
#endif
memcpy(p, mac, maclen);
return 0;
}
#endif #endif
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
+176 -22
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -87,26 +87,33 @@ int main (int argc, char **argv)
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (!daemon->lease_file) if (!daemon->lease_file)
{ {
if (daemon->dhcp) if (daemon->dhcp || daemon->dhcp6)
daemon->lease_file = LEASEFILE; daemon->lease_file = LEASEFILE;
} }
#endif #endif
/* Close any file descriptors we inherited apart from std{in|out|err} */ /* Close any file descriptors we inherited apart from std{in|out|err}
Ensure that at least stdin, stdout and stderr (fd 0, 1, 2) exist,
otherwise file descriptors we create can end up being 0, 1, or 2
and then get accidentally closed later when we make 0, 1, and 2
open to /dev/null. Normally we'll be started with 0, 1 and 2 open,
but it's not guaranteed. By opening /dev/null three times, we
ensure that we're not using those fds for real stuff. */
for (i = 0; i < max_fd; i++) for (i = 0; i < max_fd; i++)
if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO) if (i != STDOUT_FILENO && i != STDERR_FILENO && i != STDIN_FILENO)
close(i); close(i);
else
open("/dev/null", O_RDWR);
#ifdef HAVE_LINUX_NETWORK #ifndef HAVE_LINUX_NETWORK
netlink_init(); # if !(defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR))
#elif !(defined(IP_RECVDSTADDR) && \
defined(IP_RECVIF) && \
defined(IP_SENDSRCADDR))
if (!option_bool(OPT_NOWILD)) if (!option_bool(OPT_NOWILD))
{ {
bind_fallback = 1; bind_fallback = 1;
set_option_bool(OPT_NOWILD); set_option_bool(OPT_NOWILD);
} }
# endif
#endif #endif
#ifndef HAVE_TFTP #ifndef HAVE_TFTP
@@ -137,19 +144,64 @@ int main (int argc, char **argv)
now = dnsmasq_time(); now = dnsmasq_time();
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp || daemon->dhcp6)
{ {
/* Note that order matters here, we must call lease_init before /* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked 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); lease_init(now);
dhcp_init();
if (daemon->dhcp)
dhcp_init();
} }
# ifdef HAVE_DHCP6
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
if (daemon->ra_contexts || option_bool(OPT_RA))
{
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
struct dhcp_context *context;
if (!daemon->ra_contexts)
daemon->ra_contexts = daemon->dhcp6;
else
{
for (context = daemon->ra_contexts; context->next; context = context->next);
context->next = daemon->dhcp6;
}
ra_init(now);
}
if (daemon->dhcp6)
dhcp6_init();
# endif
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
netlink_init();
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces(now);
#endif #endif
if (!enumerate_interfaces()) if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC); die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
if (option_bool(OPT_NOWILD)) if (option_bool(OPT_NOWILD))
{ {
create_bound_listeners(1); create_bound_listeners(1);
@@ -189,7 +241,8 @@ int main (int argc, char **argv)
#if defined(HAVE_SCRIPT) #if defined(HAVE_SCRIPT)
/* Note getpwnam returns static storage */ /* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->scriptuser && if ((daemon->dhcp || daemon->dhcp6) &&
daemon->scriptuser &&
(daemon->lease_change_command || daemon->luascript)) (daemon->lease_change_command || daemon->luascript))
{ {
if ((ent_pw = getpwnam(daemon->scriptuser))) if ((ent_pw = getpwnam(daemon->scriptuser)))
@@ -341,7 +394,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */ /* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1; daemon->helperfd = -1;
#ifdef HAVE_SCRIPT #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); daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif #endif
@@ -479,27 +532,65 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0) if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs); my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
if (daemon->ra_contexts)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp || daemon->dhcp6)
{ {
struct dhcp_context *dhcp_tmp; struct dhcp_context *dhcp_tmp;
int family = AF_INET;
for (dhcp_tmp = daemon->dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next) 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); 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, my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ? (dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") : _("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_RA_NAME) ?
_("router advertisement with DHCPv4-derived names on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_RA_ONLY) ?
_("router advertisement only on %.0s%s, lifetime %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ? (dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") : _("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"), _("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;
if (daemon->ra_contexts)
dhcp_tmp = daemon->ra_contexts;
else
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
} }
#endif #endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (daemon->tftp_unlimited || daemon->tftp_interfaces) if (daemon->tftp_unlimited || daemon->tftp_interfaces)
{ {
@@ -604,6 +695,20 @@ int main (int argc, char **argv)
} }
#endif #endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
if (daemon->ra_contexts)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
}
#endif
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
FD_SET(daemon->netlinkfd, &rset); FD_SET(daemon->netlinkfd, &rset);
bump_maxfd(daemon->netlinkfd, &maxfd); bump_maxfd(daemon->netlinkfd, &maxfd);
@@ -699,6 +804,17 @@ int main (int argc, char **argv)
dhcp_packet(now, 1); dhcp_packet(now, 1);
} }
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
if (FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
}
#endif
# ifdef HAVE_SCRIPT # ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset)) if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write(); helper_write();
@@ -748,6 +864,11 @@ static void sig_handler(int sig)
} }
} }
void send_alarm(void)
{
send_event(pipewrite, EVENT_ALARM, 0, NULL);
}
void send_event(int fd, int event, int data, char *msg) void send_event(int fd, int event, int data, char *msg)
{ {
struct event_desc ev; struct event_desc ev;
@@ -860,11 +981,21 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM: case EVENT_ALARM:
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp || daemon->dhcp6)
{ {
lease_prune(NULL, now); lease_prune(NULL, now);
lease_update_file(now); lease_update_file(now);
} }
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
#endif
#endif #endif
break; break;
@@ -1018,7 +1149,7 @@ void clear_cache_and_reload(time_t now)
cache_reload(); cache_reload();
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp || daemon->dhcp6)
{ {
if (option_bool(OPT_ETHERS)) if (option_bool(OPT_ETHERS))
dhcp_read_ethers(); dhcp_read_ethers();
@@ -1029,6 +1160,16 @@ void clear_cache_and_reload(time_t now)
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
} }
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
{
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
time_t next_event = periodic_ra(now);
if (next_event != 0)
alarm((unsigned)difftime(next_event, now));
}
#endif
#endif #endif
} }
@@ -1312,7 +1453,15 @@ int icmp_ping(struct in_addr addr)
FD_SET(fd, &rset); FD_SET(fd, &rset);
set_dns_listeners(now, &rset, &maxfd); set_dns_listeners(now, &rset, &maxfd);
set_log_writer(&wset, &maxfd); set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
}
#endif
if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0) if (select(maxfd+1, &rset, &wset, NULL, &tv) < 0)
{ {
FD_ZERO(&rset); FD_ZERO(&rset);
@@ -1324,6 +1473,11 @@ int icmp_ping(struct in_addr addr)
check_log_writer(&wset); check_log_writer(&wset);
check_dns_listeners(&rset, now); check_dns_listeners(&rset, now);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
#endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
check_tftp_listeners(&rset, now); check_tftp_listeners(&rset, now);
#endif #endif
+135 -35
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define COPYRIGHT "Copyright (c) 2000-2011 Simon Kelley" #define COPYRIGHT "Copyright (c) 2000-2012 Simon Kelley"
#ifndef NO_LARGEFILE #ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */ /* Ensure we can use files >2GB (log files may grow this big) */
@@ -54,11 +54,13 @@
typedef unsigned char u8; typedef unsigned char u8;
typedef unsigned short u16; typedef unsigned short u16;
typedef unsigned int u32; typedef unsigned int u32;
typedef unsigned long long u64;
#include "dns_protocol.h" #include "dns-protocol.h"
#include "dhcp_protocol.h" #include "dhcp-protocol.h"
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
#include "dhcp6_protocol.h" #include "dhcp6-protocol.h"
#include "radv-protocol.h"
#endif #endif
#define gettext_noop(S) (S) #define gettext_noop(S) (S)
@@ -214,7 +216,8 @@ struct event_desc {
#define OPT_CONSEC_ADDR 34 #define OPT_CONSEC_ADDR 34
#define OPT_CONNTRACK 35 #define OPT_CONNTRACK 35
#define OPT_FQDN_UPDATE 36 #define OPT_FQDN_UPDATE 36
#define OPT_LAST 37 #define OPT_RA 37
#define OPT_LAST 38
/* extra flags for my_syslog, we use a couple of facilities since they are known /* extra flags for my_syslog, we use a couple of facilities since they are known
not to occupy the same bits as priorities, no matter how syslog.h is set up. */ not to occupy the same bits as priorities, no matter how syslog.h is set up. */
@@ -435,28 +438,30 @@ struct frec {
#define ACTION_OLD 3 #define ACTION_OLD 3
#define ACTION_ADD 4 #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 { struct dhcp_lease {
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
char *hostname, *fqdn; /* name from client-hostname option or config */ char *hostname, *fqdn; /* name from client-hostname option or config */
char *old_hostname; /* hostname before it moved to another lease */ char *old_hostname; /* hostname before it moved to another lease */
char auth_name; /* hostname came from config, not from client */ int flags;
char new; /* newly created */
char changed; /* modified */
char aux_changed; /* CLID or expiry changed */
time_t expires; /* lease expiry */ time_t expires; /* lease expiry */
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
unsigned int length; unsigned int length;
#endif #endif
int hwaddr_len, hwaddr_type; int hwaddr_len, hwaddr_type; /* hw_type used for iaid in v6 */
unsigned char hwaddr[DHCP_CHADDR_MAX]; unsigned char hwaddr[DHCP_CHADDR_MAX]; /* also IPv6 address */
struct in_addr addr, override, giaddr; struct in_addr addr, override, giaddr;
unsigned char *extradata; unsigned char *extradata;
unsigned int extradata_len, extradata_size; unsigned int extradata_len, extradata_size;
int last_interface; int last_interface;
#ifdef HAVE_DHCP6
char is_ipv6;
#endif
struct dhcp_lease *next; struct dhcp_lease *next;
}; };
@@ -489,6 +494,9 @@ struct dhcp_config {
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
char *hostname, *domain; char *hostname, *domain;
struct dhcp_netid_list *netid; struct dhcp_netid_list *netid;
#ifdef HAVE_DHCP6
struct in6_addr addr6;
#endif
struct in_addr addr; struct in_addr addr;
time_t decline_time; time_t decline_time;
unsigned int lease_time; unsigned int lease_time;
@@ -496,6 +504,8 @@ struct dhcp_config {
struct dhcp_config *next; struct dhcp_config *next;
}; };
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define CONFIG_DISABLE 1 #define CONFIG_DISABLE 1
#define CONFIG_CLID 2 #define CONFIG_CLID 2
#define CONFIG_TIME 8 #define CONFIG_TIME 8
@@ -506,6 +516,7 @@ struct dhcp_config {
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */ #define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
#define CONFIG_DECLINED 1024 /* address declined by client */ #define CONFIG_DECLINED 1024 /* address declined by client */
#define CONFIG_BANK 2048 /* from dhcp hosts file */ #define CONFIG_BANK 2048 /* from dhcp hosts file */
#define CONFIG_ADDR6 4096
struct dhcp_opt { struct dhcp_opt {
int opt, len, flags; int opt, len, flags;
@@ -532,6 +543,7 @@ struct dhcp_opt {
#define DHOPT_VENDOR_MATCH 1024 #define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048 #define DHOPT_RFC3925 2048
#define DHOPT_TAGOK 4096 #define DHOPT_TAGOK 4096
#define DHOPT_ADDR6 8192
struct dhcp_boot { struct dhcp_boot {
char *file, *sname, *tftp_sname; char *file, *sname, *tftp_sname;
@@ -542,7 +554,7 @@ struct dhcp_boot {
struct pxe_service { struct pxe_service {
unsigned short CSA, type; unsigned short CSA, type;
char *menu, *basename; char *menu, *basename, *sname;
struct in_addr server; struct in_addr server;
struct dhcp_netid *netid; struct dhcp_netid *netid;
struct pxe_service *next; struct pxe_service *next;
@@ -556,7 +568,8 @@ struct pxe_service {
/* vendorclass, userclass, remote-id or cicuit-id */ /* vendorclass, userclass, remote-id or cicuit-id */
struct dhcp_vendor { struct dhcp_vendor {
int len, match_type, option; int len, match_type;
unsigned int enterprise;
char *data; char *data;
struct dhcp_netid netid; struct dhcp_netid netid;
struct dhcp_vendor *next; struct dhcp_vendor *next;
@@ -578,6 +591,10 @@ struct dhcp_bridge {
struct cond_domain { struct cond_domain {
char *domain; char *domain;
struct in_addr start, end; struct in_addr start, end;
#ifdef HAVE_IPV6
struct in6_addr start6, end6;
#endif
int is6;
struct cond_domain *next; struct cond_domain *next;
}; };
@@ -588,7 +605,9 @@ struct dhcp_context {
struct in_addr start, end; /* range of available addresses */ struct in_addr start, end; /* range of available addresses */
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
struct in6_addr start6, end6; /* range of available addresses */ struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix; int prefix;
time_t ra_time;
#endif #endif
int flags; int flags;
char *interface; char *interface;
@@ -600,7 +619,9 @@ struct dhcp_context {
#define CONTEXT_NETMASK 2 #define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4 #define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8 #define CONTEXT_PROXY 8
#define CONTEXT_IPV6 16 #define CONTEXT_RA_ONLY 16
#define CONTEXT_RA_DONE 32
#define CONTEXT_RA_NAME 64
struct ping_result { struct ping_result {
struct in_addr addr; struct in_addr addr;
@@ -609,6 +630,13 @@ struct ping_result {
struct ping_result *next; struct ping_result *next;
}; };
struct subnet_map {
int iface;
struct in6_addr subnet;
struct subnet_map *next;
};
struct tftp_file { struct tftp_file {
int refcount, fd; int refcount, fd;
off_t size; off_t size;
@@ -679,9 +707,9 @@ extern struct daemon {
int port, query_port, min_port; int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl; unsigned long local_ttl, neg_ttl, max_ttl;
struct hostsfile *addn_hosts; struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6; struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
struct dhcp_config *dhcp_conf; 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_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;
@@ -703,6 +731,8 @@ extern struct daemon {
struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */ struct tftp_prefix *if_prefix; /* per-interface TFTP prefixes */
struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */ struct interface_list *tftp_interfaces; /* interfaces for limited TFTP service */
int tftp_unlimited; int tftp_unlimited;
unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config;
/* globally used stuff for DNS */ /* globally used stuff for DNS */
char *packet; /* packet buffer */ char *packet; /* packet buffer */
@@ -739,7 +769,7 @@ extern struct daemon {
int duid_len; int duid_len;
unsigned char *duid; unsigned char *duid;
struct iovec outpacket; struct iovec outpacket;
int dhcp6fd; int dhcp6fd, icmp6fd;
#endif #endif
/* DBus stuff */ /* DBus stuff */
/* void * here to avoid depending on dbus headers outside dbus.c */ /* void * here to avoid depending on dbus headers outside dbus.c */
@@ -771,12 +801,15 @@ void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags); time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(void); 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); struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr); char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
#endif
/* rfc1035.c */ /* rfc1035.c */
unsigned int extract_request(struct dns_header *header, size_t qlen, unsigned int extract_request(struct dns_header *header, size_t qlen,
@@ -814,6 +847,8 @@ time_t dnsmasq_time(void);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask); int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen); 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 #endif
int retry_send(void); int retry_send(void);
void prettyprint_time(char *buf, unsigned int t); void prettyprint_time(char *buf, unsigned int t);
@@ -838,7 +873,8 @@ void flush_log(void);
/* option.c */ /* option.c */
void read_opts (int argc, char **argv, char *compile_opts); 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 reread_dhcp(void);
void set_option_bool(unsigned int opt); void set_option_bool(unsigned int opt);
struct hostsfile *expand_filelist(struct hostsfile *list); struct hostsfile *expand_filelist(struct hostsfile *list);
@@ -876,31 +912,24 @@ int set_ipv6pktinfo(int fd);
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
void dhcp_init(void); void dhcp_init(void);
void dhcp_packet(time_t now, int pxe_fd); 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 dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr, struct in_addr addr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr, struct in_addr taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);
int address_allocate(struct dhcp_context *context, int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now); 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); 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_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *clid, int clid_len, unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len, unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname); int hw_type, char *hostname);
void dhcp_update_configs(struct dhcp_config *configs);
void dhcp_read_ethers(void); 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); 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 *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
#endif #endif
/* lease.c */ /* lease.c */
@@ -908,13 +937,17 @@ char *get_domain(struct in_addr addr);
void lease_update_file(time_t now); void lease_update_file(time_t now);
void lease_update_dns(); void lease_update_dns();
void lease_init(time_t now); 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 #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 #endif
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr, void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
unsigned char *clid, int hw_len, int hw_type, int clid_len); unsigned char *clid, int hw_len, int hw_type, int clid_len);
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_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface); void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -925,6 +958,11 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void); void lease_update_from_configs(void);
int do_script_run(time_t now); int do_script_run(time_t now);
void rerun_scripts(void); void rerun_scripts(void);
void lease_find_interfaces(time_t now);
#ifdef HAVE_SCRIPT
void lease_add_extradata(struct dhcp_lease *lease, unsigned char *data,
unsigned int len, int delim);
#endif
#endif #endif
/* rfc2131.c */ /* rfc2131.c */
@@ -940,6 +978,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int make_icmp_sock(void); int make_icmp_sock(void);
int icmp_ping(struct in_addr addr); int icmp_ping(struct in_addr addr);
#endif #endif
void send_alarm(void);
void send_event(int fd, int event, int data, char *msg); void send_event(int fd, int event, int data, char *msg);
void clear_cache_and_reload(time_t now); void clear_cache_and_reload(time_t now);
void poll_resolv(int force, int do_reload, time_t now); void poll_resolv(int force, int do_reload, time_t now);
@@ -991,8 +1030,69 @@ int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
int istcp, unsigned int *markp); int istcp, unsigned int *markp);
#endif #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 */ /* rfc3315.c */
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
void make_duid(time_t now); size_t dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
size_t dhcp6_reply(struct dhcp_context *context, size_t sz); struct in6_addr *fallback, 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);
# ifdef HAVE_DHCP6
void join_multicast(void);
# endif
#endif
/* outpacket.c */
#ifdef HAVE_DHCP6
void end_opt6(int container);
int save_counter(int newval);
void *expand(size_t headroom);
int new_opt6(int opt);
void *put_opt6(void *data, size_t len);
void put_opt6_long(unsigned int val);
void put_opt6_short(unsigned int val);
void put_opt6_char(unsigned int val);
void put_opt6_string(char *s);
#endif
/* radv.c */
#ifdef HAVE_DHCP6
void ra_init(time_t now);
void icmp6_packet(void);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now);
struct subnet_map *build_subnet_map(void);
#endif #endif
+31 -7
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -106,8 +106,11 @@ void send_from(int fd, int nowild, char *packet, size_t len,
msg.msg_controllen = 0; msg.msg_controllen = 0;
goto retry; goto retry;
} }
if (retry_send()) if (retry_send())
goto retry; goto retry;
my_syslog(LOG_ERR, _("failed to send packet: %s"), strerror(errno));
} }
} }
@@ -763,12 +766,33 @@ void receive_query(struct listener *listen, time_t now)
!iface_check(listen->family, &dst_addr, ifr.ifr_name)) !iface_check(listen->family, &dst_addr, ifr.ifr_name))
return; return;
if (listen->family == AF_INET && if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
option_bool(OPT_LOCALISE) && {
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1) struct irec *iface;
return;
/* get the netmask of the interface whch has the address we were sent to.
netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; This is no neccessarily the interface we arrived on. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->addr.sa.sa_family == AF_INET &&
iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
break;
/* interface may be new */
if (!iface)
enumerate_interfaces();
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->addr.sa.sa_family == AF_INET &&
iface->addr.in.sin_addr.s_addr == dst_addr_4.s_addr)
break;
/* If we failed, abandon localisation */
if (iface)
netmask = iface->netmask;
else
dst_addr_4.s_addr = 0;
}
} }
if (extract_request(header, (size_t)n, daemon->namebuff, &type)) if (extract_request(header, (size_t)n, daemon->namebuff, &type))
+153 -49
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -46,8 +46,9 @@ static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end,
struct script_data struct script_data
{ {
unsigned char action, hwaddr_len, hwaddr_type; int flags;
unsigned char clid_len, hostname_len, ed_len; int action, hwaddr_len, hwaddr_type;
int clid_len, hostname_len, ed_len;
struct in_addr addr, giaddr; struct in_addr addr, giaddr;
unsigned int remaining_time; unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
@@ -57,6 +58,7 @@ struct script_data
#endif #endif
unsigned char hwaddr[DHCP_CHADDR_MAX]; unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE]; char interface[IF_NAMESIZE];
}; };
static struct script_data *buf = NULL; 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; char *p, *action_str, *hostname = NULL, *domain = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff; unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *extradata, *alloc_buff = NULL; unsigned char *end, *extradata, *alloc_buff = NULL;
int err = 0; int is6, err = 0;
free(alloc_buff); 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"; action_str = "old";
else else
continue; continue;
is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
/* stringify MAC into dhcp_buff */ if (!is6)
p = daemon->dhcp_buff; {
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) /* stringify MAC into dhcp_buff */
p += sprintf(p, "%.2x-", data.hwaddr_type); p = daemon->dhcp_buff;
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
{ p += sprintf(p, "%.2x-", data.hwaddr_type);
p += sprintf(p, "%.2x", data.hwaddr[i]); for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
if (i != data.hwaddr_len - 1) {
p += sprintf(p, ":"); p += sprintf(p, "%.2x", data.hwaddr[i]);
} if (i != data.hwaddr_len - 1)
p += sprintf(p, ":");
}
}
/* expiry or length into dhcp_buff2 */ /* expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC #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; continue;
/* CLID into packet */ /* 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]); /* or IAID and server DUID for IPv6 */
if (i != data.clid_len - 1) sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.hwaddr_type);
p += sprintf(p, ":"); 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; 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; 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 #ifdef HAVE_LUASCRIPT
if (daemon->luascript) if (daemon->luascript)
{ {
lua_getglobal(lua, "lease"); /* function to call */ lua_getglobal(lua, "lease"); /* function to call */
lua_pushstring(lua, action_str); /* arg1 - action */ lua_pushstring(lua, action_str); /* arg1 - action */
lua_newtable(lua); /* arg2 - data table */ 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_pushstring(lua, daemon->packet);
lua_setfield(lua, -2, "client_id"); 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; end = extradata + data.ed_len;
buf = extradata; 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, "supplied_hostname");
buf = grab_extradata_lua(buf, end, "cpewan_oui");
buf = grab_extradata_lua(buf, end, "cpewan_serial"); if (!is6)
buf = grab_extradata_lua(buf, end, "cpewan_class"); {
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"); 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++) for (i = 0; buf; i++)
{ {
sprintf(daemon->dhcp_buff2, "user_class%i", i); sprintf(daemon->dhcp_buff2, "user_class%i", i);
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2); 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) if (data.action != ACTION_DEL && data.remaining_time != 0)
{ {
lua_pushnumber(lua, data.remaining_time); 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_setfield(lua, -2, "old_hostname");
} }
lua_pushstring(lua, daemon->dhcp_buff); if (!is6)
lua_setfield(lua, -2, "mac_address"); {
lua_pushstring(lua, daemon->dhcp_buff);
lua_pushstring(lua, inet_ntoa(data.addr)); lua_setfield(lua, -2, "mac_address");
}
lua_pushstring(lua, daemon->addrbuff);
lua_setfield(lua, -2, "ip_address"); lua_setfield(lua, -2, "ip_address");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */ 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; 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); my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
if (strlen(data.interface) != 0) 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; end = extradata + data.ed_len;
buf = extradata; 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++) for (i = 0; buf; i++)
{ {
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i); sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err); 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) if (data.action != ACTION_DEL && data.remaining_time != 0)
{ {
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time); 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, execl(daemon->lease_change_command,
p ? p+1 : 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; err = errno;
} }
/* failed, send event so the main process logs the problem */ /* 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; unsigned char *p;
size_t size; size_t size;
unsigned int hostname_len = 0, clid_len = 0, ed_len = 0; unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
int fd = daemon->dhcpfd;
#ifdef HAVE_DHCP6
if (!daemon->dhcp)
fd = daemon->dhcp6fd;
#endif
/* no script */ /* no script */
if (daemon->helperfd == -1) if (daemon->helperfd == -1)
return; return;
@@ -524,6 +627,7 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
} }
buf->action = action; buf->action = action;
buf->flags = lease->flags;
buf->hwaddr_len = lease->hwaddr_len; buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type; buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len; 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->hostname_len = hostname_len;
buf->addr = lease->addr; buf->addr = lease->addr;
buf->giaddr = lease->giaddr; buf->giaddr = lease->giaddr;
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len); memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface)) if (!indextoname(fd, lease->last_interface, buf->interface))
buf->interface[0] = 0; buf->interface[0] = 0;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
+364 -108
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -28,18 +28,9 @@ void lease_init(time_t now)
struct dhcp_lease *lease; struct dhcp_lease *lease;
int clid_len, hw_len, hw_type; int clid_len, hw_len, hw_type;
FILE *leasestream; 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; leases_left = daemon->dhcp_max;
if (option_bool(OPT_LEASE_RO)) if (option_bool(OPT_LEASE_RO))
{ {
/* run "<lease_change_script> init" once to get the /* run "<lease_change_script> init" once to get the
@@ -73,45 +64,70 @@ void lease_init(time_t now)
rewind(leasestream); rewind(leasestream);
} }
#ifdef HAVE_DHCP6
again:
#endif
/* client-id max length is 255 which is 255*2 digits + 254 colons /* client-id max length is 255 which is 255*2 digits + 254 colons
borrow DNS packet buffer which is always larger than 1000 bytes */ borrow DNS packet buffer which is always larger than 1000 bytes */
if (leasestream) if (leasestream)
while (fscanf(leasestream, "%lu %255s %64s %255s %764s", while (fscanf(leasestream, "%255s %255s", daemon->dhcp_buff3, daemon->dhcp_buff2) == 2)
&ei, daemon->dhcp_buff2, daemon->namebuff,
daemon->dhcp_buff, daemon->packet) == 5)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (!v6pass) if (strcmp(daemon->dhcp_buff3, "duid") == 0)
#endif
{ {
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type); daemon->duid_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, 130, NULL, NULL);
/* For backwards compatibility, no explict MAC address type means ether. */ daemon->duid = safe_malloc(daemon->duid_len);
if (hw_type == 0 && hw_len != 0) memcpy(daemon->duid, daemon->dhcp_buff2, daemon->duid_len);
hw_type = ARPHRD_ETHER; continue;
} }
#endif
#ifdef HAVE_DHCP6 ei = atol(daemon->dhcp_buff3);
if (v6pass)
inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6); if (fscanf(leasestream, " %64s %255s %764s",
else daemon->namebuff, daemon->dhcp_buff, daemon->packet) != 3)
#endif break;
inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4);
clid_len = 0; clid_len = 0;
if (strcmp(daemon->packet, "*") != 0) if (strcmp(daemon->packet, "*") != 0)
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL); 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 #ifdef HAVE_DHCP6
if (v6pass) else if (inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6))
lease = lease_allocate6(&addr.addr.addr6); {
else 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 #endif
lease = lease_allocate4(addr.addr.addr4); else
break;
if (!lease) if (!lease)
die (_("too many stored leases"), NULL, EC_MISC); die (_("too many stored leases"), NULL, EC_MISC);
@@ -126,37 +142,11 @@ void lease_init(time_t now)
even when sizeof(time_t) == 8 */ even when sizeof(time_t) == 8 */
lease->expires = (time_t)ei; lease->expires = (time_t)ei;
#endif #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 /* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */ 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 #ifdef HAVE_SCRIPT
if (!daemon->lease_stream) if (!daemon->lease_stream)
@@ -194,17 +184,17 @@ void lease_update_from_configs(void)
struct dhcp_lease *lease; struct dhcp_lease *lease;
struct dhcp_config *config; struct dhcp_config *config;
char *name; char *name;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len, if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) && (config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) (!(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))) 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, ...) static void ourprintf(int *errp, char *format, ...)
{ {
va_list ap; va_list ap;
@@ -232,7 +222,7 @@ void lease_update_file(time_t now)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
@@ -277,7 +267,7 @@ void lease_update_file(time_t now)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
if (!lease->is_ipv6) if (!(lease->flags & (LEASE_TA | LEASE_NA)))
continue; continue;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
@@ -288,7 +278,8 @@ void lease_update_file(time_t now)
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN); 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 : "*"); ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
if (lease->clid && lease->clid_len != 0) if (lease->clid && lease->clid_len != 0)
@@ -312,7 +303,15 @@ void lease_update_file(time_t now)
} }
/* Set alarm for when the first lease expires + slop. */ /* Set alarm for when the first lease expires + slop. */
for (next_event = 0, lease = leases; lease; lease = lease->next) next_event = 0;
#ifdef HAVE_DHCP6
/* do timed RAs and determine when the next is */
if (daemon->ra_contexts)
next_event = periodic_ra(now);
#endif
for (lease = leases; lease; lease = lease->next)
if (lease->expires != 0 && if (lease->expires != 0 &&
(next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0)) (next_event == 0 || difftime(next_event, lease->expires + 10) > 0.0))
next_event = lease->expires + 10; next_event = lease->expires + 10;
@@ -331,21 +330,133 @@ void lease_update_file(time_t now)
alarm((unsigned)difftime(next_event, now)); alarm((unsigned)difftime(next_event, now));
} }
void lease_update_dns(void)
static int find_interface_v4(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
(void) broadcast;
(void) vparam;
for (lease = leases; lease; lease = lease->next)
if (!(lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net(local, lease->addr, netmask))
lease->last_interface = if_index;
return 1;
}
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_lease *lease;
(void) scope;
(void) vparam;
(void)dad;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
if (is_same_net6(local, (struct in6_addr *)&lease->hwaddr, prefix))
lease->last_interface = if_index;
return 1;
}
#endif
/* Find interfaces associated with leases at start-up. This gets updated as
we do DHCP transactions, but information about directly-connected subnets
is useful from scrips and necessary for determining SLAAC addresses from
start-time. */
void lease_find_interfaces(time_t now)
{
iface_enumerate(AF_INET, NULL, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, NULL, find_interface_v6);
/* 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_dns(void)
{
struct dhcp_lease *lease;
if (daemon->port != 0 && dns_dirty) if (daemon->port != 0 && dns_dirty)
{ {
cache_unhash_dhcp(); #ifdef HAVE_DHCP6
struct subnet_map *subnets = build_subnet_map();
#endif
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
int prot = AF_INET;
#ifdef HAVE_DHCP6
if (lease->flags & (LEASE_TA | LEASE_NA))
prot = AF_INET6;
else if (lease->hostname || lease->fqdn)
{
struct subnet_map *map;
for (map = subnets; map; map = map->next)
if (lease->last_interface == map->iface)
{
struct in6_addr addr = map->subnet;
if (lease->hwaddr_len == 6 &&
(lease->hwaddr_type == ARPHRD_ETHER || lease->hwaddr_type == ARPHRD_IEEE802))
{
/* convert MAC address to EUI-64 */
memcpy(&addr.s6_addr[8], lease->hwaddr, 3);
memcpy(&addr.s6_addr[13], &lease->hwaddr[3], 3);
addr.s6_addr[11] = 0xff;
addr.s6_addr[12] = 0xfe;
}
#if defined(ARPHRD_EUI64)
else if (lease->hwaddr_len == 8 &&
lease->hwaddr_type == ARPHRD_EUI64)
memcpy(&addr.s6_addr[8], lease->hwaddr, 8);
#endif
#if defined(ARPHRD_IEEE1394) && defined(ARPHRD_EUI64)
else if (lease->clid_len == 9 &&
lease->clid[0] == ARPHRD_EUI64 &&
lease->hwaddr_type == ARPHRD_IEEE1394)
/* firewire has EUI-64 identifier as clid */
memcpy(&addr.s6_addr[8], &lease->clid[1], 8);
#endif
else
continue;
addr.s6_addr[8] ^= 0x02;
if (lease->fqdn)
cache_add_dhcp_entry(lease->fqdn, AF_INET6, (struct all_addr *)&addr, lease->expires);
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, AF_INET6, (struct all_addr *)&addr, lease->expires);
}
}
#endif
if (lease->fqdn) 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) 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; dns_dirty = 0;
@@ -389,7 +500,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (lease->clid && clid_len == lease->clid_len && if (lease->clid && clid_len == lease->clid_len &&
@@ -400,7 +511,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if ((!lease->clid || !clid) && if ((!lease->clid || !clid) &&
@@ -421,7 +532,7 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (lease->addr.s_addr == addr.s_addr) if (lease->addr.s_addr == addr.s_addr)
@@ -431,6 +542,83 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
return NULL; 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 */ /* Find largest assigned address in context */
struct in_addr lease_find_max_addr(struct dhcp_context *context) struct in_addr lease_find_max_addr(struct dhcp_context *context)
{ {
@@ -441,7 +629,7 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
if (lease->is_ipv6) if (lease->flags & (LEASE_TA | LEASE_NA))
continue; continue;
#endif #endif
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) && if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
@@ -460,7 +648,7 @@ static struct dhcp_lease *lease_allocate(void)
return NULL; return NULL;
memset(lease, 0, sizeof(struct dhcp_lease)); memset(lease, 0, sizeof(struct dhcp_lease));
lease->new = 1; lease->flags = LEASE_NEW;
lease->expires = 1; lease->expires = 1;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
lease->length = 0xffffffff; /* illegal value */ lease->length = 0xffffffff; /* illegal value */
@@ -474,7 +662,7 @@ static struct dhcp_lease *lease_allocate(void)
return lease; 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(); struct dhcp_lease *lease = lease_allocate();
lease->addr = addr; lease->addr = addr;
@@ -484,11 +672,11 @@ struct dhcp_lease *lease_allocate4(struct in_addr addr)
} }
#ifdef HAVE_DHCP6 #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(); struct dhcp_lease *lease = lease_allocate();
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ; memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
lease->is_ipv6 = 1; lease->flags |= lease_type;
return lease; return lease;
} }
@@ -509,7 +697,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
dns_dirty = 1; dns_dirty = 1;
lease->expires = exp; lease->expires = exp;
#ifndef HAVE_BROKEN_RTC #ifndef HAVE_BROKEN_RTC
lease->aux_changed = file_dirty = 1; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
#endif #endif
} }
@@ -517,7 +706,8 @@ void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
if (len != lease->length) if (len != lease->length)
{ {
lease->length = len; lease->length = len;
lease->aux_changed = file_dirty = 1; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
} }
#endif #endif
} }
@@ -529,10 +719,12 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
hw_type != lease->hwaddr_type || hw_type != lease->hwaddr_type ||
(hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0)) (hw_len != 0 && memcmp(lease->hwaddr, hwaddr, hw_len) != 0))
{ {
memcpy(lease->hwaddr, hwaddr, hw_len); if (hw_len != 0)
memcpy(lease->hwaddr, hwaddr, hw_len);
lease->hwaddr_len = hw_len; lease->hwaddr_len = hw_len;
lease->hwaddr_type = hw_type; 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 /* only update clid when one is available, stops packets
@@ -545,14 +737,18 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
if (lease->clid_len != clid_len) if (lease->clid_len != clid_len)
{ {
lease->aux_changed = file_dirty = 1; lease->flags |= LEASE_AUX_CHANGED;
file_dirty = 1;
free(lease->clid); free(lease->clid);
if (!(lease->clid = whine_malloc(clid_len))) if (!(lease->clid = whine_malloc(clid_len)))
return; return;
} }
else if (memcmp(lease->clid, clid, clid_len) != 0) 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; lease->clid_len = clid_len;
memcpy(lease->clid, clid, clid_len); memcpy(lease->clid, clid, clid_len);
} }
@@ -568,7 +764,7 @@ static void kill_name(struct dhcp_lease *lease)
free(lease->old_hostname); free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the /* 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) if (lease->fqdn)
{ {
@@ -581,14 +777,18 @@ static void kill_name(struct dhcp_lease *lease)
lease->hostname = lease->fqdn = NULL; 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; struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL; 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)) if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{ {
lease->auth_name = auth; if (auth)
lease->flags |= LEASE_AUTH_NAME;
return; return;
} }
@@ -598,19 +798,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, /* 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 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. 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. */ Don't allow a name from the client to override a name from dnsmasq config. */
if (name) if (name)
{ {
if ((new_name = whine_malloc(strlen(name) + 1))) if ((new_name = whine_malloc(strlen(name) + 1)))
{ {
char *suffix = get_domain(lease->addr);
strcpy(new_name, name); 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); strcpy(new_fqdn, name);
strcat(new_fqdn, "."); strcat(new_fqdn, ".");
strcat(new_fqdn, suffix); strcat(new_fqdn, domain);
} }
} }
@@ -619,7 +821,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{ {
if (option_bool(OPT_DHCP_FQDN)) 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; continue;
} }
else else
@@ -627,8 +829,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) ) if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue; 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_name);
free(new_fqdn); free(new_fqdn);
@@ -645,11 +861,13 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
lease->hostname = new_name; lease->hostname = new_name;
lease->fqdn = new_fqdn; lease->fqdn = new_fqdn;
lease->auth_name = auth;
if (auth)
lease->flags |= LEASE_AUTH_NAME;
file_dirty = 1; file_dirty = 1;
dns_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) void lease_set_interface(struct dhcp_lease *lease, int interface)
@@ -658,7 +876,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface)
return; return;
lease->last_interface = interface; lease->last_interface = interface;
lease->changed = 1; lease->flags |= LEASE_CHANGED;
} }
void rerun_scripts(void) void rerun_scripts(void)
@@ -666,7 +884,7 @@ void rerun_scripts(void)
struct dhcp_lease *lease; struct dhcp_lease *lease;
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
lease->changed = 1; lease->flags |= LEASE_CHANGED;
} }
/* deleted leases get transferred to the old_leases list. /* deleted leases get transferred to the old_leases list.
@@ -732,18 +950,18 @@ int do_script_run(time_t now)
} }
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if (lease->new || lease->changed || if ((lease->flags & (LEASE_NEW | LEASE_CHANGED)) ||
(lease->aux_changed && option_bool(OPT_LEASE_RO))) ((lease->flags & LEASE_AUX_CHANGED) && option_bool(OPT_LEASE_RO)))
{ {
#ifdef HAVE_SCRIPT #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); lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif #endif
#ifdef HAVE_DBUS #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); lease->fqdn ? lease->fqdn : lease->hostname);
#endif #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 */ /* this is used for the "add" call, then junked, since they're not in the database */
free(lease->extradata); free(lease->extradata);
@@ -755,6 +973,44 @@ int do_script_run(time_t now)
return 0; /* nothing to do */ 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 #endif
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
+25 -12
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -136,6 +136,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
struct nlmsghdr *h; struct nlmsghdr *h;
ssize_t len; ssize_t len;
static unsigned int seq = 0; static unsigned int seq = 0;
int callback_ok = 1;
struct { struct {
struct nlmsghdr nlh; struct nlmsghdr nlh;
@@ -186,7 +187,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
else if (h->nlmsg_type == NLMSG_ERROR) else if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h); nl_err(h);
else if (h->nlmsg_type == NLMSG_DONE) else if (h->nlmsg_type == NLMSG_DONE)
return 1; return callback_ok;
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL) else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
{ {
struct ifaddrmsg *ifa = NLMSG_DATA(h); struct ifaddrmsg *ifa = NLMSG_DATA(h);
@@ -213,9 +214,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (addr.s_addr) if (addr.s_addr && callback_ok)
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm))) if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
return 0; callback_ok = 0;
} }
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
else if (ifa->ifa_family == AF_INET6) else if (ifa->ifa_family == AF_INET6)
@@ -229,10 +230,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (addrp) if (addrp && callback_ok)
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index, if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm))) (int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
return 0; callback_ok = 0;
} }
#endif #endif
} }
@@ -258,9 +259,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (inaddr && mac) if (inaddr && mac && callback_ok)
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
return 0; callback_ok = 0;
} }
#ifdef HAVE_DHCP6 #ifdef HAVE_DHCP6
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL) else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
@@ -282,8 +283,9 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm))) if (mac && callback_ok && !((link->ifi_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) &&
return 0; !((*callback)((int)link->ifi_index, (unsigned int)link->ifi_type, mac, maclen, parm)))
callback_ok = 0;
} }
#endif #endif
} }
@@ -339,6 +341,17 @@ static void nl_routechange(struct nlmsghdr *h)
/* Force re-reading resolv file right now, for luck. */ /* Force re-reading resolv file right now, for luck. */
daemon->last_resolv = 0; daemon->last_resolv = 0;
#ifdef HAVE_DHCP6
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
ra_start_unsolicted(dnsmasq_time());
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm();
}
#endif
if (daemon->srv_save) if (daemon->srv_save)
{ {
if (daemon->srv_save->sfd) if (daemon->srv_save->sfd)
+5 -4
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -274,9 +274,10 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
{ {
union mysockaddr addr; union mysockaddr addr;
struct in_addr netmask; /* dummy */ struct in_addr netmask; /* dummy */
(void)prefix; /* warning */
netmask.s_addr = 0; netmask.s_addr = 0;
(void)prefix; /* warning */
(void)scope; /* warning */
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN #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_family = AF_INET6;
addr.in6.sin6_addr = *local; addr.in6.sin6_addr = *local;
addr.in6.sin6_port = htons(daemon->port); 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); return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
} }
+641 -154
View File
File diff suppressed because it is too large. Load diff
+108
View File
@@ -0,0 +1,108 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_DHCP6
static size_t outpacket_counter;
void end_opt6(int container)
{
void *p = daemon->outpacket.iov_base + container + 2;
u16 len = outpacket_counter - container - 4 ;
PUTSHORT(len, p);
}
int save_counter(int newval)
{
int ret = outpacket_counter;
if (newval != -1)
outpacket_counter = newval;
return ret;
}
void *expand(size_t headroom)
{
void *ret;
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
{
ret = daemon->outpacket.iov_base + outpacket_counter;
outpacket_counter += headroom;
return ret;
}
return NULL;
}
int new_opt6(int opt)
{
int ret = outpacket_counter;
void *p;
if ((p = expand(4)))
{
PUTSHORT(opt, p);
PUTSHORT(0, p);
}
return ret;
}
void *put_opt6(void *data, size_t len)
{
void *p;
if ((p = expand(len)))
memcpy(p, data, len);
return p;
}
void put_opt6_long(unsigned int val)
{
void *p;
if ((p = expand(4)))
PUTLONG(val, p);
}
void put_opt6_short(unsigned int val)
{
void *p;
if ((p = expand(2)))
PUTSHORT(val, p);
}
void put_opt6_char(unsigned int val)
{
unsigned char *p;
if ((p = expand(1)))
*p = val;
}
void put_opt6_string(char *s)
{
put_opt6(s, strlen(s));
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/* 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/>.
*/
#define ALL_HOSTS "FF02::1"
#define ALL_ROUTERS "FF02::2"
struct ra_packet {
u8 type, code;
u16 checksum;
u8 hop_limit, flags;
u16 lifetime;
u32 reachable_time;
u32 retrans_time;
};
struct prefix_opt {
u8 type, len, prefix_len, flags;
u32 valid_lifetime, preferred_lifetime, reserved;
struct in6_addr prefix;
};
#define ICMP6_ROUTER_SOLICIT 133
#define ICMP6_ROUTER_ADVERT 134
#define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
#define ICMP6_OPT_RDNSS 25
+498
View File
@@ -0,0 +1,498 @@
/* 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/>.
*/
/* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
It therefore cannot use any DHCP buffer resources except outpacket, which is
not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
active, so we ensure that outpacket is allocated here too */
#include "dnsmasq.h"
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct ra_param {
int ind, managed, found_context, first;
char *if_name;
struct in6_addr link_local;
};
struct search_param {
time_t now; int iface;
};
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int hop_limit;
static time_t ra_short_period_start;
void ra_init(time_t now)
{
struct icmp6_filter filter;
int fd;
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
int class = IPTOS_CLASS_CS6;
#endif
int val = 255; /* radvd uses this value */
socklen_t len = sizeof(int);
/* ensure this is around even if we're not doing DHCPv6 */
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
#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) ||
setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
daemon->icmp6fd = fd;
ra_start_unsolicted(now);
}
void ra_start_unsolicted(time_t now)
{
struct dhcp_context *context;
/* init timers so that we do ra's for all soon. some ra_times will end up zeroed
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
/* range 0 - 5 */
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000);
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
}
void icmp6_packet(void)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
int if_index = 0;
struct cmsghdr *cmptr;
struct msghdr msg;
union {
struct cmsghdr align; /* this ensures alignment */
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
} control_u;
struct sockaddr_in6 from;
unsigned char *p;
char *mac = "";
struct iname *tmp;
struct dhcp_context *context;
/* Note: use outpacket for input buffer */
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
msg.msg_flags = 0;
msg.msg_name = &from;
msg.msg_namelen = sizeof(from);
msg.msg_iov = &daemon->outpacket;
msg.msg_iovlen = 1;
if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
return;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
union {
unsigned char *c;
struct in6_pktinfo *p;
} p;
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
}
if (!indextoname(daemon->icmp6fd, if_index, interface))
return;
if (!iface_check(AF_LOCAL, NULL, interface))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0))
return;
/* weird libvirt-inspired access control */
for (context = daemon->dhcp6; context; context = context->next)
if (!context->interface || strcmp(context->interface, interface) == 0)
break;
if (!context)
return;
p = (unsigned char *)daemon->outpacket.iov_base;
if (p[0] != ICMP6_ROUTER_SOLICIT || p[1] != 0)
return;
/* look for link-layer address option for logging */
if (sz >= 16 && p[8] == ICMP6_OPT_SOURCE_MAC && (p[9] * 8) + 8 <= sz)
{
print_mac(daemon->namebuff, &p[10], (p[9] * 8) - 2);
mac = daemon->namebuff;
}
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
send_ra(if_index, interface, &from.sin6_addr);
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
{
struct ra_packet *ra;
struct ra_param parm;
struct ifreq ifr;
struct sockaddr_in6 addr;
struct dhcp_context *context;
save_counter(0);
ra = expand(sizeof(struct ra_packet));
ra->type = ICMP6_ROUTER_ADVERT;
ra->code = 0;
ra->hop_limit = hop_limit;
ra->flags = 0;
ra->lifetime = htons(1800); /* AdvDefaultLifetime*/
ra->reachable_time = 0;
ra->retrans_time = 0;
parm.ind = iface;
parm.managed = 0;
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
for (context = daemon->ra_contexts; context; context = context->next)
context->flags &= ~CONTEXT_RA_DONE;
if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
!parm.found_context)
return;
strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
if (ioctl(daemon->icmp6fd, SIOCGIFMTU, &ifr) != -1)
{
put_opt6_char(ICMP6_OPT_MTU);
put_opt6_char(1);
put_opt6_short(0);
put_opt6_long(ifr.ifr_mtu);
}
iface_enumerate(AF_LOCAL, &iface, add_lla);
/* RDNSS, RFC 6106 */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
/* set managed bits unless we're providing only RA on this link */
if (parm.managed)
ra->flags = 0xc0;
/* decide where we're sending */
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.sin6_family = AF_INET6;
addr.sin6_port = htons(IPPROTO_ICMPV6);
if (dest)
{
memcpy(&addr.sin6_addr, dest, sizeof(struct in6_addr));
if (IN6_IS_ADDR_LINKLOCAL(dest) ||
IN6_IS_ADDR_MC_LINKLOCAL(dest))
addr.sin6_scope_id = iface;
}
else
inet_pton(AF_INET6, ALL_HOSTS, &addr.sin6_addr);
send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
(union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface);
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context, *tmp;
struct ra_param *param = vparam;
struct prefix_opt *opt;
(void)scope; /* warning */
(void)dad;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
if (!(context->flags & CONTEXT_RA_ONLY))
{
/* don't do RA for non-ra-only unless --enable-ra is set */
if (!option_bool(OPT_RA))
continue;
param->managed = 1;
}
if (context->flags & CONTEXT_RA_DONE)
continue;
/* subsequent prefixes on the same interface don't need timers */
if (!param->first)
context->ra_time = 0;
param->first = 0;
param->found_context = 1;
context->flags |= CONTEXT_RA_DONE;
/* mark this subnet and duplicates: as done. */
for (tmp = context->next; tmp; tmp = tmp->next)
if (tmp->prefix == prefix &&
is_same_net6(local, &tmp->start6, prefix) &&
is_same_net6(local, &tmp->end6, prefix))
{
tmp->flags |= CONTEXT_RA_DONE;
context->ra_time = 0;
}
if ((opt = expand(sizeof(struct prefix_opt))))
{
u64 addrpart = addr6part(&context->start6);
u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
unsigned int time = context->lease_time;
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only is we're not doing dhcp */
opt->flags = (context->flags & CONTEXT_RA_ONLY) ? 0xc0 : 0x00;
opt->valid_lifetime = opt->preferred_lifetime = htonl(time);
opt->reserved = 0;
opt->prefix = context->start6;
setaddr6part(&opt->prefix, addrpart & ~mask);
inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
}
}
}
}
return 1;
}
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
{
(void)type;
if (index == *((int *)parm))
{
/* size is in units of 8 octets and includes type and length (2 bytes)
add 7 to round up */
int len = (maclen + 9) >> 3;
unsigned char *p = expand(len << 3);
memset(p, 0, len << 3);
*p++ = ICMP6_OPT_SOURCE_MAC;
*p++ = len;
memcpy(p, mac, maclen);
return 0;
}
return 1;
}
time_t periodic_ra(time_t now)
{
struct search_param param;
struct dhcp_context *context;
time_t next_event;
char interface[IF_NAMESIZE+1];
param.now = now;
while (1)
{
/* find overdue events, and time of first future event */
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) < 0.0)
break; /* overdue */
if (next_event == 0 || difftime(next_event, context->ra_time + 2) > 0.0)
next_event = context->ra_time + 2;
}
/* none overdue */
if (!context)
break;
/* There's a context overdue, but we can't find an interface
associated with it, because it's for a subnet we dont
have an interface on. Probably we're doing DHCP on
a remote subnet via a relay. Zero the timer, since we won't
ever be able to send ra's and satistfy it. */
if (iface_enumerate(AF_INET6, &param, iface_search))
context->ra_time = 0;
else if (indextoname(daemon->icmp6fd, param.iface, interface))
send_ra(param.iface, interface, NULL);
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) < 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and zap other contexts on the same interface
so they don't timeout independently .*/
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
return 0; /* found, abort */
}
return 1; /* keep searching */
}
static int add_subnet(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
struct subnet_map **subnets = vparam;
struct subnet_map *map;
(void)scope;
(void)dad;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
for (map = *subnets; map; map = map->next)
if (map->iface == 0 ||
(map->iface == if_index && is_same_net6(local, &map->subnet, prefix)))
break;
/* It's there already */
if (map && map->iface != 0)
continue;
if (!map && (map = whine_malloc(sizeof(struct subnet_map))))
{
map->next = *subnets;
*subnets = map;
}
if (map)
{
map->iface = if_index;
map->subnet = *local;
}
}
return 1;
}
/* Build a map from ra-names subnets to corresponding interfaces. This
is used to go from DHCPv4 leases to SLAAC addresses,
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
*/
struct subnet_map *build_subnet_map(void)
{
struct subnet_map *map;
struct dhcp_context *context;
static struct subnet_map *subnets = NULL;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
/* no ra-names, no need to go further. */
if (!context)
return NULL;
/* mark unused */
for (map = subnets; map; map = map->next)
map->iface = 0;
if (iface_enumerate(AF_INET6, &subnets, add_subnet))
return subnets;
return NULL;
}
#endif
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -25,7 +25,7 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen)) ((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \ #define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1) (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes) char *name, int isExtract, int extrabytes)
+56 -213
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -18,16 +18,13 @@
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
#define option_len(opt) ((int)(((unsigned char *)(opt))[1])) #define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)])) #define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
#ifdef HAVE_SCRIPT #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); static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
#endif #endif
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
static int sanitise(unsigned char *opt, char *buf); 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 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); 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, static void option_put_string(struct dhcp_packet *mess, unsigned char *end,
int opt, char *string, int null_term); int opt, char *string, int null_term);
static struct in_addr option_addr(unsigned char *opt); 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 unsigned int option_uint(unsigned char *opt, int i, int size);
static void log_packet(char *type, void *addr, unsigned char *ext_mac, static void log_packet(char *type, void *addr, unsigned char *ext_mac,
int mac_len, char *interface, char *string, u32 xid); 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_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 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 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 clear_packet(struct dhcp_packet *mess, unsigned char *end);
static void do_options(struct dhcp_context *context, 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 *real_end,
unsigned char *req_options, unsigned char *req_options,
char *hostname, char *hostname,
char *domain, char *config_domain, char *config_domain,
struct dhcp_netid *netid, struct dhcp_netid *netid,
struct in_addr subnet_addr, struct in_addr subnet_addr,
unsigned char fqdn_flags, 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 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 void pxe_misc(struct dhcp_packet *mess, unsigned char *end, unsigned char *uuid);
static int prune_vendor_opts(struct dhcp_netid *netid); 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); 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); tagif_netid = run_tag_if(&context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
if (!message && !nailed) if (!message && !nailed)
{ {
@@ -481,7 +476,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (!message && if (!message &&
!lease && !lease &&
(!(lease = lease_allocate4(mess->yiaddr)))) (!(lease = lease4_allocate(mess->yiaddr))))
message = _("no leases left"); message = _("no leases left");
if (!message) 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); lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
if (hostname) 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. */ /* infinite lease unless nailed in dhcp-host line. */
lease_set_expires(lease, lease_set_expires(lease,
have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff, have_config(config, CONFIG_TIME) ? config->lease_time : 0xffffffff,
@@ -499,7 +494,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
clear_packet(mess, end); clear_packet(mess, end);
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr), do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
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->yiaddr = mess->ciaddr;
mess->ciaddr.s_addr = 0; 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; mess->siaddr = service->server;
else else
mess->siaddr = context->local; 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); 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_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); 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)); option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
pxe_misc(mess, end, uuid); pxe_misc(mess, end, uuid);
prune_vendor_opts(tagif_netid); 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_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); 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); 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); 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); option_put(mess, end, OPTION_T2, 4, (time*7)/8);
} }
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr), 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); 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) else if (!lease)
{ {
if ((lease = lease_allocate4(mess->yiaddr))) if ((lease = lease4_allocate(mess->yiaddr)))
do_classes = 1; do_classes = 1;
else else
message = _("no leases left"); 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); tagif_netid = run_tag_if( &context->netid);
} }
log_tags(tagif_netid, mess); log_tags(tagif_netid, ntohl(mess->xid));
#ifdef HAVE_SCRIPT #ifdef HAVE_SCRIPT
if (do_classes && daemon->lease_change_command) 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) if (mess->giaddr.s_addr)
lease->giaddr = mess->giaddr; lease->giaddr = mess->giaddr;
lease->changed = 1; lease->flags |= LEASE_CHANGED;
free(lease->extradata); free(lease->extradata);
lease->extradata = NULL; lease->extradata = NULL;
lease->extradata_size = lease->extradata_len = 0; lease->extradata_size = lease->extradata_len = 0;
@@ -1249,8 +1246,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
add_extradata_opt(lease, NULL); add_extradata_opt(lease, NULL);
else else
for (n = tagif_netid; n; n = n->next) for (n = tagif_netid; n; n = n->next)
add_extradata_data(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0); {
struct dhcp_netid *n1;
/* kill dupes */
for (n1 = n->next; n1; n1 = n1->next)
if (strcmp(n->net, n1->net) == 0)
break;
if (!n1)
lease_add_extradata(lease, (unsigned char *)n->net, strlen(n->net), n->next ? ' ' : 0);
}
if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1))) if ((opt = option_find(mess, sz, OPTION_USER_CLASS, 1)))
{ {
int len = option_len(opt); int len = option_len(opt);
@@ -1258,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 the user-class option started as counted strings, the first byte will be zero. */
if (len != 0 && ucp[0] == 0) if (len != 0 && ucp[0] == 0)
ucp++, len--; ucp++, len--;
add_extradata_data(lease, ucp, len, 0); lease_add_extradata(lease, ucp, len, 0);
} }
} }
#endif #endif
@@ -1302,7 +1307,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
} }
if (hostname) 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_expires(lease, time, now);
lease_set_interface(lease, int_index); lease_set_interface(lease, int_index);
@@ -1326,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); option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
} }
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr), 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); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1356,10 +1361,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
if (context && context->netid.net) if (context && context->netid.net)
{ {
context->netid.next = netid; 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); log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
@@ -1386,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), 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 */ *is_inform = 1; /* handle reply differently */
return dhcp_packet_size(mess, agent_id, real_end); return dhcp_packet_size(mess, agent_id, real_end);
@@ -1395,37 +1400,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
return 0; 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. /* 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, This is normally just the chaddr field from the DHCP packet,
but eg Firewire will have hlen == 0 and use the client-id instead. but eg Firewire will have hlen == 0 and use the client-id instead.
@@ -1511,51 +1485,12 @@ static int sanitise(unsigned char *opt, char *buf)
} }
#ifdef HAVE_SCRIPT #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) static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt)
{ {
if (!opt) if (!opt)
add_extradata_data(lease, NULL, 0, 0); lease_add_extradata(lease, NULL, 0, 0);
else else
{ lease_add_extradata(lease, option_ptr(opt, 0), option_len(opt), 0);
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);
}
} }
#endif #endif
@@ -1593,30 +1528,10 @@ static void log_options(unsigned char *start, u32 xid)
{ {
while (*start != OPTION_END) while (*start != OPTION_END)
{ {
int is_ip, is_name, i; char *optname = option_string(AF_INET, start[0], option_ptr(start, 0), option_len(start), daemon->namebuff, MAXDNAME);
char *text = option_string(start[0], &is_ip, &is_name);
unsigned char trunc = option_len(start);
if (is_ip) my_syslog(MS_DHCP | LOG_INFO, "%u sent size:%3d option:%3d %s %s",
for (daemon->namebuff[0]= 0, i = 0; i <= trunc - INADDRSZ; i += INADDRSZ) ntohl(xid), option_len(start), start[0], optname, daemon->namebuff);
{
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) ? "" : "...");
start += start[1] + 2; start += start[1] + 2;
} }
} }
@@ -1671,22 +1586,17 @@ static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt
return NULL; 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 is network byte order */
struct in_addr ret; struct in_addr ret;
memcpy(&ret, option_ptr(opt, offset), INADDRSZ); memcpy(&ret, option_ptr(opt, 0), INADDRSZ);
return ret; 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) static unsigned int option_uint(unsigned char *opt, int offset, int size)
{ {
/* this worries about unaligned data and byte order */ /* this worries about unaligned data and byte order */
@@ -1721,31 +1631,6 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
return NULL; 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) 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)); unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
@@ -2040,7 +1925,7 @@ static int prune_vendor_opts(struct dhcp_netid *netid)
return force; 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 #define NUM_OPTS 4
@@ -2097,8 +1982,9 @@ static struct dhcp_opt *pxe_opts(int pxe_arch, struct dhcp_netid *netid, struct
return daemon->dhcp_opts; 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 (boot_server.s_addr != 0)
{ {
if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253) if (q - (unsigned char *)daemon->dhcp_buff3 + 3 + INADDRSZ >= 253)
@@ -2189,7 +2075,7 @@ static void do_options(struct dhcp_context *context,
unsigned char *end, unsigned char *end,
unsigned char *req_options, unsigned char *req_options,
char *hostname, char *hostname,
char *domain, char *config_domain, char *domain,
struct dhcp_netid *netid, struct dhcp_netid *netid,
struct in_addr subnet_addr, struct in_addr subnet_addr,
unsigned char fqdn_flags, unsigned char fqdn_flags,
@@ -2208,65 +2094,22 @@ static void do_options(struct dhcp_context *context,
struct dhcp_netid *tagif; struct dhcp_netid *tagif;
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
/* flag options which are valid with the current tag set (sans context tags) */ /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
tagif = run_tag_if(netid); context->netid.next = NULL;
for (opt = config_opts; opt; opt = opt->next) tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
{
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);
}
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 */ /* logging */
if (option_bool(OPT_LOG_OPTS) && req_options) if (option_bool(OPT_LOG_OPTS) && req_options)
{ {
char *q = daemon->namebuff; char *q = daemon->namebuff;
for (i = 0; req_options[i] != OPTION_END; i++) 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), q += snprintf(q, MAXDNAME - (q - daemon->namebuff),
"%d%s%s%s", "%d%s%s%s",
req_options[i], req_options[i],
s ? ":" : "", strlen(s) != 0 ? ":" : "",
s ? s : "", s,
req_options[i+1] == OPTION_END ? "" : ", "); req_options[i+1] == OPTION_END ? "" : ", ");
if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40) if (req_options[i+1] == OPTION_END || (q - daemon->namebuff) > 40)
{ {
@@ -2503,8 +2346,8 @@ static void do_options(struct dhcp_context *context,
/* Now send options to be encapsulated in arbitrary options, /* Now send options to be encapsulated in arbitrary options,
eg dhcp-option=encap:172,17,....... eg dhcp-option=encap:172,17,.......
Also hand vendor-identifying vendor-encapsulated options, Also handle vendor-identifying vendor-encapsulated options,
dhcp-option = rfc3925-encap:13,17,....... dhcp-option = vi-encap:13,17,.......
The may be more that one "outer" to do, so group The may be more that one "outer" to do, so group
all the options which match each outer in turn. */ all the options which match each outer in turn. */
for (opt = config_opts; opt; opt = opt->next) for (opt = config_opts; opt; opt = opt->next)
@@ -2571,7 +2414,7 @@ static void do_options(struct dhcp_context *context,
if (context && pxe_arch != -1) if (context && pxe_arch != -1)
{ {
pxe_misc(mess, end, uuid); 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)) && if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
+1356 -214
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
+24 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley /* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@@ -336,6 +336,29 @@ int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
return 0; 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 #endif