mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
14
Commits
v2.58
..
v2.60test9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
915363f976 | ||
|
|
205fafa577 | ||
|
|
8ecfaa4adf | ||
|
|
03bfcf6462 | ||
|
|
39bec5ff32 | ||
|
|
246839d64a | ||
|
|
3862deb398 | ||
|
|
5954608577 | ||
|
|
984d2fded6 | ||
|
|
a4f04ed45a | ||
|
|
07736e8dcb | ||
|
|
00fc082d68 | ||
|
|
c72daea868 | ||
|
|
74c95c2542 |
No files matched your search
@@ -1,3 +1,52 @@
|
|||||||
|
version 2.60
|
||||||
|
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||||
|
Flebbe for the patch.
|
||||||
|
|
||||||
|
Fix DHCP when using --listen-address with an IP address
|
||||||
|
which is not the primary address of an interface.
|
||||||
|
|
||||||
|
Add --dhcp-client-update option.
|
||||||
|
|
||||||
|
Add Lua integration. Dnsmasq can now execute a DHCP
|
||||||
|
lease-change script written in Lua. This needs to be
|
||||||
|
enabled at compile time by setting HAVE_LUASCRIPT in
|
||||||
|
src/config.h or running "make COPTS=-DHAVE_LUASCRIPT"
|
||||||
|
Thanks to Jan-Piet Mens for the idea and proof-of-concept
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Tidied src/config.h to distinguish between
|
||||||
|
platform-dependent compile-time options which are selected
|
||||||
|
automatically, and builder-selectable compile time
|
||||||
|
options. Document the latter better, and describe how to
|
||||||
|
set them from the make command line.
|
||||||
|
|
||||||
|
Tidied up IPPROTO_IP/SOL_IP (and IPv6 equivalent)
|
||||||
|
confusion. IPPROTO_IP works everywhere now.
|
||||||
|
|
||||||
|
Set TOS on DHCP sockets, this improves things on busy
|
||||||
|
wireless networks. Thanks to Dave Taht for the patch.
|
||||||
|
|
||||||
|
Determine VERSION automatically based on git magic:
|
||||||
|
release tags or hash values.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.59
|
||||||
|
Fix regression in 2.58 which caused failure to start up
|
||||||
|
with some combinations of dnsmasq config and IPv6 kernel
|
||||||
|
network config. Thanks to Brielle Bruns for the bug
|
||||||
|
report.
|
||||||
|
|
||||||
|
Improve dnsmasq's behaviour when network interfaces are
|
||||||
|
still doing duplicate address detection (DAD). Previously,
|
||||||
|
dnsmasq would wait up to 20 seconds at start-up for the
|
||||||
|
DAD state to terminate. This is broken for bridge
|
||||||
|
interfaces on recent Linux kernels, which don't start DAD
|
||||||
|
until the bridge comes up, and so can take arbitrary
|
||||||
|
time. The new behaviour lets dnsmasq poll for an arbitrary
|
||||||
|
time whilst providing service on other interfaces. Thanks
|
||||||
|
to Stephen Hemminger for pointing out the problem.
|
||||||
|
|
||||||
|
|
||||||
version 2.58
|
version 2.58
|
||||||
Provide a definition of the SA_SIZE macro where it's
|
Provide a definition of the SA_SIZE macro where it's
|
||||||
missing. Fixes build failure on openBSD.
|
missing. Fixes build failure on openBSD.
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -38,16 +38,19 @@ IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags
|
|||||||
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs 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_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`
|
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`
|
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 \
|
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
|
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o
|
||||||
|
|
||||||
all :
|
all :
|
||||||
@cd $(SRC) && $(MAKE) \
|
@cd $(SRC) && $(MAKE) \
|
||||||
BUILD_CFLAGS="$(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS)" \
|
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS)" \
|
||||||
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(SUNOS_LIBS)" \
|
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS)" \
|
||||||
-f ../Makefile dnsmasq
|
-f ../Makefile dnsmasq
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
@@ -63,9 +66,9 @@ install-common :
|
|||||||
|
|
||||||
all-i18n :
|
all-i18n :
|
||||||
@cd $(SRC) && $(MAKE) \
|
@cd $(SRC) && $(MAKE) \
|
||||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
I18N=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||||
BUILD_CFLAGS="$(DBUS_CFLAGS) $(CT_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||||
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||||
-f ../Makefile dnsmasq
|
-f ../Makefile dnsmasq
|
||||||
@cd $(PO); for f in *.po; do \
|
@cd $(PO); for f in *.po; do \
|
||||||
cd ../$(SRC) && $(MAKE) \
|
cd ../$(SRC) && $(MAKE) \
|
||||||
|
|||||||
Executable
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Determine the version string to build into a binary.
|
||||||
|
# When building in the git repository, we can use the output
|
||||||
|
# of "git describe" which gives an unequivocal answer.
|
||||||
|
#
|
||||||
|
# Failing that, we use the contents of the VERSION file
|
||||||
|
# which has a set of references substituted into it by git.
|
||||||
|
# If we can find one which matches $v[0-9].* then we assume it's
|
||||||
|
# a version-number tag, else we just use the whole string.
|
||||||
|
|
||||||
|
# we're called with pwd == src
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
if [ -d .git ]; then
|
||||||
|
git describe
|
||||||
|
else
|
||||||
|
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]`
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo ${vers#v}
|
||||||
|
else
|
||||||
|
cat VERSION
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
search=$1
|
search=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
|
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h 2>&1 >/dev/null || \
|
||||||
grep $search 2>&1 >/dev/null ; then
|
grep $search 2>&1 >/dev/null ; then
|
||||||
exec $*
|
exec $*
|
||||||
fi
|
fi
|
||||||
|
|||||||
Vendored
+1011
File diff suppressed because it is too large.
Load diff
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/etc/init.d/dnsmasq
|
||||||
|
/etc/default/dnsmasq
|
||||||
|
/etc/dnsmasq.conf
|
||||||
|
/etc/resolvconf/update.d/dnsmasq
|
||||||
|
/etc/dbus-1/system.d/dnsmasq.conf
|
||||||
|
/etc/insserv.conf.d/dnsmasq
|
||||||
Vendored
+41
@@ -0,0 +1,41 @@
|
|||||||
|
Source: dnsmasq
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
|
||||||
|
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||||
|
Standards-Version: 3.9.2
|
||||||
|
|
||||||
|
Package: dnsmasq
|
||||||
|
Architecture: all
|
||||||
|
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||||
|
Suggests: resolvconf
|
||||||
|
Conflicts: resolvconf (<<1.15)
|
||||||
|
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||||
|
Dnsmasq is a lightweight, easy to configure, DNS forwarder and DHCP
|
||||||
|
server. It is designed to provide DNS and optionally, DHCP, to a
|
||||||
|
small network. It can serve the names of local machines which are
|
||||||
|
not in the global DNS. The DHCP server integrates with the DNS
|
||||||
|
server and allows machines with DHCP-allocated addresses
|
||||||
|
to appear in the DNS with names configured either in each host or
|
||||||
|
in a central configuration file. Dnsmasq supports static and dynamic
|
||||||
|
DHCP leases and BOOTP/TFTP for network booting of diskless machines.
|
||||||
|
|
||||||
|
Package: dnsmasq-base
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.41)
|
||||||
|
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||||
|
This package contains the dnsmasq executable and documentation, but
|
||||||
|
not the infrastructure required to run it as a system daemon. For
|
||||||
|
that, install the dnsmasq package.
|
||||||
|
|
||||||
|
Package: dnsmasq-utils
|
||||||
|
Architecture: linux-any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.40)
|
||||||
|
Description: Utilities for manipulating DHCP leases
|
||||||
|
Small utilities to query a DHCP server's lease database and
|
||||||
|
remove leases from it. These programs are distributed with dnsmasq
|
||||||
|
and may not work correctly with other DHCP servers.
|
||||||
|
|
||||||
|
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
|
||||||
|
|
||||||
|
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
On Debian GNU/Linux systems, the text of the GNU general public license is
|
||||||
|
available in the file /usr/share/common-licenses/GPL-2 or
|
||||||
|
/usr/share/common-licenses/GPL-3
|
||||||
|
|
||||||
|
The Debian package of dnsmasq was created by Simon Kelley with assistance
|
||||||
|
from Lars Bahner.
|
||||||
|
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
<policy user="root">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy user="dnsmasq">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy context="default">
|
||||||
|
<deny own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<deny send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
</busconfig>
|
||||||
|
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# This file has five functions:
|
||||||
|
# 1) to completely disable starting dnsmasq,
|
||||||
|
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
|
||||||
|
# 3) to select an alternative config file
|
||||||
|
# by setting DNSMASQ_OPTS to --conf-file=<file>
|
||||||
|
# 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for
|
||||||
|
# more configuration variables.
|
||||||
|
# 5) to stop the resolvconf package from controlling dnsmasq's
|
||||||
|
# idea of which upstream nameservers to use.
|
||||||
|
# For upgraders from very old versions, all the shell variables set
|
||||||
|
# here in previous versions are still honored by the init script
|
||||||
|
# so if you just keep your old version of this file nothing will break.
|
||||||
|
|
||||||
|
#DOMAIN_SUFFIX=`dnsdomainname`
|
||||||
|
#DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt"
|
||||||
|
|
||||||
|
# Whether or not to run the dnsmasq daemon; set to 0 to disable.
|
||||||
|
ENABLED=1
|
||||||
|
|
||||||
|
# By default search this drop directory for configuration options.
|
||||||
|
# Libvirt leaves a file here to make the system dnsmasq play nice.
|
||||||
|
# Comment out this line if you don't want this. The dpkg-* are file
|
||||||
|
# endings which cause dnsmasq to skip that file. This avoids pulling
|
||||||
|
# in backups made by dpkg.
|
||||||
|
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||||
|
|
||||||
|
# If the resolvconf package is installed, dnsmasq will use its output
|
||||||
|
# rather than the contents of /etc/resolv.conf to find upstream
|
||||||
|
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||||
|
# Not that including a "resolv-file=<filename>" line in
|
||||||
|
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||||
|
# installed: the line below must be uncommented.
|
||||||
|
#IGNORE_RESOLVCONF=yes
|
||||||
Vendored
+266
@@ -0,0 +1,266 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: dnsmasq
|
||||||
|
# Required-Start: $network $remote_fs $syslog
|
||||||
|
# Required-Stop: $network $remote_fs $syslog
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Description: DHCP and DNS server
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
set +e # Don't exit on error status
|
||||||
|
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
DAEMON=/usr/sbin/dnsmasq
|
||||||
|
NAME=dnsmasq
|
||||||
|
DESC="DNS forwarder and DHCP server"
|
||||||
|
|
||||||
|
# Most configuration options in /etc/default/dnsmasq are deprecated
|
||||||
|
# but still honoured.
|
||||||
|
ENABLED=1
|
||||||
|
if [ -r /etc/default/$NAME ]; then
|
||||||
|
. /etc/default/$NAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the system locale, so that messages are in the correct language, and the
|
||||||
|
# charset for IDN is correct
|
||||||
|
if [ -r /etc/default/locale ]; then
|
||||||
|
. /etc/default/locale
|
||||||
|
export LANG
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -x $DAEMON || exit 0
|
||||||
|
|
||||||
|
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||||
|
if [ -f /lib/lsb/init-functions ]; then
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
else
|
||||||
|
log_warning_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_daemon_msg () {
|
||||||
|
echo -n "${1}: $2"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_end_msg () {
|
||||||
|
if [ $1 -eq 0 ]; then
|
||||||
|
echo "."
|
||||||
|
elif [ $1 -eq 255 ]; then
|
||||||
|
/bin/echo -e " (warning)."
|
||||||
|
else
|
||||||
|
/bin/echo -e " failed!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# RESOLV_CONF:
|
||||||
|
# If the resolvconf package is installed then use the resolv conf file
|
||||||
|
# that it provides as the default. Otherwise use /etc/resolv.conf as
|
||||||
|
# the default.
|
||||||
|
#
|
||||||
|
# If IGNORE_RESOLVCONF is set in /etc/default/dnsmasq or an explicit
|
||||||
|
# filename is set there then this inhibits the use of the resolvconf-provided
|
||||||
|
# information.
|
||||||
|
#
|
||||||
|
# Note that if the resolvconf package is installed it is not possible to
|
||||||
|
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
|
||||||
|
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
|
||||||
|
|
||||||
|
if [ ! "$RESOLV_CONF" ] &&
|
||||||
|
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||||
|
[ -x /sbin/resolvconf ]
|
||||||
|
then
|
||||||
|
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_EXCEPT; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! "$DNSMASQ_USER" ]; then
|
||||||
|
DNSMASQ_USER="dnsmasq"
|
||||||
|
fi
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been started
|
||||||
|
# 1 if daemon was already running
|
||||||
|
# 2 if daemon could not be started
|
||||||
|
|
||||||
|
# /var/run may be volatile, so we need to ensure that
|
||||||
|
# /var/run/dnsmasq exists here as well as in postinst
|
||||||
|
if [ ! -d /var/run/dnsmasq ]; then
|
||||||
|
mkdir /var/run/dnsmasq || return 2
|
||||||
|
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||||
|
-x /var/run/dnsmasq/$NAME.pid \
|
||||||
|
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||||
|
${MAILTARGET:+ -t $MAILTARGET} \
|
||||||
|
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||||
|
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
|
||||||
|
${DHCP_LEASE:+ -l $DHCP_LEASE} \
|
||||||
|
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
|
||||||
|
${RESOLV_CONF:+ -r $RESOLV_CONF} \
|
||||||
|
${CACHESIZE:+ -c $CACHESIZE} \
|
||||||
|
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
|
||||||
|
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
|
||||||
|
|| return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
start_resolvconf()
|
||||||
|
{
|
||||||
|
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
|
||||||
|
# Then dnsmasq won't be providing local DNS, so don't add it to
|
||||||
|
# the resolvconf server set.
|
||||||
|
for interface in $DNSMASQ_EXCEPT
|
||||||
|
do
|
||||||
|
[ $interface = lo ] && return
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been stopped
|
||||||
|
# 1 if daemon was already stopped
|
||||||
|
# 2 if daemon could not be stopped
|
||||||
|
# other if a failure occurred
|
||||||
|
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||||
|
RETVAL="$?"
|
||||||
|
[ "$RETVAL" = 2 ] && return 2
|
||||||
|
return "$RETVAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_resolvconf()
|
||||||
|
{
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
/sbin/resolvconf -d lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
status()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon is running
|
||||||
|
# 1 if daemon is dead and pid file exists
|
||||||
|
# 3 if daemon is not running
|
||||||
|
# 4 if daemon status is unknown
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||||
|
case "$?" in
|
||||||
|
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||||
|
1) return 0 ;;
|
||||||
|
*) return 4 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
test "$ENABLED" != "0" || exit 0
|
||||||
|
log_daemon_msg "Starting $DESC" "$NAME"
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
log_success_msg "(already running)"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_resolvconf
|
||||||
|
if [ "$ENABLED" != "0" ]; then
|
||||||
|
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||||
|
fi
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
if [ "$ENABLED" = "0" ]; then
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_end_msg 0 ; exit 0 ;;
|
||||||
|
1) log_warning_msg "(not running)" ; exit 0 ;;
|
||||||
|
*) log_end_msg 1; exit 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
test "$ENABLED" != "0" || exit 1
|
||||||
|
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
NAME="configuration syntax check"
|
||||||
|
RETVAL="2"
|
||||||
|
else
|
||||||
|
stop_resolvconf
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
fi
|
||||||
|
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||||
|
case "$RETVAL" in
|
||||||
|
0|1)
|
||||||
|
sleep 2
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
log_daemon_msg "Checking $DESC" "$NAME"
|
||||||
|
status
|
||||||
|
case "$?" in
|
||||||
|
0) log_success_msg "(running)" ; exit 0 ;;
|
||||||
|
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
|
||||||
|
3) log_success_msg "(not running)" ; exit 3 ;;
|
||||||
|
*) log_success_msg "(unknown)" ; exit 4 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
$named dnsmasq
|
||||||
Vendored
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# create a user to run as (code stolen from dovecot-common)
|
||||||
|
if [ "$1" = "configure" ]; then
|
||||||
|
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||||
|
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||||
|
--no-create-home --disabled-password \
|
||||||
|
--quiet dnsmasq || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make the directory where we keep the pid file - this
|
||||||
|
# has to be owned by "dnsmasq" do that the file can be unlinked.
|
||||||
|
if [ ! -d /var/run/dnsmasq ]; then
|
||||||
|
mkdir /var/run/dnsmasq
|
||||||
|
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||||
|
fi
|
||||||
|
|
||||||
|
# handle new location of pidfile during an upgrade
|
||||||
|
if [ -e /var/run/dnsmasq.pid ]; then
|
||||||
|
mv /var/run/dnsmasq.pid /var/run/dnsmasq
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x /etc/init.d/dnsmasq ]; then
|
||||||
|
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||||
|
|
||||||
|
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||||
|
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
|
||||||
|
ACTION=restart
|
||||||
|
else
|
||||||
|
ACTION=start
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq $ACTION || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq $ACTION || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dpkg can botch the change of /usr/share/doc/dnsmasq from
|
||||||
|
# directory to symlink. Fix up here.
|
||||||
|
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
|
||||||
|
cd /usr/share/doc/
|
||||||
|
ln -s /usr/share/doc/dnsmasq-base dnsmasq
|
||||||
|
fi
|
||||||
|
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ purge = "$1" ]; then
|
||||||
|
update-rc.d dnsmasq remove >/dev/null
|
||||||
|
if [ -x "$(command -v deluser)" ]; then
|
||||||
|
deluser --quiet --system dnsmasq > /dev/null || true
|
||||||
|
else
|
||||||
|
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||||
|
fi
|
||||||
|
rm -rf /var/run/dnsmasq
|
||||||
|
fi
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" = "remove" ]; then
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq stop || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq stop || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
||||||
Vendored
+70
@@ -0,0 +1,70 @@
|
|||||||
|
Notes on configuring dnsmasq as packaged for Debian.
|
||||||
|
|
||||||
|
(1) To configure dnsmasq edit /etc/dnsmasq.conf. The file is well
|
||||||
|
commented; see also the dnsmasq.8 man page for explanation of
|
||||||
|
the options. The file /etc/default/dnsmasq also exists but it
|
||||||
|
shouldn't need to be touched in most cases. To set up DHCP
|
||||||
|
options you might need to refer to a copy of RFC 2132. This is
|
||||||
|
available on Debian systems in the package doc-rfc-std as the file
|
||||||
|
/usr/share/doc/RFC/draft-standard/rfc2132.txt.gz .
|
||||||
|
|
||||||
|
(2) Installing the dnsmasq package also creates the directory
|
||||||
|
/etc/dnsmasq.d which is searched by dnsmasq for configuration file
|
||||||
|
fragments. This behaviour can be disabled by editing
|
||||||
|
/etc/default/dnsmasq.
|
||||||
|
|
||||||
|
(3) If the Debian resolvconf package is installed then, regardless
|
||||||
|
of what interface configuration daemons are employed, the list of
|
||||||
|
nameservers to which dnsmasq should forward queries can be found
|
||||||
|
in /var/run/dnsmasq/resolv.conf; also, 127.0.0.1 is listed as the
|
||||||
|
first nameserver address in /etc/resolv.conf. This works using the
|
||||||
|
default configurations of resolvconf and dnsmasq.
|
||||||
|
|
||||||
|
(4) In the absence of resolvconf, if you are using dhcpcd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/dhcpc/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(5) In the absence of resolvconf, if you are using pppd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/ppp/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(6) In the absence of resolvconf, dns-nameservers lines in
|
||||||
|
/etc/network/interfaces are ignored. If you do do not use
|
||||||
|
resolvconf, list 127.0.0.1 as the first nameserver address
|
||||||
|
in /etc/resolv.conf and configure your nameservers using
|
||||||
|
"server=<IP-address>" lines in /etc/dnsmasq.conf.
|
||||||
|
|
||||||
|
(7) If you run multiple DNS servers on a single machine, each
|
||||||
|
listening on a different interface, then it is necessary to use
|
||||||
|
the bind-interfaces option by uncommenting "bind-interfaces" in
|
||||||
|
/etc/dnsmasq.conf. This option stops dnsmasq from binding the
|
||||||
|
wildcard address and allows servers listening on port 53 on
|
||||||
|
interfaces not in use by dnsmasq to work. The Debian
|
||||||
|
libvirt package will add a configuration file in /etc/dnsmasq.d
|
||||||
|
which does this so that the "system" dnsmasq and "private" dnsmasq
|
||||||
|
instances started by libvirt do not clash.
|
||||||
|
|
||||||
|
(8) The following options are supported in DEB_BUILD_OPTIONS
|
||||||
|
noopt : compile without optimisation.
|
||||||
|
nostrip : don't remove symbols from binary.
|
||||||
|
nodocs : omit documentation.
|
||||||
|
notftp : omit TFTP support.
|
||||||
|
nodhcp : omit DHCP support.
|
||||||
|
noscript : omit lease-change script support.
|
||||||
|
noipv6 : omit IPv6 support.
|
||||||
|
nodbus : omit DBus support.
|
||||||
|
noconntrack : omit connection tracking support.
|
||||||
|
nortc : compile alternate mode suitable for systems without an RTC.
|
||||||
|
noi18n : omit translations and internationalisation support.
|
||||||
|
noidn : omit international domain name support, must be
|
||||||
|
combined with noi18n to be effective.
|
||||||
|
|
||||||
|
(9) Dnsmasq comes as two packages - dnsmasq-base and
|
||||||
|
dnsmasq. dnsmasq-base provides the dnsmasq executable and
|
||||||
|
documentation (including this file). Dnsmasq, which depends on
|
||||||
|
dnsmasq-base, provides the init script and configuration
|
||||||
|
infrastructure. This file assumes that both are installed. It is
|
||||||
|
possible to install only dnsmasq-base and use dnsmasq as a
|
||||||
|
non-"system" daemon. Libvirt, for instance, does this.
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# All files in this directory will be read by dnsmasq as
|
||||||
|
# configuration files, except if their names end in
|
||||||
|
# ".dpkg-dist",".dpkg-old" or ".dpkg-new"
|
||||||
|
#
|
||||||
|
# This can be changed by editing /etc/default/dnsmasq
|
||||||
|
|
||||||
|
|
||||||
Vendored
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Script to update the resolver list for dnsmasq
|
||||||
|
#
|
||||||
|
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||||
|
# If dnsmasq is installed then we go ahead and update
|
||||||
|
# the resolver list in case dnsmasq is started later.
|
||||||
|
#
|
||||||
|
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||||
|
#
|
||||||
|
# Requires bash because it uses a non-POSIX printf extension.
|
||||||
|
#
|
||||||
|
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RUN_DIR="/var/run/dnsmasq"
|
||||||
|
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||||
|
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||||
|
|
||||||
|
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||||
|
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||||
|
|
||||||
|
PATH=/bin:/sbin
|
||||||
|
|
||||||
|
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||||
|
|
||||||
|
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||||
|
# Doesn't work properly if an argument itself contain whitespace
|
||||||
|
uniquify()
|
||||||
|
{
|
||||||
|
RSLT=""
|
||||||
|
while [ "$1" ] ; do
|
||||||
|
for E in $RSLT ; do
|
||||||
|
[ "$1" = "$E" ] && { shift ; continue 2 ; }
|
||||||
|
done
|
||||||
|
RSLT="${RSLT:+$RSLT }$1"
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||||
|
report_err "Failed trying to create directory $RUN_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||||
|
|
||||||
|
NMSRVRS=""
|
||||||
|
if [ "$RSLVCNFFILES" ] ; then
|
||||||
|
uniquify $(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
|
||||||
|
NMSRVRS="$RSLT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||||
|
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||||
|
# within one second of the previous one then dnsmasq may fail to notice the
|
||||||
|
# more recent change. To work around this problem we sleep here to ensure
|
||||||
|
# that the new mtime is different.
|
||||||
|
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean_up() { rm -f "$TMP_FILE" ; }
|
||||||
|
trap clean_up EXIT
|
||||||
|
: >| "$TMP_FILE"
|
||||||
|
for N in $NMSRVRS ; do echo "nameserver $N" >> "$TMP_FILE" ; done
|
||||||
|
mv -f "$TMP_FILE" "$RSLVRLIST_FILE"
|
||||||
|
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Resolvconf packaging event hook script for the dnsmasq package
|
||||||
|
restart_dnsmasq() {
|
||||||
|
if which invoke-rc.d >/dev/null 2>&1 ; then
|
||||||
|
invoke-rc.d dnsmasq restart
|
||||||
|
elif [ -x /etc/init.d/dnsmasq ] ; then
|
||||||
|
/etc/init.d/dnsmasq restart
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install) restart_dnsmasq ;;
|
||||||
|
esac
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# debian/rules file - for dnsmasq.
|
||||||
|
# Copyright 2001-2011 by Simon Kelley
|
||||||
|
# Based on the sample in the debian hello package which carries the following:
|
||||||
|
# Copyright 1994,1995 by Ian Jackson.
|
||||||
|
# I hereby give you perpetual unlimited permission to copy,
|
||||||
|
# modify and relicense this file, provided that you do not remove
|
||||||
|
# my name from the file itself. (I assert my moral right of
|
||||||
|
# paternity under the Copyright, Designs and Patents Act 1988.)
|
||||||
|
# This file may have to be extensively modified
|
||||||
|
|
||||||
|
package=dnsmasq-base
|
||||||
|
|
||||||
|
# policy manual, section 10.1
|
||||||
|
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||||
|
CFLAGS = -g -O0 -Wall -W
|
||||||
|
else
|
||||||
|
CFLAGS = -g -O2 -Wall -W
|
||||||
|
endif
|
||||||
|
|
||||||
|
COPTS =
|
||||||
|
TARGET = install-i18n
|
||||||
|
|
||||||
|
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||||
|
|
||||||
|
ifeq (,$(findstring nodbus,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_DBUS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (,$(findstring noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
COPTS += -DHAVE_CONNTRACK
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noipv6,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_IPV6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring notftp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_TFTP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring nodhcp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_DHCP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noscript,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_SCRIPT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring nortc,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_BROKEN_RTC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noi18n,$(DEB_BUILD_OPTIONS)))
|
||||||
|
TARGET = install
|
||||||
|
ifeq (,$(findstring noidn, $(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_IDN
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||||
|
make clean
|
||||||
|
make -C contrib/wrt clean
|
||||||
|
|
||||||
|
binary-indep: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/daemon/DEBIAN \
|
||||||
|
-d debian/daemon/usr/share/doc \
|
||||||
|
-d debian/daemon/etc/init.d \
|
||||||
|
-d debian/daemon/etc/dnsmasq.d \
|
||||||
|
-d debian/daemon/etc/resolvconf/update.d \
|
||||||
|
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||||
|
-d debian/daemon/etc/default \
|
||||||
|
-d debian/daemon/etc/dbus-1/system.d \
|
||||||
|
-d debian/daemon/lib/systemd/system \
|
||||||
|
-d debian/daemon/etc/insserv.conf.d
|
||||||
|
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||||
|
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||||
|
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||||
|
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||||
|
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||||
|
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||||
|
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
|
||||||
|
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||||
|
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||||
|
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||||
|
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
|
||||||
|
chown -R root.root debian/daemon
|
||||||
|
chmod -R g-ws debian/daemon
|
||||||
|
dpkg --build debian/daemon ..
|
||||||
|
|
||||||
|
binary-arch: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/base
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/base/DEBIAN \
|
||||||
|
-d debian/base/usr/share/doc/$(package) \
|
||||||
|
-d debian/base/usr/share/doc/$(package)/examples \
|
||||||
|
-d debian/base/var/run \
|
||||||
|
-d debian/base/var/lib/misc
|
||||||
|
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||||
|
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||||
|
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||||
|
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
|
||||||
|
endif
|
||||||
|
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||||
|
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||||
|
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||||
|
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||||
|
for f in debian/base/usr/share/man/*; do \
|
||||||
|
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||||
|
gzip -9 $$f/man8/dnsmasq.8 ; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||||
|
endif
|
||||||
|
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
|
||||||
|
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
|
||||||
|
chown -R root.root debian/base
|
||||||
|
chmod -R g-ws debian/base
|
||||||
|
dpkg --build debian/base ..
|
||||||
|
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
rm -rf debian/utils
|
||||||
|
install -m 755 -d debian/utils/DEBIAN \
|
||||||
|
-d debian/utils/usr/share/man/man1 \
|
||||||
|
-d debian/utils/usr/bin \
|
||||||
|
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||||
|
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||||
|
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||||
|
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
endif
|
||||||
|
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||||
|
chown -R root.root debian/utils
|
||||||
|
chmod -R g-ws debian/utils
|
||||||
|
dpkg --build debian/utils ..
|
||||||
|
endif
|
||||||
|
|
||||||
|
define checkdir
|
||||||
|
test -f Makefile -a -f debian/rules
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Below here is fairly generic really
|
||||||
|
|
||||||
|
binary: binary-arch binary-indep
|
||||||
|
build:
|
||||||
|
|
||||||
|
checkroot:
|
||||||
|
test root = "`whoami`"
|
||||||
|
|
||||||
|
.PHONY: binary binary-arch binary-indep clean checkroot
|
||||||
|
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
1.0
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=A lightweight DHCP and caching DNS server
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=uk.org.thekelleys.dnsmasq
|
||||||
|
|
||||||
|
# Test the config file and refuse starting if it is not valid.
|
||||||
|
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||||
|
|
||||||
|
# Enable DBus by default because we use DBus activation.
|
||||||
|
#
|
||||||
|
# Drop privileges and become the 'dnsmasq' user. It is recommended by dnsmasq
|
||||||
|
# upstream to run dnsmasq as an isolated user that does not run any other
|
||||||
|
# processes, owns no files and has no shell. The default 'nobody' user has a
|
||||||
|
# shell and might be used for other processes.
|
||||||
|
#
|
||||||
|
# Debian-specific: add /etc/dnsmasq.d to config search path (with the exception
|
||||||
|
# of .dpkg-*). Packages such as libvirt leave config files there.
|
||||||
|
#
|
||||||
|
# --pid-file without argument disables writing a PIDfile, we don't need one.
|
||||||
|
ExecStart=/usr/sbin/dnsmasq -k \
|
||||||
|
--enable-dbus \
|
||||||
|
--user=dnsmasq \
|
||||||
|
-7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new \
|
||||||
|
--pid-file
|
||||||
|
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
# 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
|
# 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.
|
||||||
@@ -304,6 +304,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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
+11
-3
@@ -51,7 +51,7 @@ apply to domain names in cnames, PTR records, TXT records etc.
|
|||||||
.B \-T, --local-ttl=<time>
|
.B \-T, --local-ttl=<time>
|
||||||
When replying with information from /etc/hosts or the DHCP leases
|
When replying with information from /etc/hosts or the DHCP leases
|
||||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||||
that the requestor should not itself cache the information. This is
|
that the requester should not itself cache the information. This is
|
||||||
the correct thing to do in almost all situations. This option allows a
|
the correct thing to do in almost all situations. This option allows a
|
||||||
time-to-live (in seconds) to be given for these replies. This will
|
time-to-live (in seconds) to be given for these replies. This will
|
||||||
reduce the load on the server at the expense of clients using stale
|
reduce the load on the server at the expense of clients using stale
|
||||||
@@ -276,7 +276,7 @@ server strictly in the order they appear in /etc/resolv.conf
|
|||||||
By default, when dnsmasq has more than one upstream server available,
|
By default, when dnsmasq has more than one upstream server available,
|
||||||
it will send queries to just one server. Setting this flag forces
|
it will send queries to just one server. Setting this flag forces
|
||||||
dnsmasq to send all queries to all available servers. The reply from
|
dnsmasq to send all queries to all available servers. The reply from
|
||||||
the server which answers first will be returned to the original requestor.
|
the server which answers first will be returned to the original requester.
|
||||||
.TP
|
.TP
|
||||||
.B --stop-dns-rebind
|
.B --stop-dns-rebind
|
||||||
Reject (and log) addresses from upstream nameservers which are in the
|
Reject (and log) addresses from upstream nameservers which are in the
|
||||||
@@ -545,7 +545,7 @@ Specify per host parameters for the DHCP server. This allows a machine
|
|||||||
with a particular hardware address to be always allocated the same
|
with a particular hardware address to be always allocated the same
|
||||||
hostname, IP address and lease time. A hostname specified like this
|
hostname, IP address and lease time. A hostname specified like this
|
||||||
overrides any supplied by the DHCP client on the machine. It is also
|
overrides any supplied by the DHCP client on the machine. It is also
|
||||||
allowable to ommit the hardware address and include the hostname, in
|
allowable to omit the hardware address and include the hostname, in
|
||||||
which case the IP address and lease times will apply to any machine
|
which case the IP address and lease times will apply to any machine
|
||||||
claiming that name. For example
|
claiming that name. For example
|
||||||
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
||||||
@@ -1134,6 +1134,14 @@ without an address specified when
|
|||||||
.B --dhcp-fqdn
|
.B --dhcp-fqdn
|
||||||
is set.
|
is set.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-client-update
|
||||||
|
Normally, when giving a DHCP lease, dnsmasq sets flags in the FQDN
|
||||||
|
option to tell the client not to attempt a DDNS update with its name
|
||||||
|
and IP address. This is because the name-IP pair is automatically
|
||||||
|
added into dnsmasq's DNS view. This flag suppresses that behaviour,
|
||||||
|
this is useful, for instance, to allow Windows clients to update
|
||||||
|
Active Directory servers. See RFC 4702 for details.
|
||||||
|
.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
|
||||||
|
|||||||
+370
-334
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
@@ -182,9 +182,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
addr->s6_addr[2] = 0;
|
addr->s6_addr[2] = 0;
|
||||||
addr->s6_addr[3] = 0;
|
addr->s6_addr[3] = 0;
|
||||||
}
|
}
|
||||||
if (!((*callback)(addr,
|
/* We have no way to determine the prefix, so we assume it's 64 for now....... */
|
||||||
|
if (!((*callback)(addr, 64,
|
||||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||||
(int)if_nametoindex(ifr->ifr_name),
|
(int)if_nametoindex(ifr->ifr_name), 0,
|
||||||
parm)))
|
parm)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|||||||
+60
-58
@@ -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,6 @@ static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
|||||||
static union bigname *big_free = NULL;
|
static union bigname *big_free = NULL;
|
||||||
static int bignames_left, hash_size;
|
static int bignames_left, hash_size;
|
||||||
static int uid = 0;
|
static int uid = 0;
|
||||||
static char *addrbuff = NULL;
|
|
||||||
|
|
||||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -75,9 +74,6 @@ void cache_init(void)
|
|||||||
struct crec *crecp;
|
struct crec *crecp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (option_bool(OPT_LOG))
|
|
||||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
|
||||||
|
|
||||||
bignames_left = daemon->cachesize/10;
|
bignames_left = daemon->cachesize/10;
|
||||||
|
|
||||||
if (daemon->cachesize > 0)
|
if (daemon->cachesize > 0)
|
||||||
@@ -639,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)
|
||||||
{
|
{
|
||||||
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))
|
||||||
@@ -657,33 +654,42 @@ 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. Note that rhash and the values in ->next are only valid
|
||||||
Then we search and bail at the first matching address that came from
|
whilst reading hosts files: the buckets are then freed, and the
|
||||||
a HOSTS file. Since the first host entry gets reverse, we know
|
->next pointer used for other things.
|
||||||
then that it must exist without searching exhaustively for it. */
|
|
||||||
|
Only insert each unique address one 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 += ((unsigned char *)addr)[i] + (j << 6) + (j << 16) - j;
|
||||||
for (i=0; i<hash_size; i++)
|
|
||||||
|
j = j % RHASHSIZE;
|
||||||
|
|
||||||
|
for (lookup = rhash[j]; lookup; lookup = lookup->next)
|
||||||
|
if ((lookup->flags & F_HOSTS) &&
|
||||||
|
(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. */
|
||||||
@@ -747,14 +753,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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
{
|
{
|
||||||
@@ -766,7 +772,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
|
||||||
@@ -798,14 +803,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. */
|
||||||
@@ -836,14 +833,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);
|
||||||
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);
|
||||||
name_count++;
|
name_count++;
|
||||||
}
|
}
|
||||||
free(canon);
|
free(canon);
|
||||||
@@ -867,6 +863,7 @@ void cache_reload(void)
|
|||||||
struct crec *cache, **up, *tmp;
|
struct crec *cache, **up, *tmp;
|
||||||
int i, total_size = daemon->cachesize;
|
int i, total_size = daemon->cachesize;
|
||||||
struct hostsfile *ah;
|
struct hostsfile *ah;
|
||||||
|
struct crec **reverse_hash;
|
||||||
|
|
||||||
cache_inserted = cache_live_freed = 0;
|
cache_inserted = cache_live_freed = 0;
|
||||||
|
|
||||||
@@ -899,14 +896,22 @@ void cache_reload(void)
|
|||||||
my_syslog(LOG_INFO, _("cleared cache"));
|
my_syslog(LOG_INFO, _("cleared cache"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(reverse_hash = whine_malloc(sizeof(struct crec *) * RHASHSIZE)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < RHASHSIZE; i++)
|
||||||
|
reverse_hash[i] = 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, reverse_hash);
|
||||||
|
|
||||||
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, reverse_hash);
|
||||||
|
|
||||||
|
free(reverse_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *get_domain(struct in_addr addr)
|
char *get_domain(struct in_addr addr)
|
||||||
@@ -1057,9 +1062,6 @@ void dump_cache(time_t now)
|
|||||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||||
daemon->queries_forwarded, daemon->local_answer);
|
daemon->queries_forwarded, daemon->local_answer);
|
||||||
|
|
||||||
if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* sum counts from different records for same server */
|
/* sum counts from different records for same server */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_COUNTED;
|
||||||
@@ -1079,8 +1081,8 @@ void dump_cache(time_t now)
|
|||||||
queries += serv1->queries;
|
queries += serv1->queries;
|
||||||
failed_queries += serv1->failed_queries;
|
failed_queries += serv1->failed_queries;
|
||||||
}
|
}
|
||||||
port = prettyprint_addr(&serv->addr, addrbuff);
|
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||||
@@ -1105,11 +1107,11 @@ void dump_cache(time_t now)
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a = addrbuff;
|
a = daemon->addrbuff;
|
||||||
if (cache->flags & F_IPV4)
|
if (cache->flags & F_IPV4)
|
||||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
else if (cache->flags & F_IPV6)
|
else if (cache->flags & F_IPV6)
|
||||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
else
|
else
|
||||||
@@ -1164,7 +1166,7 @@ void querystr(char *str, unsigned short type)
|
|||||||
|
|
||||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||||
{
|
{
|
||||||
char *source, *dest = addrbuff;
|
char *source, *dest = daemon->addrbuff;
|
||||||
char *verb = "is";
|
char *verb = "is";
|
||||||
|
|
||||||
if (!option_bool(OPT_LOG))
|
if (!option_bool(OPT_LOG))
|
||||||
@@ -1174,16 +1176,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||||
addr, addrbuff, ADDRSTRLEN);
|
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
#else
|
#else
|
||||||
strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_REVERSE)
|
if (flags & F_REVERSE)
|
||||||
{
|
{
|
||||||
dest = name;
|
dest = name;
|
||||||
name = addrbuff;
|
name = daemon->addrbuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_NEG)
|
if (flags & F_NEG)
|
||||||
|
|||||||
+208
-127
@@ -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,9 +14,8 @@
|
|||||||
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 VERSION "2.58"
|
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||||
|
#define RHASHSIZE 1024 /* hash buckets for address lookup during hostfile read */
|
||||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||||
@@ -34,12 +33,102 @@
|
|||||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||||
#define HOSTSFILE "/etc/hosts"
|
#define HOSTSFILE "/etc/hosts"
|
||||||
#define ETHERSFILE "/etc/ethers"
|
#define ETHERSFILE "/etc/ethers"
|
||||||
#ifdef __uClinux__
|
|
||||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
|
||||||
#else
|
|
||||||
# define RESOLVFILE "/etc/resolv.conf"
|
|
||||||
#endif
|
|
||||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||||
|
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||||
|
#define CHUSER "nobody"
|
||||||
|
#define CHGRP "dip"
|
||||||
|
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||||
|
#define LOG_MAX 5 /* log-queue length */
|
||||||
|
#define RANDFILE "/dev/urandom"
|
||||||
|
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||||
|
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* DBUS interface specifics */
|
||||||
|
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||||
|
|
||||||
|
/* compile-time options: uncomment below to enable or do eg.
|
||||||
|
make COPTS=-DHAVE_BROKEN_RTC
|
||||||
|
|
||||||
|
HAVE_BROKEN_RTC
|
||||||
|
define this on embedded systems which don't have an RTC
|
||||||
|
which keeps time over reboots. Causes dnsmasq to use uptime
|
||||||
|
for timing, and keep lease lengths rather than expiry times
|
||||||
|
in its leases file. This also make dnsmasq "flash disk friendly".
|
||||||
|
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
||||||
|
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
||||||
|
is in effect, the lease file is only written when a new lease is
|
||||||
|
created, or an old one destroyed. (Because those are the only times
|
||||||
|
it changes.) This vastly reduces the number of file writes, and makes
|
||||||
|
it viable to keep the lease file on a flash filesystem.
|
||||||
|
NOTE: when enabling or disabling this, be sure to delete any old
|
||||||
|
leases file, otherwise dnsmasq may get very confused.
|
||||||
|
|
||||||
|
HAVE_TFTP
|
||||||
|
define this to get dnsmasq's built-in TFTP server.
|
||||||
|
|
||||||
|
HAVE_DHCP
|
||||||
|
define this to get dnsmasq's DHCPv4 server.
|
||||||
|
|
||||||
|
HAVE_DHCP6
|
||||||
|
define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
|
||||||
|
|
||||||
|
HAVE_SCRIPT
|
||||||
|
define this to get the ability to call scripts on lease-change.
|
||||||
|
|
||||||
|
HAVE_LUASCRIPT
|
||||||
|
define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT)
|
||||||
|
|
||||||
|
HAVE_DBUS
|
||||||
|
define this if you want to link against libdbus, and have dnsmasq
|
||||||
|
support some methods to allow (re)configuration of the upstream DNS
|
||||||
|
servers via DBus.
|
||||||
|
|
||||||
|
HAVE_IDN
|
||||||
|
define this if you want international domain name support.
|
||||||
|
NOTE: for backwards compatibility, IDN support is automatically
|
||||||
|
included when internationalisation support is built, using the
|
||||||
|
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||||
|
|
||||||
|
HAVE_CONNTRACK
|
||||||
|
define this to include code which propogates conntrack marks from
|
||||||
|
incoming DNS queries to the corresponding upstream queries. This adds
|
||||||
|
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||||
|
still run happily on a kernel without conntrack support.
|
||||||
|
|
||||||
|
NO_IPV6
|
||||||
|
NO_TFTP
|
||||||
|
NO_DHCP
|
||||||
|
NO_DHCP6
|
||||||
|
NO_SCRIPT
|
||||||
|
NO_LARGEFILE
|
||||||
|
these are avilable to explictly disable compile time options which would
|
||||||
|
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
|
||||||
|
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||||
|
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||||
|
|
||||||
|
LEASEFILE
|
||||||
|
CONFFILE
|
||||||
|
RESOLVFILE
|
||||||
|
the default locations of these files are determined below, but may be overridden
|
||||||
|
in a build command line using COPTS.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* The default set of options to build. Built with these options, dnsmasq
|
||||||
|
has no library dependencies other than libc */
|
||||||
|
|
||||||
|
#define HAVE_DHCP
|
||||||
|
/* #define HAVE_DHCP6 */
|
||||||
|
#define HAVE_TFTP
|
||||||
|
#define HAVE_SCRIPT
|
||||||
|
/* #define HAVE_LUASCRIPT */
|
||||||
|
/* #define HAVE_BROKEN_RTC */
|
||||||
|
/* #define HAVE_DBUS */
|
||||||
|
/* #define HAVE_IDN */
|
||||||
|
/* #define HAVE_CONNTRACK */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Default locations for important system files. */
|
||||||
|
|
||||||
#ifndef LEASEFILE
|
#ifndef LEASEFILE
|
||||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||||
@@ -61,131 +150,34 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
#ifndef RESOLVFILE
|
||||||
#define CHUSER "nobody"
|
# if defined(__uClinux__)
|
||||||
#define CHGRP "dip"
|
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||||
#define NAMESERVER_PORT 53
|
# else
|
||||||
#define DHCP_SERVER_PORT 67
|
# define RESOLVFILE "/etc/resolv.conf"
|
||||||
#define DHCP_CLIENT_PORT 68
|
# endif
|
||||||
#define DHCP_SERVER_ALTPORT 1067
|
#endif
|
||||||
#define DHCP_CLIENT_ALTPORT 1068
|
|
||||||
#define PXE_PORT 4011
|
|
||||||
#define TFTP_PORT 69
|
|
||||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
|
||||||
#define LOG_MAX 5 /* log-queue length */
|
|
||||||
#define RANDFILE "/dev/urandom"
|
|
||||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
|
||||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
|
||||||
|
|
||||||
/* DBUS interface specifics */
|
|
||||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
|
||||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
|
||||||
|
|
||||||
/* Follows system specific switches. If you run on a
|
|
||||||
new system, you may want to edit these.
|
/* platform dependent options: these are determined automatically below
|
||||||
May replace this with Autoconf one day.
|
|
||||||
|
|
||||||
HAVE_LINUX_NETWORK
|
HAVE_LINUX_NETWORK
|
||||||
HAVE_BSD_NETWORK
|
HAVE_BSD_NETWORK
|
||||||
HAVE_SOLARIS_NETWORK
|
HAVE_SOLARIS_NETWORK
|
||||||
define exactly one of these to alter interaction with kernel networking.
|
define exactly one of these to alter interaction with kernel networking.
|
||||||
|
|
||||||
HAVE_BROKEN_RTC
|
|
||||||
define this on embedded systems which don't have an RTC
|
|
||||||
which keeps time over reboots. Causes dnsmasq to use uptime
|
|
||||||
for timing, and keep lease lengths rather than expiry times
|
|
||||||
in its leases file. This also make dnsmasq "flash disk friendly".
|
|
||||||
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
|
||||||
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
|
||||||
is in effect, the lease file is only written when a new lease is
|
|
||||||
created, or an old one destroyed. (Because those are the only times
|
|
||||||
it changes.) This vastly reduces the number of file writes, and makes
|
|
||||||
it viable to keep the lease file on a flash filesystem.
|
|
||||||
NOTE: when enabling or disabling this, be sure to delete any old
|
|
||||||
leases file, otherwise dnsmasq may get very confused.
|
|
||||||
|
|
||||||
HAVE_TFTP
|
|
||||||
define this to get dnsmasq's built-in TFTP server.
|
|
||||||
|
|
||||||
HAVE_DHCP
|
|
||||||
define this to get dnsmasq's DHCP server.
|
|
||||||
|
|
||||||
HAVE_SCRIPT
|
|
||||||
define this to get the ability to call scripts on lease-change
|
|
||||||
|
|
||||||
HAVE_GETOPT_LONG
|
HAVE_GETOPT_LONG
|
||||||
define this if you have GNU libc or GNU getopt.
|
defined when GNU-sty;e getopt_long available.
|
||||||
|
|
||||||
HAVE_ARC4RANDOM
|
HAVE_ARC4RANDOM
|
||||||
define this if you have arc4random() to get better security from DNS spoofs
|
defined if arc4random() available to get better security from DNS spoofs
|
||||||
by using really random ids (OpenBSD)
|
by using really random ids (OpenBSD)
|
||||||
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
HAVE_SOCKADDR_SA_LEN
|
||||||
define this if struct sockaddr has sa_len field (*BSD)
|
defined if struct sockaddr has sa_len field (*BSD)
|
||||||
|
|
||||||
HAVE_DBUS
|
|
||||||
define this if you want to link against libdbus, and have dnsmasq
|
|
||||||
support some methods to allow (re)configuration of the upstream DNS
|
|
||||||
servers via DBus.
|
|
||||||
|
|
||||||
HAVE_IDN
|
|
||||||
define this if you want international domain name support.
|
|
||||||
NOTE: for backwards compatibility, IDN support is automatically
|
|
||||||
included when internationalisation support is built, using the
|
|
||||||
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
|
||||||
|
|
||||||
HAVE_CONNTRACK
|
|
||||||
define this to include code which propogates conntrack marks from
|
|
||||||
incoming DNS queries to the corresponding upstream queries. This adds
|
|
||||||
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
|
||||||
still run happily on a kernel without conntrack support.
|
|
||||||
|
|
||||||
NOTES:
|
|
||||||
For Linux you should define
|
|
||||||
HAVE_LINUX_NETWORK
|
|
||||||
HAVE_GETOPT_LONG
|
|
||||||
you should NOT define
|
|
||||||
HAVE_ARC4RANDOM
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
|
|
||||||
For *BSD systems you should define
|
|
||||||
HAVE_BSD_NETWORK
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
and you MAY define
|
|
||||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
|
||||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
|
||||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* platform independent options- uncomment to enable */
|
|
||||||
#define HAVE_DHCP
|
|
||||||
#define HAVE_TFTP
|
|
||||||
#define HAVE_SCRIPT
|
|
||||||
/* #define HAVE_BROKEN_RTC */
|
|
||||||
/* #define HAVE_DBUS */
|
|
||||||
/* #define HAVE_IDN */
|
|
||||||
/* #define HAVE_CONNTRACK */
|
|
||||||
|
|
||||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
|
||||||
#ifdef NO_TFTP
|
|
||||||
#undef HAVE_TFTP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
|
|
||||||
#ifdef NO_DHCP
|
|
||||||
#undef HAVE_DHCP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
|
|
||||||
#ifdef NO_SCRIPT
|
|
||||||
#undef HAVE_SCRIPT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* platform dependent options. */
|
|
||||||
|
|
||||||
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
||||||
#if defined(__uClinux__)
|
#if defined(__uClinux__)
|
||||||
#define HAVE_LINUX_NETWORK
|
#define HAVE_LINUX_NETWORK
|
||||||
@@ -260,18 +252,12 @@ NOTES:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Decide if we're going to support IPv6 */
|
/* Decide if we're going to support IPv6 */
|
||||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
|
||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
headers don't have ntop and pton either */
|
||||||
|
|
||||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||||
# define HAVE_IPV6
|
# define HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||||
# if defined(SOL_IPV6)
|
|
||||||
# define IPV6_LEVEL SOL_IPV6
|
|
||||||
# else
|
|
||||||
# define IPV6_LEVEL IPPROTO_IPV6
|
|
||||||
# endif
|
|
||||||
#elif defined(INET_ADDRSTRLEN)
|
#elif defined(INET_ADDRSTRLEN)
|
||||||
# undef HAVE_IPV6
|
# undef HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||||
@@ -280,8 +266,103 @@ NOTES:
|
|||||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Can't do scripts without fork */
|
|
||||||
#ifdef NOFORK
|
/* rules to implement compile-time option dependencies and
|
||||||
# undef HAVE_SCRIPT
|
the NO_XXX flags */
|
||||||
|
|
||||||
|
#ifdef NO_IPV6
|
||||||
|
#undef HAVE_IPV6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_TFTP
|
||||||
|
#undef HAVE_TFTP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_DHCP
|
||||||
|
#undef HAVE_DHCP
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DHCP6 needs DHCP too */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#define HAVE_DHCP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||||
|
#undef HAVE_SCRIPT
|
||||||
|
#undef HAVE_LUASCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#define HAVE_SCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Define a string indicating which options are in use.
|
||||||
|
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||||
|
|
||||||
|
#ifdef DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
|
static char *compile_opts =
|
||||||
|
#ifndef HAVE_IPV6
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IPv6 "
|
||||||
|
#ifndef HAVE_GETOPT_LONG
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"GNU-getopt "
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
"no-RTC "
|
||||||
|
#endif
|
||||||
|
#ifdef NO_FORK
|
||||||
|
"no-MMU "
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_DBUS
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DBus "
|
||||||
|
#ifndef LOCALEDIR
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"i18n "
|
||||||
|
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IDN "
|
||||||
|
#ifndef HAVE_DHCP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DHCP "
|
||||||
|
#if defined(HAVE_DHCP)
|
||||||
|
# if !defined (HAVE_DHCP6)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"DHCPv6 "
|
||||||
|
# if !defined(HAVE_SCRIPT)
|
||||||
|
"no-scripts "
|
||||||
|
# else
|
||||||
|
# if !defined(HAVE_LUASCRIPT)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"Lua "
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TFTP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"TFTP "
|
||||||
|
#ifndef HAVE_CONNTRACK
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"conntrack";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+139
-77
@@ -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
|
||||||
@@ -23,8 +23,15 @@ struct iface_param {
|
|||||||
int ind;
|
int ind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct match_param {
|
||||||
|
int ind, matched;
|
||||||
|
struct in_addr netmask, broadcast, addr;
|
||||||
|
};
|
||||||
|
|
||||||
static int complete_context(struct in_addr local, int if_index,
|
static int complete_context(struct in_addr local, int if_index,
|
||||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
|
||||||
static int make_fd(int port)
|
static int make_fd(int port)
|
||||||
{
|
{
|
||||||
@@ -34,16 +41,22 @@ static int make_fd(int port)
|
|||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
int mtu = IP_PMTUDISC_DONT;
|
int mtu = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
int tos = IPTOS_CLASS_CS6;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
if (!fix_fd(fd) ||
|
if (!fix_fd(fd) ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||||
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#else
|
#else
|
||||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
@@ -110,7 +123,41 @@ void dhcp_init(void)
|
|||||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
||||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
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)
|
||||||
{
|
{
|
||||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||||
@@ -124,7 +171,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||||
struct in_addr iface_addr, *addrp = NULL;
|
struct in_addr iface_addr;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
struct arpreq arp_req;
|
struct arpreq arp_req;
|
||||||
@@ -140,56 +187,23 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
#endif
|
#endif
|
||||||
} control_u;
|
} control_u;
|
||||||
|
struct dhcp_bridge *bridge, *alias;
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
msg.msg_controllen = sizeof(control_u);
|
||||||
msg.msg_name = NULL;
|
msg.msg_control = control_u.control;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_name = &dest;
|
||||||
|
msg.msg_namelen = sizeof(dest);
|
||||||
msg.msg_iov = &daemon->dhcp_packet;
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
while (1)
|
if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
|
||||||
{
|
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||||
msg.msg_flags = 0;
|
|
||||||
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (sz == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expand_buf(&daemon->dhcp_packet, sz);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* expand_buf may have moved buffer */
|
|
||||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
|
||||||
msg.msg_controllen = sizeof(control_u);
|
|
||||||
msg.msg_control = control_u.control;
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
msg.msg_name = &dest;
|
|
||||||
msg.msg_namelen = sizeof(dest);
|
|
||||||
|
|
||||||
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined (HAVE_LINUX_NETWORK)
|
#if defined (HAVE_LINUX_NETWORK)
|
||||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -236,26 +250,50 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* One form of bridging on BSD has the property that packets
|
||||||
|
can be recieved on bridge interfaces which do not have an IP address.
|
||||||
|
We allow these to be treated as aliases of another interface which does have
|
||||||
|
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||||
|
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||||
|
{
|
||||||
|
for (alias = bridge->alias; alias; alias = alias->next)
|
||||||
|
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||||
|
{
|
||||||
|
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||||
|
{
|
||||||
|
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alias)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef MSG_BCAST
|
#ifdef MSG_BCAST
|
||||||
/* OpenBSD tells us when a packet was broadcast */
|
/* OpenBSD tells us when a packet was broadcast */
|
||||||
if (!(msg.msg_flags & MSG_BCAST))
|
if (!(msg.msg_flags & MSG_BCAST))
|
||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||||
|
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
addrp = &iface_addr;
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* weird libvirt-inspired access control */
|
/* weird libvirt-inspired access control */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
@@ -263,7 +301,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
|
|
||||||
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->dhcp; context; context = context->next)
|
||||||
context->current = context;
|
context->current = context;
|
||||||
@@ -271,29 +309,29 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
parm.current = NULL;
|
parm.current = NULL;
|
||||||
parm.ind = iface_index;
|
parm.ind = iface_index;
|
||||||
|
|
||||||
/* interface may have been changed by alias in iface_check, make sure it gets priority in case
|
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||||
there is more than one address on the interface in the same subnet */
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
|
||||||
{
|
{
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||||
return;
|
for a secondary */
|
||||||
}
|
struct match_param match;
|
||||||
else
|
|
||||||
{
|
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
match.matched = 0;
|
||||||
|
match.ind = iface_index;
|
||||||
|
|
||||||
|
if (!daemon->if_addrs ||
|
||||||
|
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||||
|
!match.matched)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface_addr = match.addr;
|
||||||
|
/* make sure secondary address gets priority in case
|
||||||
|
there is more than one address on the interface in the same subnet */
|
||||||
|
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||||
|
}
|
||||||
|
|
||||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||||
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||||
@@ -316,7 +354,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
dest.sin_len = sizeof(struct sockaddr_in);
|
dest.sin_len = sizeof(struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pxe_fd)
|
if (pxe_fd)
|
||||||
{
|
{
|
||||||
if (mess->ciaddr.s_addr != 0)
|
if (mess->ciaddr.s_addr != 0)
|
||||||
@@ -354,7 +392,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
pkt->ipi_ifindex = iface_index;
|
pkt->ipi_ifindex = iface_index;
|
||||||
pkt->ipi_spec_dst.s_addr = 0;
|
pkt->ipi_spec_dst.s_addr = 0;
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||||
@@ -411,6 +449,30 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check against secondary interface addresses */
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||||
|
{
|
||||||
|
struct match_param *param = vparam;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
if (if_index == param->ind)
|
||||||
|
{
|
||||||
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
|
if ( tmp->addr.sa.sa_family == AF_INET &&
|
||||||
|
tmp->addr.in.sin_addr.s_addr == local.s_addr)
|
||||||
|
{
|
||||||
|
param->matched = 1;
|
||||||
|
param->addr = local;
|
||||||
|
param->netmask = netmask;
|
||||||
|
param->broadcast = broadcast;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
||||||
of each interface (and any relay address) and does the following things:
|
of each interface (and any relay address) and does the following things:
|
||||||
|
|
||||||
|
|||||||
+220
@@ -0,0 +1,220 @@
|
|||||||
|
/* 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
|
||||||
|
|
||||||
|
struct iface_param {
|
||||||
|
struct dhcp_context *current;
|
||||||
|
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,
|
||||||
|
int scope, int if_index, void *vparam);
|
||||||
|
|
||||||
|
void dhcp6_init(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
int class = IPTOS_CLASS_CS6;
|
||||||
|
|
||||||
|
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||||
|
!fix_fd(fd) ||
|
||||||
|
!set_ipv6pktinfo(fd))
|
||||||
|
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
saddr.sin6_len = sizeof(addr.in6);
|
||||||
|
#endif
|
||||||
|
saddr.sin6_family = AF_INET6;
|
||||||
|
saddr.sin6_addr = in6addr_any;
|
||||||
|
saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
|
||||||
|
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;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param parm;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
struct msghdr msg;
|
||||||
|
int if_index = 0;
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
} control_u;
|
||||||
|
union mysockaddr from;
|
||||||
|
struct all_addr dest;
|
||||||
|
ssize_t sz;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
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->dhcp_packet;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4)
|
||||||
|
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;
|
||||||
|
dest.addr.addr6 = p.p->ipi6_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
ls -l
|
||||||
|
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* unlinked contexts are marked by context->current == context */
|
||||||
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
|
context->current = context;
|
||||||
|
|
||||||
|
parm.current = NULL;
|
||||||
|
parm.ind = if_index;
|
||||||
|
|
||||||
|
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
|
||||||
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
|
sz = dhcp6_reply(parm.current, sz);
|
||||||
|
/* ifr.ifr_name, if_index, (size_t)sz,
|
||||||
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
|
||||||
|
lease_update_file(now);
|
||||||
|
lease_update_dns();
|
||||||
|
|
||||||
|
if (sz != 0)
|
||||||
|
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, sz, &from, &dest, if_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, void *vparam)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param *param = vparam;
|
||||||
|
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
{
|
||||||
|
if ((context->flags & CONTEXT_IPV6) &&
|
||||||
|
prefix == context->prefix &&
|
||||||
|
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 (if_index == param->ind && context->current == context)
|
||||||
|
{
|
||||||
|
context->current = param->current;
|
||||||
|
param->current = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/* 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 DHCPV6_SERVER_PORT 547
|
||||||
|
#define DHCPV6_CLIENT_PORT 546
|
||||||
|
|
||||||
|
#define ALL_SERVERS "FF05::1:3"
|
||||||
|
#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
|
||||||
|
|
||||||
|
#define DHCP6SOLICIT 1
|
||||||
|
#define DHCP6ADVERTISE 2
|
||||||
|
#define DHCP6REQUEST 3
|
||||||
|
#define DHCP6CONFIRM 4
|
||||||
|
#define DHCP6RENEW 5
|
||||||
|
#define DHCP6REBIND 6
|
||||||
|
#define DHCP6REPLY 7
|
||||||
|
#define DHCP6RELEASE 8
|
||||||
|
#define DHCP6DECLINE 9
|
||||||
|
#define DHCP6RECONFIGURE 10
|
||||||
|
#define DHCP6IREQ 11
|
||||||
|
#define DHCP6RELAYFORW 12
|
||||||
|
#define DHCP6RELAYREPL 13
|
||||||
|
|
||||||
|
#define OPTION6_CLIENT_ID 1
|
||||||
|
#define OPTION6_SERVER_ID 2
|
||||||
|
#define OPTION6_IA_NA 3
|
||||||
|
#define OPTION6_IA_TA 4
|
||||||
|
#define OPTION6_IAADDR 5
|
||||||
|
#define OPTION6_ORO 6
|
||||||
|
#define OPTION6_PREFERENCE 7
|
||||||
|
#define OPTION6_ELAPSED_TIME 8
|
||||||
|
#define OPTION6_RELAY_MSG 9
|
||||||
|
#define OPTION6_AUTH 11
|
||||||
|
#define OPTION6_UNICAST 12
|
||||||
|
#define OPTION6_STATUS_CODE 13
|
||||||
|
#define OPTION6_RAPID_COMMIT 14
|
||||||
|
#define OPTION6_USER_CLASS 15
|
||||||
|
#define OPTION6_VENDOR_CLASS 16
|
||||||
|
#define OPTION6_VENDOR_OPTS 17
|
||||||
|
#define OPTION6_INTERFACE_ID 18
|
||||||
|
#define OPTION6_RECONFIGURE_MSG 19
|
||||||
|
#define OPTION6_RECONF_ACCEPT 20
|
||||||
+6
-1
@@ -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,6 +13,11 @@
|
|||||||
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/>.
|
||||||
*/
|
*/
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
#define DHCP_SERVER_ALTPORT 1067
|
||||||
|
#define DHCP_CLIENT_ALTPORT 1068
|
||||||
|
#define PXE_PORT 4011
|
||||||
|
|
||||||
#define BOOTREQUEST 1
|
#define BOOTREQUEST 1
|
||||||
#define BOOTREPLY 2
|
#define BOOTREPLY 2
|
||||||
|
|||||||
+4
-1
@@ -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,6 +14,9 @@
|
|||||||
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 NAMESERVER_PORT 53
|
||||||
|
#define TFTP_PORT 69
|
||||||
|
|
||||||
#define IN6ADDRSZ 16
|
#define IN6ADDRSZ 16
|
||||||
#define INADDRSZ 4
|
#define INADDRSZ 4
|
||||||
|
|
||||||
|
|||||||
+114
-90
@@ -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,54 +14,13 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declare static char *compiler_opts in config.h */
|
||||||
|
#define DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
struct daemon *daemon;
|
struct daemon *daemon;
|
||||||
|
|
||||||
static char *compile_opts =
|
|
||||||
#ifndef HAVE_IPV6
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"IPv6 "
|
|
||||||
#ifndef HAVE_GETOPT_LONG
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"GNU-getopt "
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
"no-RTC "
|
|
||||||
#endif
|
|
||||||
#ifdef NO_FORK
|
|
||||||
"no-MMU "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_DBUS
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DBus "
|
|
||||||
#ifndef LOCALEDIR
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"i18n "
|
|
||||||
#ifndef HAVE_DHCP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DHCP "
|
|
||||||
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
|
|
||||||
"no-scripts "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_TFTP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"TFTP "
|
|
||||||
#ifndef HAVE_CONNTRACK
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"conntrack "
|
|
||||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"IDN";
|
|
||||||
|
|
||||||
|
|
||||||
static volatile pid_t pid = 0;
|
static volatile pid_t pid = 0;
|
||||||
static volatile int pipewrite;
|
static volatile int pipewrite;
|
||||||
|
|
||||||
@@ -69,7 +28,8 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
|||||||
static void check_dns_listeners(fd_set *set, time_t now);
|
static void check_dns_listeners(fd_set *set, time_t now);
|
||||||
static void sig_handler(int sig);
|
static void sig_handler(int sig);
|
||||||
static void async_event(int pipe, time_t now);
|
static void async_event(int pipe, time_t now);
|
||||||
static void fatal_event(struct event_desc *ev);
|
static void fatal_event(struct event_desc *ev, char *msg);
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg);
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -79,7 +39,7 @@ int main (int argc, char **argv)
|
|||||||
struct iname *if_tmp;
|
struct iname *if_tmp;
|
||||||
int piperead, pipefd[2], err_pipe[2];
|
int piperead, pipefd[2], err_pipe[2];
|
||||||
struct passwd *ent_pw = NULL;
|
struct passwd *ent_pw = NULL;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
uid_t script_uid = 0;
|
uid_t script_uid = 0;
|
||||||
gid_t script_gid = 0;
|
gid_t script_gid = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -122,6 +82,8 @@ int main (int argc, char **argv)
|
|||||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||||
|
|
||||||
|
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (!daemon->lease_file)
|
if (!daemon->lease_file)
|
||||||
{
|
{
|
||||||
@@ -190,7 +152,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
daemon->listeners = create_bound_listeners();
|
create_bound_listeners(1);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
if (if_tmp->name && !if_tmp->used)
|
if (if_tmp->name && !if_tmp->used)
|
||||||
@@ -204,7 +166,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
daemon->listeners = create_wildcard_listeners();
|
create_wildcard_listeners();
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
cache_init();
|
cache_init();
|
||||||
@@ -225,9 +187,10 @@ int main (int argc, char **argv)
|
|||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
pre_allocate_sfds();
|
pre_allocate_sfds();
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* Note getpwnam returns static storage */
|
/* Note getpwnam returns static storage */
|
||||||
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
|
if (daemon->dhcp && daemon->scriptuser &&
|
||||||
|
(daemon->lease_change_command || daemon->luascript))
|
||||||
{
|
{
|
||||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||||
{
|
{
|
||||||
@@ -290,7 +253,7 @@ int main (int argc, char **argv)
|
|||||||
piperead = pipefd[0];
|
piperead = pipefd[0];
|
||||||
pipewrite = pipefd[1];
|
pipewrite = pipefd[1];
|
||||||
/* prime the pipe to load stuff first time. */
|
/* prime the pipe to load stuff first time. */
|
||||||
send_event(pipewrite, EVENT_RELOAD, 0);
|
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||||
|
|
||||||
err_pipe[1] = -1;
|
err_pipe[1] = -1;
|
||||||
|
|
||||||
@@ -313,18 +276,19 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
/* fd == -1 since we've not forked, never returns. */
|
/* fd == -1 since we've not forked, never returns. */
|
||||||
send_event(-1, EVENT_FORK_ERR, errno);
|
send_event(-1, EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
/* close our copy of write-end */
|
/* close our copy of write-end */
|
||||||
close(err_pipe[1]);
|
close(err_pipe[1]);
|
||||||
|
|
||||||
/* check for errors after the fork */
|
/* check for errors after the fork */
|
||||||
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
|
if (read_event(err_pipe[0], &ev, &msg))
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
|
|
||||||
_exit(EC_GOOD);
|
_exit(EC_GOOD);
|
||||||
}
|
}
|
||||||
@@ -336,7 +300,7 @@ int main (int argc, char **argv)
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
send_event(err_pipe[1], EVENT_FORK_ERR, errno);
|
send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
_exit(0);
|
_exit(0);
|
||||||
@@ -356,7 +320,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (getuid() == 0)
|
else if (getuid() == 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_PIDFILE, errno);
|
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,8 +340,8 @@ 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;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#ifdef HAVE_SCRIPT
|
||||||
if (daemon->dhcp && daemon->lease_change_command)
|
if (daemon->dhcp && (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
|
||||||
|
|
||||||
@@ -391,17 +355,23 @@ int main (int argc, char **argv)
|
|||||||
(setgroups(0, &dummy) == -1 ||
|
(setgroups(0, &dummy) == -1 ||
|
||||||
setgid(gp->gr_gid) == -1))
|
setgid(gp->gr_gid) == -1))
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
|
send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent_pw && ent_pw->pw_uid != 0)
|
if (ent_pw && ent_pw->pw_uid != 0)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||||
data->effective = data->permitted = data->inheritable =
|
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
if (is_dad_listeners())
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||||
|
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||||
|
|
||||||
/* Tell kernel to not clear capabilities when dropping root */
|
/* Tell kernel to not clear capabilities when dropping root */
|
||||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||||
@@ -431,26 +401,30 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (bad_capabilities != 0)
|
if (bad_capabilities != 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
|
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally drop root */
|
/* finally drop root */
|
||||||
if (setuid(ent_pw->pw_uid) == -1)
|
if (setuid(ent_pw->pw_uid) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_USER_ERR, errno);
|
send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
data->effective = data->permitted =
|
if (is_dad_listeners())
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||||
data->inheritable = 0;
|
data->inheritable = 0;
|
||||||
|
|
||||||
/* lose the setuid and setgid capbilities */
|
/* lose the setuid and setgid capbilities */
|
||||||
if (capset(hdr, data) == -1)
|
if (capset(hdr, data) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -605,6 +579,13 @@ int main (int argc, char **argv)
|
|||||||
t.tv_usec = 250000;
|
t.tv_usec = 250000;
|
||||||
tp = &t;
|
tp = &t;
|
||||||
}
|
}
|
||||||
|
/* Wake every second whilst waiting for DAD to complete */
|
||||||
|
else if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
t.tv_sec = 1;
|
||||||
|
t.tv_usec = 0;
|
||||||
|
tp = &t;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||||
@@ -659,6 +640,15 @@ int main (int argc, char **argv)
|
|||||||
now = dnsmasq_time();
|
now = dnsmasq_time();
|
||||||
|
|
||||||
check_log_writer(&wset);
|
check_log_writer(&wset);
|
||||||
|
|
||||||
|
/* Check the interfaces to see if any have exited DAD state
|
||||||
|
and if so, bind the address. */
|
||||||
|
if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
enumerate_interfaces();
|
||||||
|
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||||
|
create_bound_listeners(0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||||
@@ -753,28 +743,57 @@ static void sig_handler(int sig)
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
send_event(pipewrite, event, 0);
|
send_event(pipewrite, event, 0, NULL);
|
||||||
errno = errsave;
|
errno = errsave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_event(int fd, int event, int data)
|
void send_event(int fd, int event, int data, char *msg)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
struct iovec iov[2];
|
||||||
|
|
||||||
ev.event = event;
|
ev.event = event;
|
||||||
ev.data = data;
|
ev.data = data;
|
||||||
|
ev.msg_sz = msg ? strlen(msg) : 0;
|
||||||
|
|
||||||
|
iov[0].iov_base = &ev;
|
||||||
|
iov[0].iov_len = sizeof(ev);
|
||||||
|
iov[1].iov_base = msg;
|
||||||
|
iov[1].iov_len = ev.msg_sz;
|
||||||
|
|
||||||
/* error pipe, debug mode. */
|
/* error pipe, debug mode. */
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
else
|
else
|
||||||
/* pipe is non-blocking and struct event_desc is smaller than
|
/* pipe is non-blocking and struct event_desc is smaller than
|
||||||
PIPE_BUF, so this either fails or writes everything */
|
PIPE_BUF, so this either fails or writes everything */
|
||||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal_event(struct event_desc *ev)
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*msg = NULL;
|
||||||
|
|
||||||
|
if (evp->msg_sz != 0 &&
|
||||||
|
(buf = malloc(evp->msg_sz + 1)) &&
|
||||||
|
read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
|
||||||
|
{
|
||||||
|
buf[evp->msg_sz] = 0;
|
||||||
|
*msg = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fatal_event(struct event_desc *ev, char *msg)
|
||||||
{
|
{
|
||||||
errno = ev->data;
|
errno = ev->data;
|
||||||
|
|
||||||
@@ -793,19 +812,19 @@ static void fatal_event(struct event_desc *ev)
|
|||||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
case EVENT_USER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_HUSER_ERR:
|
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||||
die(_("failed to change user-id to %s: %s"),
|
|
||||||
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
|
|
||||||
EC_MISC);
|
|
||||||
|
|
||||||
case EVENT_GROUP_ERR:
|
case EVENT_GROUP_ERR:
|
||||||
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
|
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||||
|
|
||||||
case EVENT_PIDFILE:
|
case EVENT_PIDFILE:
|
||||||
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
|
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
case EVENT_LOG_ERR:
|
case EVENT_LOG_ERR:
|
||||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
|
case EVENT_LUA_ERR:
|
||||||
|
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,8 +833,12 @@ static void async_event(int pipe, time_t now)
|
|||||||
pid_t p;
|
pid_t p;
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
int i;
|
int i;
|
||||||
|
char *msg;
|
||||||
if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
|
|
||||||
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
|
||||||
|
if (read_event(pipe, &ev, &msg))
|
||||||
switch (ev.event)
|
switch (ev.event)
|
||||||
{
|
{
|
||||||
case EVENT_RELOAD:
|
case EVENT_RELOAD:
|
||||||
@@ -860,11 +883,11 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_KILLED:
|
case EVENT_KILLED:
|
||||||
my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXITED:
|
case EVENT_EXITED:
|
||||||
my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXEC_ERR:
|
case EVENT_EXEC_ERR:
|
||||||
@@ -873,9 +896,10 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* necessary for fatal errors in helper */
|
/* necessary for fatal errors in helper */
|
||||||
case EVENT_HUSER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_DIE:
|
case EVENT_DIE:
|
||||||
fatal_event(&ev);
|
case EVENT_LUA_ERR:
|
||||||
|
fatal_event(&ev, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_REOPEN:
|
case EVENT_REOPEN:
|
||||||
@@ -892,7 +916,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
if (daemon->tcp_pids[i] != 0)
|
if (daemon->tcp_pids[i] != 0)
|
||||||
kill(daemon->tcp_pids[i], SIGALRM);
|
kill(daemon->tcp_pids[i], SIGALRM);
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* handle pending lease transitions */
|
/* handle pending lease transitions */
|
||||||
if (daemon->helperfd != -1)
|
if (daemon->helperfd != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
+60
-13
@@ -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) */
|
||||||
@@ -39,9 +39,14 @@
|
|||||||
/* get these before config.h for IPv6 stuff... */
|
/* get these before config.h for IPv6 stuff... */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
/* Define before netinet/in.h to select API. OSX Lion onwards. */
|
||||||
|
# define __APPLE_USE_RFC_3542
|
||||||
|
#endif
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
/* and this. */
|
/* Also needed before config.h. */
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -52,6 +57,9 @@ typedef unsigned int u32;
|
|||||||
|
|
||||||
#include "dns_protocol.h"
|
#include "dns_protocol.h"
|
||||||
#include "dhcp_protocol.h"
|
#include "dhcp_protocol.h"
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#include "dhcp6_protocol.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define gettext_noop(S) (S)
|
#define gettext_noop(S) (S)
|
||||||
#ifndef LOCALEDIR
|
#ifndef LOCALEDIR
|
||||||
@@ -127,7 +135,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
|||||||
|
|
||||||
/* Async event queue */
|
/* Async event queue */
|
||||||
struct event_desc {
|
struct event_desc {
|
||||||
int event, data;
|
int event, data, msg_sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EVENT_RELOAD 1
|
#define EVENT_RELOAD 1
|
||||||
@@ -148,6 +156,7 @@ struct event_desc {
|
|||||||
#define EVENT_DIE 16
|
#define EVENT_DIE 16
|
||||||
#define EVENT_LOG_ERR 17
|
#define EVENT_LOG_ERR 17
|
||||||
#define EVENT_FORK_ERR 18
|
#define EVENT_FORK_ERR 18
|
||||||
|
#define EVENT_LUA_ERR 19
|
||||||
|
|
||||||
/* Exit codes. */
|
/* Exit codes. */
|
||||||
#define EC_GOOD 0
|
#define EC_GOOD 0
|
||||||
@@ -204,7 +213,8 @@ struct event_desc {
|
|||||||
#define OPT_DNSSEC 33
|
#define OPT_DNSSEC 33
|
||||||
#define OPT_CONSEC_ADDR 34
|
#define OPT_CONSEC_ADDR 34
|
||||||
#define OPT_CONNTRACK 35
|
#define OPT_CONNTRACK 35
|
||||||
#define OPT_LAST 36
|
#define OPT_FQDN_UPDATE 36
|
||||||
|
#define OPT_LAST 37
|
||||||
|
|
||||||
/* 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. */
|
||||||
@@ -363,7 +373,7 @@ struct server {
|
|||||||
struct irec {
|
struct irec {
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct in_addr netmask; /* only valid for IPv4 */
|
struct in_addr netmask; /* only valid for IPv4 */
|
||||||
int tftp_ok, mtu;
|
int tftp_ok, mtu, done, dad;
|
||||||
char *name;
|
char *name;
|
||||||
struct irec *next;
|
struct irec *next;
|
||||||
};
|
};
|
||||||
@@ -444,6 +454,9 @@ struct dhcp_lease {
|
|||||||
unsigned char *extradata;
|
unsigned char *extradata;
|
||||||
unsigned int extradata_len, extradata_size;
|
unsigned int extradata_len, extradata_size;
|
||||||
int last_interface;
|
int last_interface;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
char is_ipv6;
|
||||||
|
#endif
|
||||||
struct dhcp_lease *next;
|
struct dhcp_lease *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -573,6 +586,10 @@ struct dhcp_context {
|
|||||||
struct in_addr netmask, broadcast;
|
struct in_addr netmask, broadcast;
|
||||||
struct in_addr local, router;
|
struct in_addr local, router;
|
||||||
struct in_addr start, end; /* range of available addresses */
|
struct in_addr start, end; /* range of available addresses */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct in6_addr start6, end6; /* range of available addresses */
|
||||||
|
int prefix;
|
||||||
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
char *interface;
|
char *interface;
|
||||||
struct dhcp_netid netid, *filter;
|
struct dhcp_netid netid, *filter;
|
||||||
@@ -583,6 +600,7 @@ 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
|
||||||
|
|
||||||
struct ping_result {
|
struct ping_result {
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
@@ -645,6 +663,7 @@ extern struct daemon {
|
|||||||
char *mxtarget;
|
char *mxtarget;
|
||||||
char *lease_file;
|
char *lease_file;
|
||||||
char *username, *groupname, *scriptuser;
|
char *username, *groupname, *scriptuser;
|
||||||
|
char *luascript;
|
||||||
int group_set, osport;
|
int group_set, osport;
|
||||||
char *domain_suffix;
|
char *domain_suffix;
|
||||||
struct cond_domain *cond_domain;
|
struct cond_domain *cond_domain;
|
||||||
@@ -660,7 +679,7 @@ 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;
|
struct dhcp_context *dhcp, *dhcp6;
|
||||||
struct dhcp_config *dhcp_conf;
|
struct dhcp_config *dhcp_conf;
|
||||||
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
||||||
struct dhcp_vendor *dhcp_vendors;
|
struct dhcp_vendor *dhcp_vendors;
|
||||||
@@ -716,7 +735,12 @@ extern struct daemon {
|
|||||||
struct ping_result *ping_results;
|
struct ping_result *ping_results;
|
||||||
FILE *lease_stream;
|
FILE *lease_stream;
|
||||||
struct dhcp_bridge *bridges;
|
struct dhcp_bridge *bridges;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int duid_len;
|
||||||
|
unsigned char *duid;
|
||||||
|
struct iovec outpacket;
|
||||||
|
int dhcp6fd;
|
||||||
|
#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 */
|
||||||
void *dbus;
|
void *dbus;
|
||||||
@@ -727,6 +751,9 @@ extern struct daemon {
|
|||||||
/* TFTP stuff */
|
/* TFTP stuff */
|
||||||
struct tftp_transfer *tftp_trans;
|
struct tftp_transfer *tftp_trans;
|
||||||
|
|
||||||
|
/* utility string buffer, hold max sized IP address as string */
|
||||||
|
char *addrbuff;
|
||||||
|
|
||||||
} *daemon;
|
} *daemon;
|
||||||
|
|
||||||
/* cache.c */
|
/* cache.c */
|
||||||
@@ -785,6 +812,9 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
|||||||
int hostname_isequal(char *a, char *b);
|
int hostname_isequal(char *a, char *b);
|
||||||
time_t dnsmasq_time(void);
|
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
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||||
|
#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);
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||||
@@ -820,6 +850,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
union mysockaddr *local_addr, struct in_addr netmask);
|
union mysockaddr *local_addr, struct in_addr netmask);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
struct frec *get_new_frec(time_t now, int *wait);
|
struct frec *get_new_frec(time_t now, int *wait);
|
||||||
|
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
|
union mysockaddr *to, struct all_addr *source,
|
||||||
|
unsigned int iface);
|
||||||
|
|
||||||
/* network.c */
|
/* network.c */
|
||||||
int indextoname(int fd, int index, char *name);
|
int indextoname(int fd, int index, char *name);
|
||||||
@@ -829,16 +862,21 @@ void pre_allocate_sfds(void);
|
|||||||
int reload_servers(char *fname);
|
int reload_servers(char *fname);
|
||||||
void check_servers(void);
|
void check_servers(void);
|
||||||
int enumerate_interfaces();
|
int enumerate_interfaces();
|
||||||
struct listener *create_wildcard_listeners(void);
|
void create_wildcard_listeners(void);
|
||||||
struct listener *create_bound_listeners(void);
|
void create_bound_listeners(int die);
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
|
int is_dad_listeners(void);
|
||||||
|
int iface_check(int family, struct all_addr *addr, char *name);
|
||||||
int fix_fd(int fd);
|
int fix_fd(int fd);
|
||||||
struct in_addr get_ifaddr(char *intr);
|
struct in_addr get_ifaddr(char *intr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
#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);
|
||||||
@@ -870,7 +908,10 @@ 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_allocate(struct in_addr addr);
|
struct dhcp_lease *lease_allocate4(struct in_addr addr);
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp);
|
||||||
|
#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);
|
||||||
@@ -899,7 +940,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_event(int fd, int event, int data);
|
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);
|
||||||
|
|
||||||
@@ -949,3 +990,9 @@ void check_tftp_listeners(fd_set *rset, time_t now);
|
|||||||
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
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
|
||||||
|
|
||||||
|
/* rfc3315.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void make_duid(time_t now);
|
||||||
|
size_t dhcp6_reply(struct dhcp_context *context, size_t sz);
|
||||||
|
#endif
|
||||||
+10
-10
@@ -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
|
||||||
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
|
|||||||
|
|
||||||
/* Send a UDP packet with its source address set as "source"
|
/* Send a UDP packet with its source address set as "source"
|
||||||
unless nowild is true, when we just send it with the kernel default */
|
unless nowild is true, when we just send it with the kernel default */
|
||||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, struct all_addr *source,
|
union mysockaddr *to, struct all_addr *source,
|
||||||
unsigned int iface)
|
unsigned int iface)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
@@ -70,7 +70,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
p.ipi_spec_dst = source->addr.addr4;
|
p.ipi_spec_dst = source->addr.addr4;
|
||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
#elif defined(IP_SENDSRCADDR)
|
#elif defined(IP_SENDSRCADDR)
|
||||||
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
||||||
@@ -88,10 +88,10 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||||
cmptr->cmsg_type = daemon->v6pktinfo;
|
cmptr->cmsg_type = daemon->v6pktinfo;
|
||||||
cmptr->cmsg_level = IPV6_LEVEL;
|
cmptr->cmsg_level = IPPROTO_IPV6;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
iface = 0; /* eliminate warning */
|
(void)iface; /* eliminate warning */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +703,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -743,7 +743,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -760,7 +760,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
|
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (listen->family == AF_INET &&
|
if (listen->family == AF_INET &&
|
||||||
|
|||||||
+241
-54
@@ -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
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
|
||||||
/* This file has code to fork a helper process which recieves data via a pipe
|
/* This file has code to fork a helper process which recieves data via a pipe
|
||||||
shared with the main process and which is responsible for calling a script when
|
shared with the main process and which is responsible for calling a script when
|
||||||
DHCP leases change.
|
DHCP leases change.
|
||||||
@@ -28,11 +30,20 @@
|
|||||||
main process.
|
main process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
|
||||||
|
|
||||||
static void my_setenv(const char *name, const char *value, int *error);
|
static void my_setenv(const char *name, const char *value, int *error);
|
||||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
lua_State *lua;
|
||||||
|
|
||||||
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct script_data
|
struct script_data
|
||||||
{
|
{
|
||||||
unsigned char action, hwaddr_len, hwaddr_type;
|
unsigned char action, hwaddr_len, hwaddr_type;
|
||||||
@@ -61,7 +72,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
then fork our process. */
|
then fork our process. */
|
||||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_fd, EVENT_PIPE_ERR, errno);
|
send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,38 +99,98 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
if (option_bool(OPT_NO_FORK))
|
if (option_bool(OPT_NO_FORK))
|
||||||
/* send error to daemon process if no-fork */
|
/* send error to daemon process if no-fork */
|
||||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* kill daemon */
|
/* kill daemon */
|
||||||
send_event(event_fd, EVENT_DIE, 0);
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
/* return error */
|
/* return error */
|
||||||
send_event(err_fd, EVENT_HUSER_ERR, errno);
|
send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
}
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
|
/* close all the sockets etc, we don't need them here.
|
||||||
main process can return. */
|
Don't close err_fd, in case the lua-init fails.
|
||||||
|
Note that we have to do this before lua init
|
||||||
|
so we don't close any lua fds. */
|
||||||
for (max_fd--; max_fd >= 0; max_fd--)
|
for (max_fd--; max_fd >= 0; max_fd--)
|
||||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
|
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
|
||||||
|
max_fd != event_fd && max_fd != err_fd)
|
||||||
close(max_fd);
|
close(max_fd);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
const char *lua_err = NULL;
|
||||||
|
lua = lua_open();
|
||||||
|
luaL_openlibs(lua);
|
||||||
|
|
||||||
|
/* get Lua to load our script file */
|
||||||
|
if (luaL_dofile(lua, daemon->luascript) != 0)
|
||||||
|
lua_err = lua_tostring(lua, -1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease");
|
||||||
|
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||||
|
lua_err = _("lease() function missing in Lua script");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_err)
|
||||||
|
{
|
||||||
|
if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
|
||||||
|
/* send error to daemon process if no-fork */
|
||||||
|
send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* kill daemon */
|
||||||
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
|
/* return error */
|
||||||
|
send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
lua_getglobal(lua, "init");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
else
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* All init done, close our copy of the error pipe, so that main process can return */
|
||||||
|
if (err_fd != -1)
|
||||||
|
close(err_fd);
|
||||||
|
|
||||||
/* loop here */
|
/* loop here */
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
struct script_data data;
|
struct script_data data;
|
||||||
char *p, *action_str, *hostname = 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, *alloc_buff = NULL;
|
unsigned char *end, *extradata, *alloc_buff = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
free(alloc_buff);
|
||||||
|
|
||||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||||
_exit(0);
|
{
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "shutdown");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.action == ACTION_DEL)
|
if (data.action == ACTION_DEL)
|
||||||
action_str = "del";
|
action_str = "del";
|
||||||
else if (data.action == ACTION_ADD)
|
else if (data.action == ACTION_ADD)
|
||||||
@@ -139,42 +210,142 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
if (i != data.hwaddr_len - 1)
|
if (i != data.hwaddr_len - 1)
|
||||||
p += sprintf(p, ":");
|
p += sprintf(p, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and CLID into packet, avoid overwrite from bad data */
|
/* expiry or length into dhcp_buff2 */
|
||||||
if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||||
|
#else
|
||||||
|
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* supplied data may just exceed normal buffer (unlikely) */
|
||||||
|
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||||
|
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!read_write(pipefd[0], buf,
|
||||||
|
data.hostname_len + data.ed_len + data.clid_len, 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* CLID into packet */
|
||||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||||
{
|
{
|
||||||
p += sprintf(p, "%.2x", buf[i]);
|
p += sprintf(p, "%.2x", buf[i]);
|
||||||
if (i != data.clid_len - 1)
|
if (i != data.clid_len - 1)
|
||||||
p += sprintf(p, ":");
|
p += sprintf(p, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and expiry or length into dhcp_buff2 */
|
buf += data.clid_len;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
if (data.hostname_len != 0)
|
||||||
|
{
|
||||||
|
char *dot;
|
||||||
|
hostname = (char *)buf;
|
||||||
|
hostname[data.hostname_len - 1] = 0;
|
||||||
|
if (!legal_hostname(hostname))
|
||||||
|
hostname = NULL;
|
||||||
|
else if ((dot = strchr(hostname, '.')))
|
||||||
|
{
|
||||||
|
domain = dot+1;
|
||||||
|
*dot = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extradata = buf + data.hostname_len;
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease"); /* function to call */
|
||||||
|
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||||
|
lua_newtable(lua); /* arg2 - data table */
|
||||||
|
|
||||||
|
if (data.clid_len != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, daemon->packet);
|
||||||
|
lua_setfield(lua, -2, "client_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(data.interface) != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, data.interface);
|
||||||
|
lua_setfield(lua, -2, "interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
lua_pushnumber(lua, data.length);
|
||||||
|
lua_setfield(lua, -2, "lease_length");
|
||||||
#else
|
#else
|
||||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
lua_pushnumber(lua, data.expires);
|
||||||
|
lua_setfield(lua, -2, "lease_expires");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, domain);
|
||||||
|
lua_setfield(lua, -2, "domain");
|
||||||
|
}
|
||||||
|
|
||||||
|
end = extradata + data.ed_len;
|
||||||
|
buf = extradata;
|
||||||
|
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||||
|
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||||
|
buf = grab_extradata_lua(buf, end, "tags");
|
||||||
|
|
||||||
/* supplied data may just exceed normal buffer (unlikely) */
|
for (i = 0; buf; i++)
|
||||||
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
|
{
|
||||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
|
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||||
|
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.giaddr.s_addr != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||||
|
lua_setfield(lua, -2, "relay_address");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||||
|
{
|
||||||
|
lua_pushnumber(lua, data.remaining_time);
|
||||||
|
lua_setfield(lua, -2, "time_remaining");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "old_hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff);
|
||||||
|
lua_setfield(lua, -2, "mac_address");
|
||||||
|
|
||||||
|
lua_pushstring(lua, inet_ntoa(data.addr));
|
||||||
|
lua_setfield(lua, -2, "ip_address");
|
||||||
|
|
||||||
|
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* no script, just lua */
|
||||||
|
if (!daemon->lease_change_command)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!read_write(pipefd[0], buf,
|
|
||||||
data.hostname_len + data.ed_len, 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* possible fork errors are all temporary resource problems */
|
/* possible fork errors are all temporary resource problems */
|
||||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
|
||||||
free(alloc_buff);
|
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* wait for child to complete */
|
/* wait for child to complete */
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
@@ -188,9 +359,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
/* On error send event back to main process for logging */
|
/* On error send event back to main process for logging */
|
||||||
if (WIFSIGNALED(status))
|
if (WIFSIGNALED(status))
|
||||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
|
send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
|
||||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
|
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,22 +384,11 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (data.hostname_len != 0)
|
if (domain)
|
||||||
{
|
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||||
char *dot;
|
|
||||||
hostname = (char *)buf;
|
end = extradata + data.ed_len;
|
||||||
hostname[data.hostname_len - 1] = 0;
|
buf = extradata;
|
||||||
if (!legal_hostname(hostname))
|
|
||||||
hostname = NULL;
|
|
||||||
else if ((dot = strchr(hostname, '.')))
|
|
||||||
{
|
|
||||||
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
|
|
||||||
*dot = 0;
|
|
||||||
}
|
|
||||||
buf += data.hostname_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
end = buf + data.ed_len;
|
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &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_OUI", &err);
|
||||||
@@ -245,7 +405,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
if (data.giaddr.s_addr != 0)
|
if (data.giaddr.s_addr != 0)
|
||||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||||
|
|
||||||
if (data.action != ACTION_DEL)
|
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);
|
||||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||||
@@ -271,7 +431,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
/* failed, send event so the main process logs the problem */
|
/* failed, send event so the main process logs the problem */
|
||||||
send_event(event_fd, EVENT_EXEC_ERR, err);
|
send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,6 +465,28 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
|
|||||||
return next + 1;
|
return next + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
|
||||||
|
{
|
||||||
|
unsigned char *next;
|
||||||
|
|
||||||
|
if (!buf || (buf == end))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (next = buf; *next != 0; next++)
|
||||||
|
if (next == end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (next != buf)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, (char *)buf);
|
||||||
|
lua_setfield(lua, -2, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* pack up lease data into a buffer */
|
/* pack up lease data into a buffer */
|
||||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||||
{
|
{
|
||||||
@@ -358,7 +540,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
#else
|
#else
|
||||||
buf->expires = lease->expires;
|
buf->expires = lease->expires;
|
||||||
#endif
|
#endif
|
||||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
|
||||||
|
if (lease->expires != 0)
|
||||||
|
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||||
|
else
|
||||||
|
buf->remaining_time = 0;
|
||||||
|
|
||||||
p = (unsigned char *)(buf+1);
|
p = (unsigned char *)(buf+1);
|
||||||
if (clid_len != 0)
|
if (clid_len != 0)
|
||||||
@@ -408,3 +594,4 @@ void helper_write(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+168
-36
@@ -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,10 +24,13 @@ static int dns_dirty, file_dirty, leases_left;
|
|||||||
void lease_init(time_t now)
|
void lease_init(time_t now)
|
||||||
{
|
{
|
||||||
unsigned long ei;
|
unsigned long ei;
|
||||||
struct in_addr addr;
|
struct all_addr addr;
|
||||||
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
|
/* These each hold a DHCP option max size 255
|
||||||
and get a terminating zero added */
|
and get a terminating zero added */
|
||||||
@@ -70,26 +73,46 @@ 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 %16s %255s %764s",
|
while (fscanf(leasestream, "%lu %255s %64s %255s %764s",
|
||||||
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
||||||
daemon->dhcp_buff, daemon->packet) == 5)
|
daemon->dhcp_buff, daemon->packet) == 5)
|
||||||
{
|
{
|
||||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
#ifdef HAVE_DHCP6
|
||||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
if (!v6pass)
|
||||||
if (hw_type == 0 && hw_len != 0)
|
#endif
|
||||||
hw_type = ARPHRD_ETHER;
|
{
|
||||||
|
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||||
addr.s_addr = inet_addr(daemon->namebuff);
|
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||||
|
if (hw_type == 0 && hw_len != 0)
|
||||||
/* decode hex in place */
|
hw_type = ARPHRD_ETHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (v6pass)
|
||||||
|
inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4);
|
||||||
|
|
||||||
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 (!(lease = lease_allocate(addr)))
|
#ifdef HAVE_DHCP6
|
||||||
|
if (v6pass)
|
||||||
|
lease = lease_allocate6(&addr.addr.addr6);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
lease = lease_allocate4(addr.addr.addr4);
|
||||||
|
|
||||||
|
if (!lease)
|
||||||
die (_("too many stored leases"), NULL, EC_MISC);
|
die (_("too many stored leases"), NULL, EC_MISC);
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -103,8 +126,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
|
||||||
|
|
||||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
#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)
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
||||||
@@ -113,6 +139,24 @@ void lease_init(time_t now)
|
|||||||
the startup synthesised SIGHUP. */
|
the startup synthesised SIGHUP. */
|
||||||
lease->new = lease->changed = 0;
|
lease->new = lease->changed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
@@ -186,11 +230,18 @@ void lease_update_file(time_t now)
|
|||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
ourprintf(&err, "%u ", lease->length);
|
ourprintf(&err, "%u ", lease->length);
|
||||||
#else
|
#else
|
||||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
||||||
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
||||||
for (i = 0; i < lease->hwaddr_len; i++)
|
for (i = 0; i < lease->hwaddr_len; i++)
|
||||||
@@ -199,8 +250,10 @@ void lease_update_file(time_t now)
|
|||||||
if (i != lease->hwaddr_len - 1)
|
if (i != lease->hwaddr_len - 1)
|
||||||
ourprintf(&err, ":");
|
ourprintf(&err, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
|
ourprintf(&err, " %s ", 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)
|
||||||
@@ -213,6 +266,43 @@ void lease_update_file(time_t now)
|
|||||||
ourprintf(&err, "*\n");
|
ourprintf(&err, "*\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->duid)
|
||||||
|
{
|
||||||
|
ourprintf(&err, "duid ");
|
||||||
|
for (i = 0; i < daemon->duid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", daemon->duid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", daemon->duid[i]);
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
ourprintf(&err, "%u ", lease->length);
|
||||||
|
#else
|
||||||
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
|
ourprintf(&err, "* %s ", daemon->addrbuff);
|
||||||
|
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||||
|
|
||||||
|
if (lease->clid && lease->clid_len != 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < lease->clid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", lease->clid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", lease->clid[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ourprintf(&err, "*\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fflush(daemon->lease_stream) != 0 ||
|
if (fflush(daemon->lease_stream) != 0 ||
|
||||||
fsync(fileno(daemon->lease_stream)) < 0)
|
fsync(fileno(daemon->lease_stream)) < 0)
|
||||||
err = errno;
|
err = errno;
|
||||||
@@ -275,7 +365,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
|||||||
if (lease->hostname)
|
if (lease->hostname)
|
||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
|
|
||||||
*up = lease->next; /* unlink */
|
*up = lease->next; /* unlink */
|
||||||
|
|
||||||
/* Put on old_leases list 'till we
|
/* Put on old_leases list 'till we
|
||||||
can run the script */
|
can run the script */
|
||||||
@@ -297,18 +387,30 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
|||||||
|
|
||||||
if (clid)
|
if (clid)
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->clid && clid_len == lease->clid_len &&
|
{
|
||||||
memcmp(clid, lease->clid, clid_len) == 0)
|
#ifdef HAVE_DHCP6
|
||||||
return lease;
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->clid && clid_len == lease->clid_len &&
|
||||||
|
memcmp(clid, lease->clid, clid_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if ((!lease->clid || !clid) &&
|
{
|
||||||
hw_len != 0 &&
|
#ifdef HAVE_DHCP6
|
||||||
lease->hwaddr_len == hw_len &&
|
if (lease->is_ipv6)
|
||||||
lease->hwaddr_type == hw_type &&
|
continue;
|
||||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
#endif
|
||||||
return lease;
|
if ((!lease->clid || !clid) &&
|
||||||
|
hw_len != 0 &&
|
||||||
|
lease->hwaddr_len == hw_len &&
|
||||||
|
lease->hwaddr_type == hw_type &&
|
||||||
|
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,9 +419,15 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
|||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->addr.s_addr == addr.s_addr)
|
{
|
||||||
return lease;
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->addr.s_addr == addr.s_addr)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,15 +439,21 @@ struct in_addr lease_find_max_addr(struct dhcp_context *context)
|
|||||||
|
|
||||||
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
{
|
||||||
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
|
#ifdef HAVE_DHCP6
|
||||||
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
|
if (lease->is_ipv6)
|
||||||
addr = lease->addr;
|
continue;
|
||||||
|
#endif
|
||||||
|
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
|
||||||
|
addr = lease->addr;
|
||||||
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dhcp_lease *lease_allocate(struct in_addr addr)
|
static struct dhcp_lease *lease_allocate(void)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
||||||
@@ -347,8 +461,6 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
|||||||
|
|
||||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||||
lease->new = 1;
|
lease->new = 1;
|
||||||
lease->addr = addr;
|
|
||||||
lease->hwaddr_len = 256; /* illegal value */
|
|
||||||
lease->expires = 1;
|
lease->expires = 1;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
lease->length = 0xffffffff; /* illegal value */
|
lease->length = 0xffffffff; /* illegal value */
|
||||||
@@ -362,6 +474,26 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
|||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dhcp_lease *lease_allocate4(struct in_addr addr)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease = lease_allocate();
|
||||||
|
lease->addr = addr;
|
||||||
|
lease->hwaddr_len = 256; /* illegal value */
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease = lease_allocate();
|
||||||
|
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||||
|
lease->is_ipv6 = 1;
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
time_t exp = now + (time_t)len;
|
time_t exp = now + (time_t)len;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -84,7 +84,7 @@ int log_start(struct passwd *ent_pw, int errfd)
|
|||||||
|
|
||||||
if (!log_reopen(daemon->log_file))
|
if (!log_reopen(daemon->log_file))
|
||||||
{
|
{
|
||||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ static void log_write(void)
|
|||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
return; /* syslogd busy, go again when select() or poll() says so */
|
return; /* syslogd busy, go again when select() or poll() says so */
|
||||||
|
|
||||||
if (errno == ENOBUFS)
|
if (errno == ENOBUFS)
|
||||||
@@ -244,7 +244,8 @@ static void log_write(void)
|
|||||||
errno == ECONNREFUSED ||
|
errno == ECONNREFUSED ||
|
||||||
errno == EISCONN ||
|
errno == EISCONN ||
|
||||||
errno == EINTR ||
|
errno == EINTR ||
|
||||||
errno == EAGAIN)
|
errno == EAGAIN ||
|
||||||
|
errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
/* try again on next syslog() call */
|
/* try again on next syslog() call */
|
||||||
connection_good = 0;
|
connection_good = 0;
|
||||||
|
|||||||
+40
-7
@@ -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
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static struct iovec iov;
|
static struct iovec iov;
|
||||||
static u32 netlink_pid;
|
static u32 netlink_pid;
|
||||||
|
|
||||||
@@ -127,7 +128,8 @@ static ssize_t netlink_recv(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* family = AF_UNSPEC finds ARP table entries. */
|
/* family = AF_UNSPEC finds ARP table entries.
|
||||||
|
family = AF_LOCAL finds MAC addresses. */
|
||||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
@@ -144,10 +146,16 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
addr.nl_pad = 0;
|
addr.nl_pad = 0;
|
||||||
addr.nl_groups = 0;
|
addr.nl_groups = 0;
|
||||||
addr.nl_pid = 0; /* address to kernel */
|
addr.nl_pid = 0; /* address to kernel */
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (family == AF_UNSPEC)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||||
|
else if (family == AF_LOCAL)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETLINK;
|
||||||
|
else
|
||||||
|
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||||
|
|
||||||
again:
|
|
||||||
req.nlh.nlmsg_len = sizeof(req);
|
req.nlh.nlmsg_len = sizeof(req);
|
||||||
req.nlh.nlmsg_type = family == AF_UNSPEC ? RTM_GETNEIGH : RTM_GETADDR;
|
|
||||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
||||||
req.nlh.nlmsg_pid = 0;
|
req.nlh.nlmsg_pid = 0;
|
||||||
req.nlh.nlmsg_seq = ++seq;
|
req.nlh.nlmsg_seq = ++seq;
|
||||||
@@ -179,7 +187,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
nl_err(h);
|
nl_err(h);
|
||||||
else if (h->nlmsg_type == NLMSG_DONE)
|
else if (h->nlmsg_type == NLMSG_DONE)
|
||||||
return 1;
|
return 1;
|
||||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC)
|
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);
|
||||||
struct rtattr *rta = IFA_RTA(ifa);
|
struct rtattr *rta = IFA_RTA(ifa);
|
||||||
@@ -222,7 +230,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addrp)
|
if (addrp)
|
||||||
if (!((*callback)(addrp, ifa->ifa_scope, ifa->ifa_index, parm)))
|
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index,
|
||||||
|
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -252,7 +261,31 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
if (inaddr && mac)
|
if (inaddr && mac)
|
||||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
|
||||||
|
{
|
||||||
|
struct ifinfomsg *link = NLMSG_DATA(h);
|
||||||
|
struct rtattr *rta = IFLA_RTA(link);
|
||||||
|
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
|
||||||
|
char *mac = NULL;
|
||||||
|
size_t maclen = 0;
|
||||||
|
|
||||||
|
while (RTA_OK(rta, len1))
|
||||||
|
{
|
||||||
|
if (rta->rta_type == IFLA_ADDRESS)
|
||||||
|
{
|
||||||
|
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||||
|
mac = (char *)(rta+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rta = RTA_NEXT(rta, len1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm)))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+94
-121
@@ -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
|
||||||
@@ -107,7 +107,7 @@ int indextoname(int fd, int index, char *name)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
int iface_check(int family, struct all_addr *addr, char *name)
|
||||||
{
|
{
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
@@ -115,7 +115,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
/* Note: have to check all and not bail out early, so that we set the
|
/* Note: have to check all and not bail out early, so that we set the
|
||||||
"used" flags. */
|
"used" flags. */
|
||||||
|
|
||||||
if (daemon->if_names || (addr && daemon->if_addrs))
|
if (daemon->if_names || daemon->if_addrs)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
struct dhcp_context *range;
|
struct dhcp_context *range;
|
||||||
@@ -134,7 +134,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
ret = tmp->used = 1;
|
ret = tmp->used = 1;
|
||||||
|
|
||||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
if (addr && tmp->addr.sa.sa_family == family)
|
if (tmp->addr.sa.sa_family == family)
|
||||||
{
|
{
|
||||||
if (family == AF_INET &&
|
if (family == AF_INET &&
|
||||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||||
@@ -151,43 +151,12 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if (indexp)
|
|
||||||
{
|
|
||||||
/* One form of bridging on BSD has the property that packets
|
|
||||||
can be recieved on bridge interfaces which do not have an IP address.
|
|
||||||
We allow these to be treated as aliases of another interface which does have
|
|
||||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
|
||||||
struct dhcp_bridge *bridge, *alias;
|
|
||||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
|
||||||
{
|
|
||||||
for (alias = bridge->alias; alias; alias = alias->next)
|
|
||||||
if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
|
|
||||||
{
|
|
||||||
int newindex;
|
|
||||||
|
|
||||||
if (!(newindex = if_nametoindex(bridge->iface)))
|
|
||||||
{
|
|
||||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*indexp = newindex;
|
|
||||||
strncpy(name, bridge->iface, IF_NAMESIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alias)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iface_allowed(struct irec **irecp, int if_index,
|
static int iface_allowed(struct irec **irecp, int if_index,
|
||||||
union mysockaddr *addr, struct in_addr netmask)
|
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int fd, mtu = 0, loopback;
|
int fd, mtu = 0, loopback;
|
||||||
@@ -202,8 +171,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
we call this routine multiple times. */
|
we call this routine multiple times. */
|
||||||
for (iface = *irecp; iface; iface = iface->next)
|
for (iface = *irecp; iface; iface = iface->next)
|
||||||
if (sockaddr_isequal(&iface->addr, addr))
|
if (sockaddr_isequal(&iface->addr, addr))
|
||||||
return 1;
|
{
|
||||||
|
iface->dad = dad;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||||
@@ -260,7 +232,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
if (!ir)
|
if (!ir)
|
||||||
{
|
{
|
||||||
if (addr->sa.sa_family == AF_INET &&
|
if (addr->sa.sa_family == AF_INET &&
|
||||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
@@ -271,7 +243,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (addr->sa.sa_family == AF_INET6 &&
|
if (addr->sa.sa_family == AF_INET6 &&
|
||||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -283,6 +255,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
iface->netmask = netmask;
|
iface->netmask = netmask;
|
||||||
iface->tftp_ok = tftp_ok;
|
iface->tftp_ok = tftp_ok;
|
||||||
iface->mtu = mtu;
|
iface->mtu = mtu;
|
||||||
|
iface->dad = dad;
|
||||||
|
iface->done = 0;
|
||||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||||
strcpy(iface->name, ifr.ifr_name);
|
strcpy(iface->name, ifr.ifr_name);
|
||||||
iface->next = *irecp;
|
iface->next = *irecp;
|
||||||
@@ -295,12 +269,13 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
static int iface_allowed_v6(struct in6_addr *local,
|
static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, void *vparam)
|
int scope, int if_index, int dad, void *vparam)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -312,7 +287,7 @@ static int iface_allowed_v6(struct in6_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 = scope;
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -330,7 +305,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
|||||||
addr.in.sin_addr = local;
|
addr.in.sin_addr = local;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int enumerate_interfaces(void)
|
int enumerate_interfaces(void)
|
||||||
@@ -355,13 +330,10 @@ int fix_fd(int fd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_sock(union mysockaddr *addr, int type)
|
static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||||
{
|
{
|
||||||
int family = addr->sa.sa_family;
|
int family = addr->sa.sa_family;
|
||||||
int fd, rc, opt = 1;
|
int fd, rc, opt = 1;
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
static int dad_count = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((fd = socket(family, type, 0)) == -1)
|
if ((fd = socket(family, type, 0)) == -1)
|
||||||
{
|
{
|
||||||
@@ -374,42 +346,27 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
port = prettyprint_addr(addr, daemon->namebuff);
|
if (dienow)
|
||||||
if (!option_bool(OPT_NOWILD))
|
{
|
||||||
sprintf(daemon->namebuff, "port %d", port);
|
port = prettyprint_addr(addr, daemon->namebuff);
|
||||||
die(_("failed to create listening socket for %s: %s"),
|
if (!option_bool(OPT_NOWILD))
|
||||||
daemon->namebuff, EC_BADNET);
|
sprintf(daemon->namebuff, "port %d", port);
|
||||||
|
die(_("failed to create listening socket for %s: %s"),
|
||||||
|
daemon->namebuff, EC_BADNET);
|
||||||
|
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (family == AF_INET6 && setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
|
||||||
{
|
|
||||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) != -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
|
||||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
|
||||||
before failing. */
|
|
||||||
if (family == AF_INET6 &&
|
|
||||||
(errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
|
||||||
dad_count++ < DAD_WAIT)
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == -1)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (type == SOCK_STREAM)
|
if (type == SOCK_STREAM)
|
||||||
@@ -422,7 +379,7 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
@@ -431,46 +388,52 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else if (!set_ipv6pktinfo(fd))
|
||||||
{
|
goto err;
|
||||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
|
||||||
handle all combinations of headers and kernel.
|
|
||||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
|
||||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
|
||||||
|
|
||||||
# ifdef IPV6_RECVPKTINFO
|
|
||||||
# ifdef IPV6_2292PKTINFO
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
{
|
|
||||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
|
||||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
|
||||||
else
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd)
|
||||||
|
{
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||||
|
handle all combinations of headers and kernel.
|
||||||
|
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||||
|
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||||
|
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
# ifdef IPV6_2292PKTINFO
|
||||||
|
else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
{
|
||||||
|
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||||
{
|
{
|
||||||
struct listener *l = NULL;
|
struct listener *l = NULL;
|
||||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
{
|
{
|
||||||
fd = make_sock(addr, SOCK_DGRAM);
|
fd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
tcpfd = make_sock(addr, SOCK_STREAM, dienow);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
@@ -481,7 +444,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
/* port must be restored to DNS port for TCP code */
|
/* port must be restored to DNS port for TCP code */
|
||||||
short save = addr->in.sin_port;
|
short save = addr->in.sin_port;
|
||||||
addr->in.sin_port = htons(TFTP_PORT);
|
addr->in.sin_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in.sin_port = save;
|
addr->in.sin_port = save;
|
||||||
}
|
}
|
||||||
# ifdef HAVE_IPV6
|
# ifdef HAVE_IPV6
|
||||||
@@ -489,7 +452,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
{
|
{
|
||||||
short save = addr->in6.sin6_port;
|
short save = addr->in6.sin6_port;
|
||||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in6.sin6_port = save;
|
addr->in6.sin6_port = save;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@@ -509,7 +472,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_wildcard_listeners(void)
|
void create_wildcard_listeners(void)
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct listener *l;
|
struct listener *l;
|
||||||
@@ -523,7 +486,7 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -535,31 +498,41 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in6.sin6_port = htons(daemon->port);
|
addr.in6.sin6_port = htons(daemon->port);
|
||||||
|
|
||||||
if (l)
|
if (l)
|
||||||
l->next = create_listeners(&addr, tftp_enabled);
|
l->next = create_listeners(&addr, tftp_enabled, 1);
|
||||||
else
|
else
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return l;
|
daemon->listeners = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_bound_listeners(void)
|
void create_bound_listeners(int dienow)
|
||||||
{
|
{
|
||||||
struct listener *new, *listeners = NULL;
|
struct listener *new;
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
if (!iface->done && !iface->dad &&
|
||||||
|
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||||
{
|
{
|
||||||
new->iface = iface;
|
new->iface = iface;
|
||||||
new->next = listeners;
|
new->next = daemon->listeners;
|
||||||
listeners = new;
|
daemon->listeners = new;
|
||||||
|
iface->done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_dad_listeners(void)
|
||||||
|
{
|
||||||
|
struct irec *iface;
|
||||||
|
|
||||||
|
if (option_bool(OPT_NOWILD))
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->dad && !iface->done)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||||
occupied port nos and reserved ones. */
|
occupied port nos and reserved ones. */
|
||||||
int random_sock(int family)
|
int random_sock(int family)
|
||||||
|
|||||||
+63
-48
@@ -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
|
||||||
@@ -112,6 +112,8 @@ struct myoption {
|
|||||||
#define LOPT_DNSSEC 301
|
#define LOPT_DNSSEC 301
|
||||||
#define LOPT_INCR_ADDR 302
|
#define LOPT_INCR_ADDR 302
|
||||||
#define LOPT_CONNTRACK 303
|
#define LOPT_CONNTRACK 303
|
||||||
|
#define LOPT_FQDN 304
|
||||||
|
#define LOPT_LUASCRIPT 305
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -229,6 +231,8 @@ static const struct myoption opts[] =
|
|||||||
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
||||||
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
|
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
|
||||||
{ "conntrack", 0, 0, LOPT_CONNTRACK },
|
{ "conntrack", 0, 0, LOPT_CONNTRACK },
|
||||||
|
{ "dhcp-client-update", 0, 0, LOPT_FQDN },
|
||||||
|
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -245,27 +249,27 @@ static struct {
|
|||||||
char * const desc;
|
char * const desc;
|
||||||
char * const arg;
|
char * const arg;
|
||||||
} usage[] = {
|
} usage[] = {
|
||||||
{ 'a', ARG_DUP, "ipaddr", gettext_noop("Specify local address(es) to listen on."), NULL },
|
{ 'a', ARG_DUP, "<ipaddr>", gettext_noop("Specify local address(es) to listen on."), NULL },
|
||||||
{ 'A', ARG_DUP, "/domain/ipaddr", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
|
{ 'A', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Return ipaddr for all hosts in specified domains."), NULL },
|
||||||
{ 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
|
{ 'b', OPT_BOGUSPRIV, NULL, gettext_noop("Fake reverse lookups for RFC1918 private address ranges."), NULL },
|
||||||
{ 'B', ARG_DUP, "ipaddr", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
|
{ 'B', ARG_DUP, "<ipaddr>", gettext_noop("Treat ipaddr as NXDOMAIN (defeats Verisign wildcard)."), NULL },
|
||||||
{ 'c', ARG_ONE, "cachesize", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
|
{ 'c', ARG_ONE, "<integer>", gettext_noop("Specify the size of the cache in entries (defaults to %s)."), "$" },
|
||||||
{ 'C', ARG_DUP, "path", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
|
{ 'C', ARG_DUP, "<path>", gettext_noop("Specify configuration file (defaults to %s)."), CONFFILE },
|
||||||
{ 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
|
{ 'd', OPT_DEBUG, NULL, gettext_noop("Do NOT fork into the background: run in debug mode."), NULL },
|
||||||
{ 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
|
{ 'D', OPT_NODOTS_LOCAL, NULL, gettext_noop("Do NOT forward queries with no domain part."), NULL },
|
||||||
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
|
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
|
||||||
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
|
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
|
||||||
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
|
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
|
||||||
{ 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
|
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
|
||||||
{ 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
|
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
|
||||||
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
|
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
|
||||||
{ LOPT_DHCP_HOST, ARG_DUP, "<filename>", gettext_noop("Read DHCP host specs from file."), NULL },
|
{ LOPT_DHCP_HOST, ARG_DUP, "<path>", gettext_noop("Read DHCP host specs from file."), NULL },
|
||||||
{ LOPT_DHCP_OPTS, ARG_DUP, "<filename>", gettext_noop("Read DHCP option specs from file."), NULL },
|
{ LOPT_DHCP_OPTS, ARG_DUP, "<path>", gettext_noop("Read DHCP option specs from file."), NULL },
|
||||||
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
|
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
|
||||||
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
|
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
|
||||||
{ 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
|
{ 'H', ARG_DUP, "<path>", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
|
||||||
{ 'i', ARG_DUP, "interface", gettext_noop("Specify interface(s) to listen on."), NULL },
|
{ 'i', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) to listen on."), NULL },
|
||||||
{ 'I', ARG_DUP, "int", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
|
{ 'I', ARG_DUP, "<interface>", gettext_noop("Specify interface(s) NOT to listen on.") , NULL },
|
||||||
{ 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
|
{ 'j', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP user class to tag."), NULL },
|
||||||
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
|
{ LOPT_CIRCUIT, ARG_DUP, "set:<tag>,<circuit>", gettext_noop("Map RFC3046 circuit-id to tag."), NULL },
|
||||||
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
|
{ LOPT_REMOTE, ARG_DUP, "set:<tag>,<remote>", gettext_noop("Map RFC3046 remote-id to tag."), NULL },
|
||||||
@@ -274,53 +278,55 @@ static struct {
|
|||||||
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
|
{ LOPT_BROADCAST, ARG_DUP, "[=tag:<tag>...]", gettext_noop("Force broadcast replies for hosts with tag set."), NULL },
|
||||||
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
|
{ 'k', OPT_NO_FORK, NULL, gettext_noop("Do NOT fork into the background, do NOT run in debug mode."), NULL },
|
||||||
{ 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
|
{ 'K', OPT_AUTHORITATIVE, NULL, gettext_noop("Assume we are the only DHCP server on the local network."), NULL },
|
||||||
{ 'l', ARG_ONE, "path", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
|
{ 'l', ARG_ONE, "<path>", gettext_noop("Specify where to store DHCP leases (defaults to %s)."), LEASEFILE },
|
||||||
{ 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
|
{ 'L', OPT_LOCALMX, NULL, gettext_noop("Return MX records for local hosts."), NULL },
|
||||||
{ 'm', ARG_DUP, "host_name,target,pref", gettext_noop("Specify an MX record."), NULL },
|
{ 'm', ARG_DUP, "<host_name>,<target>,<pref>", gettext_noop("Specify an MX record."), NULL },
|
||||||
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
|
{ 'M', ARG_DUP, "<bootp opts>", gettext_noop("Specify BOOTP options to DHCP server."), NULL },
|
||||||
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
|
{ 'n', OPT_NO_POLL, NULL, gettext_noop("Do NOT poll %s file, reload only on SIGHUP."), RESOLVFILE },
|
||||||
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
|
{ 'N', OPT_NO_NEG, NULL, gettext_noop("Do NOT cache failed search results."), NULL },
|
||||||
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
|
{ 'o', OPT_ORDER, NULL, gettext_noop("Use nameservers strictly in the order given in %s."), RESOLVFILE },
|
||||||
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
|
{ 'O', ARG_DUP, "<optspec>", gettext_noop("Specify options to be sent to DHCP clients."), NULL },
|
||||||
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
|
{ LOPT_FORCE, ARG_DUP, "<optspec>", gettext_noop("DHCP option sent even if the client does not request it."), NULL},
|
||||||
{ 'p', ARG_ONE, "number", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
|
{ 'p', ARG_ONE, "<integer>", gettext_noop("Specify port to listen for DNS requests on (defaults to 53)."), NULL },
|
||||||
{ 'P', ARG_ONE, "<size>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
|
{ 'P', ARG_ONE, "<integer>", gettext_noop("Maximum supported UDP packet size for EDNS.0 (defaults to %s)."), "*" },
|
||||||
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
|
{ 'q', OPT_LOG, NULL, gettext_noop("Log DNS queries."), NULL },
|
||||||
{ 'Q', ARG_ONE, "number", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
|
{ 'Q', ARG_ONE, "<integer>", gettext_noop("Force the originating port for upstream DNS queries."), NULL },
|
||||||
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
|
{ 'R', OPT_NO_RESOLV, NULL, gettext_noop("Do NOT read resolv.conf."), NULL },
|
||||||
{ 'r', ARG_DUP, "path", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
|
{ 'r', ARG_DUP, "<path>", gettext_noop("Specify path to resolv.conf (defaults to %s)."), RESOLVFILE },
|
||||||
{ 'S', ARG_DUP, "/domain/ipaddr", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
|
{ 'S', ARG_DUP, "/<domain>/<ipaddr>", gettext_noop("Specify address(es) of upstream servers with optional domains."), NULL },
|
||||||
{ LOPT_LOCAL, ARG_DUP, "/domain/", gettext_noop("Never forward queries to specified domains."), NULL },
|
{ LOPT_LOCAL, ARG_DUP, "/<domain>/", gettext_noop("Never forward queries to specified domains."), NULL },
|
||||||
{ 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
|
{ 's', ARG_DUP, "<domain>[,<range>]", gettext_noop("Specify the domain to be assigned in DHCP leases."), NULL },
|
||||||
{ 't', ARG_ONE, "host_name", gettext_noop("Specify default target in an MX record."), NULL },
|
{ 't', ARG_ONE, "<host_name>", gettext_noop("Specify default target in an MX record."), NULL },
|
||||||
{ 'T', ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
|
{ 'T', ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for replies from /etc/hosts."), NULL },
|
||||||
{ LOPT_NEGTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
|
{ LOPT_NEGTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for negative caching."), NULL },
|
||||||
{ LOPT_MAXTTL, ARG_ONE, "time", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
|
{ LOPT_MAXTTL, ARG_ONE, "<integer>", gettext_noop("Specify time-to-live in seconds for maximum TTL to send to clients."), NULL },
|
||||||
{ 'u', ARG_ONE, "username", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
|
{ 'u', ARG_ONE, "<username>", gettext_noop("Change to this user after startup. (defaults to %s)."), CHUSER },
|
||||||
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
|
{ 'U', ARG_DUP, "set:<tag>,<class>", gettext_noop("Map DHCP vendor class to tag."), NULL },
|
||||||
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
|
{ 'v', 0, NULL, gettext_noop("Display dnsmasq version and copyright information."), NULL },
|
||||||
{ 'V', ARG_DUP, "addr,addr,mask", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
|
{ 'V', ARG_DUP, "<ipaddr>,<ipaddr>,<netmask>", gettext_noop("Translate IPv4 addresses from upstream servers."), NULL },
|
||||||
{ 'W', ARG_DUP, "name,target,...", gettext_noop("Specify a SRV record."), NULL },
|
{ 'W', ARG_DUP, "<name>,<target>,...", gettext_noop("Specify a SRV record."), NULL },
|
||||||
{ 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
|
{ 'w', 0, NULL, gettext_noop("Display this message. Use --help dhcp for known DHCP options."), NULL },
|
||||||
{ 'x', ARG_ONE, "path", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
|
{ 'x', ARG_ONE, "<path>", gettext_noop("Specify path of PID file (defaults to %s)."), RUNFILE },
|
||||||
{ 'X', ARG_ONE, "number", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
|
{ 'X', ARG_ONE, "<integer>", gettext_noop("Specify maximum number of DHCP leases (defaults to %s)."), "&" },
|
||||||
{ 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
|
{ 'y', OPT_LOCALISE, NULL, gettext_noop("Answer DNS queries based on the interface a query was sent to."), NULL },
|
||||||
{ 'Y', ARG_DUP, "name,txt....", gettext_noop("Specify TXT DNS record."), NULL },
|
{ 'Y', ARG_DUP, "<name>,<txt>[,<txt]", gettext_noop("Specify TXT DNS record."), NULL },
|
||||||
{ LOPT_PTR, ARG_DUP, "name,target", gettext_noop("Specify PTR DNS record."), NULL },
|
{ LOPT_PTR, ARG_DUP, "<name>,<target>", gettext_noop("Specify PTR DNS record."), NULL },
|
||||||
{ LOPT_INTNAME, ARG_DUP, "name,interface", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
|
{ LOPT_INTNAME, ARG_DUP, "<name>,<interface>", gettext_noop("Give DNS name to IPv4 address of interface."), NULL },
|
||||||
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
|
{ 'z', OPT_NOWILD, NULL, gettext_noop("Bind only to interfaces in use."), NULL },
|
||||||
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
{ 'Z', OPT_ETHERS, NULL, gettext_noop("Read DHCP static host information from %s."), ETHERSFILE },
|
||||||
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
{ '1', OPT_DBUS, NULL, gettext_noop("Enable the DBus interface for setting upstream servers, etc."), NULL },
|
||||||
{ '2', ARG_DUP, "interface", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
{ '2', ARG_DUP, "<interface>", gettext_noop("Do not provide DHCP on this interface, only provide DNS."), NULL },
|
||||||
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
{ '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL },
|
||||||
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
{ '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL },
|
||||||
{ LOPT_BRIDGE, ARG_DUP, "iface,alias,..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
|
{ LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL },
|
||||||
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
|
{ '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL },
|
||||||
{ '6', ARG_ONE, "path", gettext_noop("Script to run on DHCP lease creation and destruction."), NULL },
|
{ '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL },
|
||||||
{ '7', ARG_DUP, "path", gettext_noop("Read configuration from all the files in this directory."), NULL },
|
{ LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL },
|
||||||
|
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change scripts as this user."), NULL },
|
||||||
|
{ '7', ARG_DUP, "<path>", gettext_noop("Read configuration from all the files in this directory."), NULL },
|
||||||
{ '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
|
{ '8', ARG_ONE, "<facilty>|<file>", gettext_noop("Log to this syslog facility or file. (defaults to DAEMON)"), NULL },
|
||||||
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
|
{ '9', OPT_LEASE_RO, NULL, gettext_noop("Do not use leasefile."), NULL },
|
||||||
{ '0', ARG_ONE, "<queries>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
|
{ '0', ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent DNS queries. (defaults to %s)"), "!" },
|
||||||
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
|
{ LOPT_RELOAD, OPT_RELOAD, NULL, gettext_noop("Clear DNS cache when reloading %s."), RESOLVFILE },
|
||||||
{ LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
|
{ LOPT_NO_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Ignore hostnames provided by DHCP clients."), NULL },
|
||||||
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
|
{ LOPT_OVERRIDE, OPT_NO_OVERRIDE, NULL, gettext_noop("Do NOT reuse filename and server fields for extra DHCP options."), NULL },
|
||||||
@@ -328,23 +334,22 @@ static struct {
|
|||||||
{ LOPT_PREFIX, ARG_ONE, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
{ LOPT_PREFIX, ARG_ONE, "<dir>[,<iface>]", gettext_noop("Export files by TFTP only from the specified subtree."), NULL },
|
||||||
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
{ LOPT_APREF, OPT_TFTP_APREF, NULL, gettext_noop("Add client IP address to tftp-root."), NULL },
|
||||||
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
{ LOPT_SECURE, OPT_TFTP_SECURE, NULL, gettext_noop("Allow access only to files owned by the user running dnsmasq."), NULL },
|
||||||
{ LOPT_TFTP_MAX, ARG_ONE, "<connections>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
{ LOPT_TFTP_MAX, ARG_ONE, "<integer>", gettext_noop("Maximum number of conncurrent TFTP transfers (defaults to %s)."), "#" },
|
||||||
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
{ LOPT_NOBLOCK, OPT_TFTP_NOBLOCK, NULL, gettext_noop("Disable the TFTP blocksize extension."), NULL },
|
||||||
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
|
{ LOPT_TFTPPORTS, ARG_ONE, "<start>,<end>", gettext_noop("Ephemeral port range for use by TFTP transfers."), NULL },
|
||||||
{ LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
|
{ LOPT_LOG_OPTS, OPT_LOG_OPTS, NULL, gettext_noop("Extra logging for DHCP."), NULL },
|
||||||
{ LOPT_MAX_LOGS, ARG_ONE, "[=<log lines>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
|
{ LOPT_MAX_LOGS, ARG_ONE, "[=<integer>]", gettext_noop("Enable async. logging; optionally set queue length."), NULL },
|
||||||
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
|
{ LOPT_REBIND, OPT_NO_REBIND, NULL, gettext_noop("Stop DNS rebinding. Filter private IP ranges when resolving."), NULL },
|
||||||
{ LOPT_LOC_REBND, OPT_LOCAL_REBIND, NULL, gettext_noop("Allow rebinding of 127.0.0.0/8, for RBL servers."), NULL },
|
{ LOPT_LOC_REBND, OPT_LOCAL_REBIND, NULL, gettext_noop("Allow rebinding of 127.0.0.0/8, for RBL servers."), NULL },
|
||||||
{ LOPT_NO_REBIND, ARG_DUP, "/domain/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
|
{ LOPT_NO_REBIND, ARG_DUP, "/<domain>/", gettext_noop("Inhibit DNS-rebind protection on this domain."), NULL },
|
||||||
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
|
{ LOPT_NOLAST, OPT_ALL_SERVERS, NULL, gettext_noop("Always perform DNS queries to all servers."), NULL },
|
||||||
{ LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
|
{ LOPT_MATCH, ARG_DUP, "set:<tag>,<optspec>", gettext_noop("Set tag if client includes matching option in request."), NULL },
|
||||||
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
|
{ LOPT_ALTPORT, ARG_ONE, "[=<ports>]", gettext_noop("Use alternative ports for DHCP."), NULL },
|
||||||
{ LOPT_SCRIPTUSR, ARG_ONE, "<username>", gettext_noop("Run lease-change script as this user."), NULL },
|
|
||||||
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
|
{ LOPT_NAPTR, ARG_DUP, "<name>,<naptr>", gettext_noop("Specify NAPTR DNS record."), NULL },
|
||||||
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
|
{ LOPT_MINPORT, ARG_ONE, "<port>", gettext_noop("Specify lowest port available for DNS query transmission."), NULL },
|
||||||
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
|
{ LOPT_DHCP_FQDN, OPT_DHCP_FQDN, NULL, gettext_noop("Use only fully qualified domain names for DHCP clients."), NULL },
|
||||||
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]...", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
{ LOPT_GEN_NAMES, ARG_DUP, "[=tag:<tag>]", gettext_noop("Generate hostnames based on MAC address for nameless clients."), NULL},
|
||||||
{ LOPT_PROXY, ARG_DUP, "[=<ip_address>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
{ LOPT_PROXY, ARG_DUP, "[=<ipaddr>]...", gettext_noop("Use these DHCP relays as full proxies."), NULL },
|
||||||
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
{ LOPT_CNAME, ARG_DUP, "<alias>,<target>", gettext_noop("Specify alias name for LOCAL DNS name."), NULL },
|
||||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||||
@@ -353,6 +358,7 @@ static struct {
|
|||||||
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
||||||
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
||||||
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||||
|
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1295,16 +1301,25 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
daemon->lease_file = opt_string_alloc(arg);
|
daemon->lease_file = opt_string_alloc(arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '6': /* --dhcp-script */
|
/* Sorry about the gross pre-processor abuse */
|
||||||
|
case '6': /* --dhcp-script */
|
||||||
|
case LOPT_LUASCRIPT: /* --dhcp-luascript */
|
||||||
# if defined(NO_FORK)
|
# if defined(NO_FORK)
|
||||||
problem = _("cannot run scripts under uClinux");
|
problem = _("cannot run scripts under uClinux");
|
||||||
# elif !defined(HAVE_SCRIPT)
|
# elif !defined(HAVE_SCRIPT)
|
||||||
problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
|
problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
|
||||||
# else
|
# else
|
||||||
daemon->lease_change_command = opt_string_alloc(arg);
|
if (option == LOPT_LUASCRIPT)
|
||||||
|
# if !defined(HAVE_LUASCRIPT)
|
||||||
|
problem = _("recompile with HAVE_LUASCRIPT defined to enable Lua scripts");
|
||||||
|
# else
|
||||||
|
daemon->luascript = opt_string_alloc(arg);
|
||||||
|
# endif
|
||||||
|
else
|
||||||
|
daemon->lease_change_command = opt_string_alloc(arg);
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif /* HAVE_DHCP */
|
||||||
|
|
||||||
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
||||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||||
@@ -3299,7 +3314,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
else if (option == 'v')
|
else if (option == 'v')
|
||||||
{
|
{
|
||||||
printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
|
printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
|
||||||
printf(_("Compile time options %s\n\n"), compile_opts);
|
printf(_("Compile time options: %s\n\n"), compile_opts);
|
||||||
printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
|
printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
|
||||||
printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
|
printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
|
||||||
printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
|
printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+16
-9
@@ -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
|
||||||
@@ -481,7 +481,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!message &&
|
if (!message &&
|
||||||
!lease &&
|
!lease &&
|
||||||
(!(lease = lease_allocate(mess->yiaddr))))
|
(!(lease = lease_allocate4(mess->yiaddr))))
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
@@ -521,11 +521,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
pp = op;
|
pp = op;
|
||||||
|
|
||||||
/* Always force update, since the client has no way to do it itself. */
|
/* Always force update, since the client has no way to do it itself. */
|
||||||
if (!(fqdn_flags & 0x01))
|
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
|
||||||
fqdn_flags |= 0x02;
|
fqdn_flags |= 0x03;
|
||||||
|
|
||||||
fqdn_flags &= ~0x08;
|
fqdn_flags &= ~0x08;
|
||||||
fqdn_flags |= 0x01;
|
|
||||||
|
|
||||||
if (fqdn_flags & 0x04)
|
if (fqdn_flags & 0x04)
|
||||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||||
@@ -1190,7 +1189,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
else if (!lease)
|
else if (!lease)
|
||||||
{
|
{
|
||||||
if ((lease = lease_allocate(mess->yiaddr)))
|
if ((lease = lease_allocate4(mess->yiaddr)))
|
||||||
do_classes = 1;
|
do_classes = 1;
|
||||||
else
|
else
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
@@ -1250,8 +1249,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)
|
||||||
|
add_extradata_data(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);
|
||||||
|
|||||||
+298
@@ -0,0 +1,298 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||||
|
size_t maclen, void *parm);
|
||||||
|
|
||||||
|
void make_duid(time_t now)
|
||||||
|
{
|
||||||
|
iface_enumerate(AF_LOCAL, &now, make_duid1);
|
||||||
|
|
||||||
|
if (!daemon->duid)
|
||||||
|
die("Cannot create DHCPv6 server DUID", NULL, EC_MISC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||||
|
size_t maclen, void *parm)
|
||||||
|
{
|
||||||
|
/* create DUID as specified in RFC3315. We use the MAC of the
|
||||||
|
first interface we find that isn't loopback or P-to-P */
|
||||||
|
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
if (flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
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 */
|
||||||
|
memcpy(p, mac, maclen);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
|
||||||
|
{
|
||||||
|
u16 opt, opt_len;
|
||||||
|
void *start;
|
||||||
|
|
||||||
|
if (!opts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (end - opts < 4)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = opts;
|
||||||
|
GETSHORT(opt, opts);
|
||||||
|
GETSHORT(opt_len, opts);
|
||||||
|
|
||||||
|
if (opt_len > (end - opts))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (opt == search && (opt_len >= minsize))
|
||||||
|
return start;
|
||||||
|
|
||||||
|
opts += opt_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *opt6_next(void *opts, void *end)
|
||||||
|
{
|
||||||
|
u16 opt_len;
|
||||||
|
|
||||||
|
if (end - opts < 4)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
opts += 2;
|
||||||
|
GETSHORT(opt_len, opts);
|
||||||
|
|
||||||
|
if (opt_len >= (end - opts))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return opts + opt_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define opt6_len(opt) ((int)(((unsigned short *)(opt))[1]))
|
||||||
|
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4u+(unsigned int)(i)]))
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||||
|
{
|
||||||
|
/* this worries about unaligned data and byte order */
|
||||||
|
unsigned int ret = 0;
|
||||||
|
int i;
|
||||||
|
unsigned char *p = opt6_ptr(opt, offset);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
ret = (ret << 8) | *p++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
daemon->outpacket_counter = 4; message type and ID
|
||||||
|
|
||||||
|
elapsed time:
|
||||||
|
int o = new_opt(OPTION_ELAPSED_TIME);
|
||||||
|
put_opt_short(o, 100)
|
||||||
|
finalise_opt(o);
|
||||||
|
|
||||||
|
IA_NA
|
||||||
|
|
||||||
|
int o = new_opt(OPTION_IA_NA);
|
||||||
|
put_opt_long(o, IAID);
|
||||||
|
put_opt_long(o, T1);
|
||||||
|
put_opt_long(0, T2);
|
||||||
|
int o1 = new_opt(OPTION_IAADDR);
|
||||||
|
put_opt(o1, &addr, sizeof(addr));
|
||||||
|
put_opt_long(o1, preferred_lifetime);
|
||||||
|
put_opt_long(o1, valid_lifetime);
|
||||||
|
finalise_opt(o1);
|
||||||
|
finalise_opt(o);
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void end_opt6(int container)
|
||||||
|
{
|
||||||
|
void *p = daemon->outpacket.iov_base + container + 2;
|
||||||
|
u16 len = outpacket_counter - container - 4 ;
|
||||||
|
|
||||||
|
PUTSHORT(len, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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 (data && (p = expand(len)))
|
||||||
|
memcpy(p, data, len);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_long(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (( p = expand(4)))
|
||||||
|
PUTLONG(p, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_short(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(2)))
|
||||||
|
PUTSHORT(val, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_byte(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(1)))
|
||||||
|
*((unsigned char *)p) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dhcp6_reply(struct dhcp_context *context, size_t sz)
|
||||||
|
{
|
||||||
|
void *packet_options = ((void *)daemon->dhcp_packet.iov_base) + 4;
|
||||||
|
void *end = ((void *)daemon->dhcp_packet.iov_base) + sz;
|
||||||
|
void *na_option, *na_end;
|
||||||
|
void *opt, *p;
|
||||||
|
int o;
|
||||||
|
|
||||||
|
outpacket_counter = 4; /* skip message type and transaction-id */
|
||||||
|
|
||||||
|
if (!(opt = opt6_find(packet_options, end, OPTION6_CLIENT_ID, 1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
o = new_opt6(OPTION6_CLIENT_ID);
|
||||||
|
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||||
|
end_opt6(o);
|
||||||
|
|
||||||
|
o = new_opt6(OPTION6_SERVER_ID);
|
||||||
|
put_opt6(daemon->duid, daemon->duid_len);
|
||||||
|
end_opt6(o);
|
||||||
|
|
||||||
|
if ((opt = opt6_find(packet_options, end, OPTION6_IA_NA, 12)))
|
||||||
|
{
|
||||||
|
while (opt = opt6_find(opt, end, OPTION6_IA_NA, 12))
|
||||||
|
{
|
||||||
|
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||||
|
void *ia_option = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_IAADDR, 24);
|
||||||
|
|
||||||
|
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||||
|
unsigned int t1 = opt6_uint(opt, 4, 4);
|
||||||
|
unsigned int t2 = opt6_uint(opt, 8, 4);
|
||||||
|
|
||||||
|
|
||||||
|
if (ia_option)
|
||||||
|
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||||
|
{
|
||||||
|
/* do address option */
|
||||||
|
|
||||||
|
ia_option = opt6_next(ia_option, ia_end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no preferred address call address allocate */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = opt6_next(opt, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((opt = opt6_find(packet_options, end, OPTION6_IA_TA, 4)))
|
||||||
|
while (opt = opt6_find(opt, end, OPTION6_IA_TA, 4))
|
||||||
|
{
|
||||||
|
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||||
|
void *ia_option = opt6_find(opt6_ptr(opt, 4), ia_end, OPTION6_IAADDR, 24);
|
||||||
|
|
||||||
|
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||||
|
|
||||||
|
if (ia_option)
|
||||||
|
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||||
|
{
|
||||||
|
/* do address option */
|
||||||
|
|
||||||
|
ia_option = opt6_next(ia_option, ia_end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no preferred address */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = opt6_next(opt, end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return; /* no IA_NA and no IA_TA */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+13
-15
@@ -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
|
||||||
@@ -57,7 +57,6 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
int mtuflag = IP_PMTUDISC_DONT;
|
int mtuflag = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
char namebuff[IF_NAMESIZE];
|
char namebuff[IF_NAMESIZE];
|
||||||
char pretty_addr[ADDRSTRLEN];
|
|
||||||
char *name;
|
char *name;
|
||||||
char *prefix = daemon->tftp_prefix;
|
char *prefix = daemon->tftp_prefix;
|
||||||
struct tftp_prefix *pref;
|
struct tftp_prefix *pref;
|
||||||
@@ -114,7 +113,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -163,7 +162,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -184,10 +183,10 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, &if_index);
|
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, &if_index);
|
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
|
||||||
|
|
||||||
/* wierd TFTP service override */
|
/* wierd TFTP service override */
|
||||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||||
@@ -260,14 +259,14 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||||
transfer->netascii = transfer->carrylf = 0;
|
transfer->netascii = transfer->carrylf = 0;
|
||||||
|
|
||||||
prettyprint_addr(&peer, pretty_addr);
|
prettyprint_addr(&peer, daemon->addrbuff);
|
||||||
|
|
||||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
!fix_fd(transfer->sockfd))
|
!fix_fd(transfer->sockfd))
|
||||||
{
|
{
|
||||||
@@ -298,7 +297,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
!(filename = next(&p, end)) ||
|
!(filename = next(&p, end)) ||
|
||||||
!(mode = next(&p, end)) ||
|
!(mode = next(&p, end)) ||
|
||||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), pretty_addr);
|
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strcasecmp(mode, "netascii") == 0)
|
if (strcasecmp(mode, "netascii") == 0)
|
||||||
@@ -348,7 +347,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
size_t oldlen = strlen(daemon->namebuff);
|
size_t oldlen = strlen(daemon->namebuff);
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
strncat(daemon->namebuff, pretty_addr, (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
|
|
||||||
/* remove unique-directory if it doesn't exist */
|
/* remove unique-directory if it doesn't exist */
|
||||||
@@ -478,7 +477,6 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
{
|
{
|
||||||
struct tftp_transfer *transfer, *tmp, **up;
|
struct tftp_transfer *transfer, *tmp, **up;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
char pretty_addr[ADDRSTRLEN];
|
|
||||||
|
|
||||||
struct ack {
|
struct ack {
|
||||||
unsigned short op, block;
|
unsigned short op, block;
|
||||||
@@ -494,7 +492,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
/* we overwrote the buffer... */
|
/* we overwrote the buffer... */
|
||||||
daemon->srv_save = NULL;
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
prettyprint_addr(&transfer->peer, pretty_addr);
|
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||||
|
|
||||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||||
{
|
{
|
||||||
@@ -526,7 +524,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
|
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||||
(int)ntohs(mess->block), err,
|
(int)ntohs(mess->block), err,
|
||||||
pretty_addr);
|
daemon->addrbuff);
|
||||||
|
|
||||||
/* Got err, ensure we take abort */
|
/* Got err, ensure we take abort */
|
||||||
transfer->timeout = now;
|
transfer->timeout = now;
|
||||||
@@ -557,7 +555,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (len != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||||
transfer->file->filename, pretty_addr);
|
transfer->file->filename, daemon->addrbuff);
|
||||||
len = 0;
|
len = 0;
|
||||||
endcon = 1;
|
endcon = 1;
|
||||||
}
|
}
|
||||||
@@ -570,7 +568,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (endcon || len == 0)
|
if (endcon || len == 0)
|
||||||
{
|
{
|
||||||
if (!endcon)
|
if (!endcon)
|
||||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, pretty_addr);
|
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
|
||||||
/* unlink */
|
/* unlink */
|
||||||
*up = tmp;
|
*up = tmp;
|
||||||
free_transfer(transfer);
|
free_transfer(transfer);
|
||||||
|
|||||||
+21
-2
@@ -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
|
||||||
@@ -320,6 +320,25 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||||
|
{
|
||||||
|
int pfbytes = prefixlen >> 3;
|
||||||
|
int pfbits = prefixlen & 7;
|
||||||
|
|
||||||
|
if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pfbits == 0 ||
|
||||||
|
(a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* returns port number from address */
|
/* returns port number from address */
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||||
{
|
{
|
||||||
@@ -483,7 +502,7 @@ void bump_maxfd(int fd, int *max)
|
|||||||
int retry_send(void)
|
int retry_send(void)
|
||||||
{
|
{
|
||||||
struct timespec waiter;
|
struct timespec waiter;
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
waiter.tv_sec = 0;
|
waiter.tv_sec = 0;
|
||||||
waiter.tv_nsec = 10000;
|
waiter.tv_nsec = 10000;
|
||||||
|
|||||||
Reference in new issue
Block a user