Compare commits

..
7 Commits
57 changed files with 12668 additions and 8689 deletions

No files matched your search

+422 -2491
View File
File diff suppressed because it is too large. Load diff
+2509
View File
File diff suppressed because it is too large. Load diff
+19
View File
@@ -16,6 +16,14 @@ A: The high ports that dnsmasq opens are for replies from the upstream
you to specify the UDP port to be used for this purpose. If not you to specify the UDP port to be used for this purpose. If not
specified, the operating system will select an available port number specified, the operating system will select an available port number
just as it did before. just as it did before.
Second addendum: following the discovery of a security flaw in the
DNS protocol, dnsmasq from version 2.43 has changed behavior. It
now uses a new, randomly selected, port for each query. The old
default behaviour (use one port allocated by the OS) is available by
setting --query-port=0, and setting the query port to a positive
value is still works. You should think hard and know what you are
doing before using either of these options.
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
that? that?
@@ -324,6 +332,17 @@ A: By default, the identity of a machine is determined by using the
method for setting the client-id varies with DHCP client software, method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting, dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Addendum:
From version 2.46, dnsmasq has a solution to this which doesn't
involve setting client-IDs. It's possible to put more than one MAC
address in a --dhcp-host configuration. This tells dnsmasq that it
should use the specified IP for any of the specified MAC addresses,
and furthermore it gives dnsmasq permission to sumarily abandon a
lease to one of the MAC addresses if another one comes along. Note
that this will work fine only as longer as only one interface is
up at any time. There is no way for dnsmasq to enforce this
constraint: if you configure multiple MAC addresses and violate
this rule, bad things will happen.
Q: Can dnsmasq do DHCP on IP-alias interfaces? Q: Can dnsmasq do DHCP on IP-alias interfaces?
+52 -35
View File
@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2007 Simon Kelley # dnsmasq is Copyright (c) 2000-2010 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
@@ -10,38 +10,41 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
PREFIX = /usr/local PREFIX = /usr/local
BINDIR = ${PREFIX}/sbin BINDIR = ${PREFIX}/sbin
MANDIR = ${PREFIX}/share/man MANDIR = ${PREFIX}/share/man
LOCALEDIR = ${PREFIX}/share/locale LOCALEDIR = ${PREFIX}/share/locale
PKG_CONFIG = pkg-config
INSTALL = install
MSGMERGE = msgmerge
MSGFMT = msgfmt
XGETTEXT = xgettext
CFLAGS = -Wall -W -O2
#################################################################
SRC = src SRC = src
PO = po PO = po
MAN = man MAN = man
PKG_CONFIG = pkg-config DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
AWK = nawk DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
INSTALL = install SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
DBUS_MINOR=" `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --modversion dbus-1 | $(AWK) -F . -- '{ if ($$(NF-1)) print \"-DDBUS_MINOR=\"$$(NF-1) }'`" OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
DBUS_CFLAGS="`echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1`" dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
DBUS_LIBS=" `echo $(COPTS) | ../bld/pkg-wrapper $(PKG_CONFIG) --libs dbus-1`" helper.o tftp.o log.o
SUNOS_VER=" `if uname | grep SunOS 2>&1 >/dev/null; then uname -r | $(AWK) -F . -- '{ print \"-DSUNOS_VER=\"$$2 }'; fi`"
SUNOS_LIBS=" `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi `"
all : dnsmasq all :
@cd $(SRC) && $(MAKE) \
dnsmasq : BUILD_CFLAGS="$(DNSMASQ_CFLAGS)" \
cd $(SRC) && $(MAKE) \ BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS)" \
DBUS_MINOR=$(DBUS_MINOR) \ -f ../Makefile dnsmasq
DBUS_CFLAGS=$(DBUS_CFLAGS) \
DBUS_LIBS=$(DBUS_LIBS) \
SUNOS_LIBS=$(SUNOS_LIBS) \
SUNOS_VER=$(SUNOS_VER) \
-f ../bld/Makefile dnsmasq
clean : clean :
rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot rm -f *~ $(SRC)/*.mo contrib/*/*~ */*~ $(SRC)/*.pot
@@ -55,26 +58,40 @@ install-common :
$(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR) $(INSTALL) -m 755 $(SRC)/dnsmasq $(DESTDIR)$(BINDIR)
all-i18n : all-i18n :
cd $(SRC) && $(MAKE) \ @cd $(SRC) && $(MAKE) \
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \ I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
DBUS_MINOR=$(DBUS_MINOR) \ BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
DBUS_CFLAGS=$(DBUS_CFLAGS) \ BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
DBUS_LIBS=$(DBUS_LIBS) \ -f ../Makefile dnsmasq
SUNOS_LIBS=$(SUNOS_LIBS) \ @cd $(PO); for f in *.po; do \
SUNOS_VER=$(SUNOS_VER) \ cd ../$(SRC) && $(MAKE) \
-f ../bld/Makefile dnsmasq -f ../Makefile $${f%.po}.mo; \
cd $(PO); for f in *.po; do \
cd ../$(SRC) && $(MAKE) -f ../bld/Makefile $${f%.po}.mo; \
done done
install-i18n : all-i18n install-common install-i18n : all-i18n install-common
cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) cd $(SRC); ../bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
merge : merge :
$(MAKE) I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' -f ../bld/Makefile -C $(SRC) dnsmasq.pot @cd $(SRC) && $(MAKE) -f ../Makefile dnsmasq.pot
cd $(PO); for f in *.po; do \ @cd $(PO); for f in *.po; do \
msgmerge --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \ echo -n msgmerge $$f && $(MSGMERGE) --no-wrap -U $$f ../$(SRC)/dnsmasq.pot; \
done done
# rules below are targets in recusive makes with cwd=$(SRC)
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(I18N) $(BUILD_CFLAGS) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(BUILD_LIBS) $(LIBS)
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
$(XGETTEXT) -d dnsmasq --foreign-user --omit-header --keyword=_ -o $@ -i $(OBJS:.o=.c)
%.mo : ../po/%.po dnsmasq.pot
$(MSGMERGE) -o - ../po/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
.PHONY : all clean install install-common all-i18n install-i18n merge
-17
View File
@@ -1,17 +0,0 @@
CFLAGS = -Wall -W -O2
OBJS = cache.o rfc1035.o util.o option.o forward.o isc.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(DBUS_MINOR) $(I18N) $(DBUS_CFLAGS) $(SUNOS_VER) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(DBUS_LIBS) $(SUNOS_LIBS) $(LIBS)
dnsmasq.pot : $(OBJS:.o=.c) dnsmasq.h config.h
xgettext -d dnsmasq --foreign-user --keyword=_ -o dnsmasq.pot -i $(OBJS:.o=.c)
%.mo : ../po/%.po dnsmasq.pot
msgmerge -o - ../po/$*.po dnsmasq.pot | msgfmt -o $*.mo -
+2 -2
View File
@@ -2,8 +2,8 @@
for f in *; do for f in *; do
if [ -d $f ]; then if [ -d $f ]; then
install -m 755 -d $1/$f/man8 $2 -m 755 -d $1/$f/man8
install -m 644 $f/dnsmasq.8 $1/$f/man8 $2 -m 644 $f/dnsmasq.8 $1/$f/man8
echo installing $1/$f/man8/dnsmasq.8 echo installing $1/$f/man8/dnsmasq.8
fi fi
done done
+2 -2
View File
@@ -1,8 +1,8 @@
#!/bin/sh #!/bin/sh
for f in *.mo; do for f in *.mo; do
install -m 755 -d $1/${f%.mo}/LC_MESSAGES $2 -m 755 -d $1/${f%.mo}/LC_MESSAGES
install -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo $2 -m 644 $f $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo echo installing $1/${f%.mo}/LC_MESSAGES/dnsmasq.mo
done done
+5 -2
View File
@@ -1,7 +1,10 @@
#!/bin/sh #!/bin/sh
if grep "^\#.*define.*HAVE_DBUS" config.h 2>&1 >/dev/null || \ search=$1
grep HAVE_DBUS 2>&1 >/dev/null ; then shift
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
grep $search 2>&1 >/dev/null ; then
exec $* exec $*
fi fi
+36
View File
@@ -0,0 +1,36 @@
Dnsmasq from version 2.52 has a couple of rather application-specific
features designed to allow for implementation of the DHCP part of CPE
WAN management protocol.
http://www.broadband-forum.org/technical/download/TR-069_Amendment-2.pdf
http://en.wikipedia.org/wiki/TR-069
The relevant sections are F.2.1 "Gateway Requirements" and F.2.5 "DHCP
Vendor Options".
First, dnsmasq checks for DHCP requests which contain an option-125
vendor-class option which in turn holds a vendor section for IANA
enterprise number 3561 which contains sub-options codes 1 and 2. If
this is present then the network-tag "cpewan-id" is set.
This allows dnsmasq to be configured to reply with the correct
GatewayManufacturerOUI, GatewaySerialNumber and GatewayProductClass like this:
dhcp-option=cpewan-id,vi-encap:3561,4,"<GatewayManufacturerOUI>"
dhcp-option=cpewan-id,vi-encap:3561,5,"<SerialNumber>"
dhcp-option=cpewan-id,vi-encap:3561,6,"<ProductClass>"
Second, the received sub-options 1, 2, and 3 are passed to the DHCP
lease-change script as the environment variables DNSMASQ_CPEWAN_OUI,
DNSMASQ_CPEWAN_SERIAL, and DNSMASQ_CPEWAN_CLASS respectively. This allows
the script to be used to maintain a ManageableDevice table as
specified in F.2.1. Note that this data is not retained in dnsmasq's
internal DHCP lease database, so it is not available on every call to
the script (this is the same as some other data such as vendor and
user classes). It will however be available for at least the "add"
call, and should be stored then against the IP address as primary
key for future use.
This feature was added to dnsmasq under sponsorship from Ericsson.
+38
View File
@@ -0,0 +1,38 @@
This is a launchd item for Mac OS X and Mac OS X Server.
For more information about launchd, the
"System wide and per-user daemon/agent manager", see the launchd
man page, or the wikipedia page: http://en.wikipedia.org/wiki/Launchd
This launchd item uses the following flags:
--keep-in-foreground - this is crucial for use with launchd
--log-queries - this is optional and you can remove it
--log-facility=/var/log/dnsmasq.log - again optional instead of system.log
To use this launchd item for dnsmasq:
If you don't already have a folder /Library/LaunchDaemons, then create one:
sudo mkdir /Library/LaunchDaemons
sudo chown root:admin /Library/LaunchDaemons
sudo chmod 775 /Library/LaunchDaemons
Copy uk.org.thekelleys.dnsmasq.plist there and then set ownership/permissions:
sudo cp uk.org.thekelleys.dnsmasq.plist /Library/LaunchDaemons/
sudo chown root:admin /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
sudo chmod 644 /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
Optionally, edit your dnsmasq configuration file to your liking.
To start the launchd job, which starts dnsmaq, reboot or use the command:
sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
To stop the launchd job, which stops dnsmasq, use the command:
sudo launchctl unload /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
If you want to permanently stop the launchd job, so it doesn't start the job even after a reboot, use the following command:
sudo launchctl unload -w /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
If you make a change to the configuration file, you should relaunch dnsmasq;
to do this unload and then load again:
sudo launchctl unload /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>uk.org.thekelleys.dnsmasq</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/dnsmasq</string>
<string>--keep-in-foreground</string>
<string>--log-queries</string>
<string>--log-facility=/var/log/dnsmasq.log</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
+25
View File
@@ -0,0 +1,25 @@
Ok, script attached ... seems to be working ok for me,
tried to install and remove a few times. It does the
right thing with the smf when installing, you can then
simply enable the service. Upon removal it cleans up the
files but won't clean up the services (I think until
a reboot) ... I've only started looking at the new
packages stuff in the last day or two, so I could be
missing something, but I can't find any way to force
a proper cleanup.
It requires that you have a writable repository setup
as per the docs on the opensolaris website and it will
create a dnsmasq package (package name is a variable
in the script). The script takes a version number for
the package and assumes that it's in the contrib/Solaris10
directory, it then works out the base tree directory
from $0.
i.e. $ contrib/Solaris10/create_package 2.52-1
or $ cd contrib/Solaris10; ./create_package 2.52-1
It's a bit more complex than it could be because I
prefer putting the daemon in /usr/sbin and the config
in /etc, so the script will actually create a new
version of the existing contrib dnsmasq.xml.
+87
View File
@@ -0,0 +1,87 @@
#!/bin/sh
#
# For our package, and for the SMF script, we need to define where we
# want things to go...
#
BIN_DIR="/usr/sbin"
CONF_DIR="/etc"
MAN_DIR="/usr/man/man8"
PACKAGE_NAME="dnsmasq"
#
# Since we know we are in the contrib directory we can work out where
# the rest of the tree is...
#
BASEDIR="`dirname $0`/../.."
#
# We need a version number to use for the package creation...
#
if [ $# != 1 ]; then
echo "Usage: $0 <package_version_number>" >&2
exit 1
fi
VERSION="$1"
#
# First thing we do is fix-up the smf file to use the paths we prefer...
#
if [ ! -f "${BASEDIR}/contrib/Solaris10/dnsmasq.xml" ]; then
echo "$0: unable to find contrib/Solaris10/dnsmasq.xml" >&2
exit 1
fi
echo "Fixing up smf file ... \c"
cat "${BASEDIR}/contrib/Solaris10/dnsmasq.xml" | \
sed -e "s%/usr/local/etc%${CONF_DIR}%" \
-e "s%/usr/local/sbin%${BIN_DIR}%" \
-e "s%/usr/local/man%${MAN_DIR}%" > ${BASEDIR}/contrib/Solaris10/dnsmasq-pkg.xml
echo "done."
echo "Creating packaging file ... \c"
cat <<EOF >${BASEDIR}/contrib/Solaris10/dnsmasq_package.inc
#
# header
#
set name=pkg.name value="dnsmasq"
set name=pkg.description value="dnsmasq daemon - dns, dhcp, tftp etc"
set name=pkg.detailed_url value="http://www.thekelleys.org.uk/dnsmasq/doc.html"
set name=info.maintainer value="TBD (tbd@tbd.com)"
set name=info.upstream value="dnsmasq-discuss@lists.thekelleys.org.uk"
set name=info.upstream_url value="http://www.thekelleys.org.uk/dnsmasq/doc.html"
#
# dependencies ... none?
#
#
# directories
#
dir mode=0755 owner=root group=bin path=${BIN_DIR}/
dir mode=0755 owner=root group=sys path=${CONF_DIR}/
dir mode=0755 owner=root group=sys path=${MAN_DIR}/
dir mode=0755 owner=root group=sys path=/var/
dir mode=0755 owner=root group=sys path=/var/svc
dir mode=0755 owner=root group=sys path=/var/svc/manifest
dir mode=0755 owner=root group=sys path=/var/svc/manifest/network
#
# files
#
file ${BASEDIR}/src/dnsmasq mode=0555 owner=root group=bin path=${BIN_DIR}/dnsmasq
file ${BASEDIR}/man/dnsmasq.8 mode=0555 owner=root group=bin path=${MAN_DIR}/dnsmasq.8
file ${BASEDIR}/dnsmasq.conf.example mode=0644 owner=root group=sys path=${CONF_DIR}/dnsmasq.conf preserve=strawberry
file ${BASEDIR}/contrib/Solaris10/dnsmasq-pkg.xml mode=0644 owner=root group=sys path=/var/svc/manifest/network/dnsmasq.xml restart_fmri=svc:/system/manifest-import:default
EOF
echo "done."
echo "Creating package..."
eval `pkgsend open ${PACKAGE_NAME}@${VERSION}`
pkgsend include ${BASEDIR}/contrib/Solaris10/dnsmasq_package.inc
if [ "$?" = 0 ]; then
pkgsend close
else
echo "Errors"
fi
File renamed without changes.
File renamed without changes.
+20
View File
@@ -0,0 +1,20 @@
Hello,
For some specific application I needed to deny access to a MAC address
to a lease. For this reason I modified the dhcp-script behavior and is
called with an extra parameter "access" once a dhcp request or discover
is received. In that case if the exit code of the script is zero,
dnsmasq continues normally, and if non-zero the packet is ignored.
This was not added as a security feature but as a mean to handle
differently some addresses. It is also quite intrusive since it requires
changes in several other subsystems.
It attach the patch in case someone is interested.
regards,
Nikos
nmav@gennetsa.com
+578
View File
@@ -0,0 +1,578 @@
Index: src/dnsmasq.c
===================================================================
--- src/dnsmasq.c (revision 696)
+++ src/dnsmasq.c (revision 821)
@@ -59,7 +59,6 @@
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 sig_handler(int sig);
-static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev);
static void poll_resolv(void);
@@ -275,7 +274,7 @@
piperead = pipefd[0];
pipewrite = pipefd[1];
/* prime the pipe to load stuff first time. */
- send_event(pipewrite, EVENT_RELOAD, 0);
+ send_event(pipewrite, EVENT_RELOAD, 0, 0);
err_pipe[1] = -1;
@@ -340,7 +339,7 @@
}
else if (getuid() == 0)
{
- send_event(err_pipe[1], EVENT_PIDFILE, errno);
+ send_event(err_pipe[1], EVENT_PIDFILE, errno, 0);
_exit(0);
}
}
@@ -372,7 +371,7 @@
(setgroups(0, &dummy) == -1 ||
setgid(gp->gr_gid) == -1))
{
- send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
+ send_event(err_pipe[1], EVENT_GROUP_ERR, errno, 0);
_exit(0);
}
@@ -415,14 +414,14 @@
if (bad_capabilities != 0)
{
- send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
+ send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, 0);
_exit(0);
}
/* finally drop root */
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, 0);
_exit(0);
}
@@ -434,7 +433,7 @@
/* lose the setuid and setgid capbilities */
if (capset(hdr, data) == -1)
{
- send_event(err_pipe[1], EVENT_CAP_ERR, errno);
+ send_event(err_pipe[1], EVENT_CAP_ERR, errno, 0);
_exit(0);
}
#endif
@@ -647,7 +646,7 @@
}
if (FD_ISSET(piperead, &rset))
- async_event(piperead, now);
+ async_event(piperead, now, NULL, 0);
#ifdef HAVE_LINUX_NETWORK
if (FD_ISSET(daemon->netlinkfd, &rset))
@@ -674,7 +673,7 @@
#endif
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
- dhcp_packet(now);
+ dhcp_packet(piperead, now);
#ifndef NO_FORK
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
@@ -719,17 +718,18 @@
else
return;
- send_event(pipewrite, event, 0);
+ send_event(pipewrite, event, 0, 0);
errno = errsave;
}
}
-void send_event(int fd, int event, int data)
+void send_event(int fd, int event, int data, int priv)
{
struct event_desc ev;
ev.event = event;
ev.data = data;
+ ev.priv = priv;
/* error pipe, debug mode. */
if (fd == -1)
@@ -771,14 +771,17 @@
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
}
}
-
-static void async_event(int pipe, time_t now)
+
+/* returns the private data of the event
+ */
+int async_event(int pipe, time_t now, struct event_desc* event, unsigned int secs)
{
pid_t p;
struct event_desc ev;
int i;
- if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
+ if (read_timeout(pipe, (unsigned char *)&ev, sizeof(ev), now, secs) > 0)
+ {
switch (ev.event)
{
case EVENT_RELOAD:
@@ -872,6 +875,14 @@
flush_log();
exit(EC_GOOD);
}
+ }
+ else
+ return -1; /* timeout */
+
+ if (event)
+ memcpy( event, &ev, sizeof(ev));
+
+ return 0;
}
static void poll_resolv()
Index: src/config.h
===================================================================
--- src/config.h (revision 696)
+++ src/config.h (revision 821)
@@ -51,6 +51,8 @@
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
+#define SCRIPT_TIMEOUT 6
+#define LEASE_CHECK_TIMEOUT 10
/* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
Index: src/dnsmasq.h
===================================================================
--- src/dnsmasq.h (revision 696)
+++ src/dnsmasq.h (revision 821)
@@ -116,6 +116,7 @@
/* Async event queue */
struct event_desc {
int event, data;
+ unsigned int priv;
};
#define EVENT_RELOAD 1
@@ -390,6 +391,7 @@
#define ACTION_OLD_HOSTNAME 2
#define ACTION_OLD 3
#define ACTION_ADD 4
+#define ACTION_ACCESS 5
#define DHCP_CHADDR_MAX 16
@@ -709,6 +711,7 @@
char *print_mac(char *buff, unsigned char *mac, int len);
void bump_maxfd(int fd, int *max);
int read_write(int fd, unsigned char *packet, int size, int rw);
+int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs);
/* log.c */
void die(char *message, char *arg1, int exit_code);
@@ -748,7 +751,7 @@
/* dhcp.c */
void dhcp_init(void);
-void dhcp_packet(time_t now);
+void dhcp_packet(int piperead, time_t now);
struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr,
@@ -792,14 +795,16 @@
void rerun_scripts(void);
/* rfc2131.c */
-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+size_t dhcp_reply(int pipefd, struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform);
/* dnsmasq.c */
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
-void send_event(int fd, int event, int data);
+void send_event(int fd, int event, int data, int priv);
void clear_cache_and_reload(time_t now);
+int wait_for_child(int pipe);
+int async_event(int pipe, time_t now, struct event_desc*, unsigned int timeout);
/* isc.c */
#ifdef HAVE_ISC_READER
@@ -832,9 +837,9 @@
/* helper.c */
#ifndef NO_FORK
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
-void helper_write(void);
+int helper_write(void);
void queue_script(int action, struct dhcp_lease *lease,
- char *hostname, time_t now);
+ char *hostname, time_t now, unsigned int uid);
int helper_buf_empty(void);
#endif
Index: src/util.c
===================================================================
--- src/util.c (revision 696)
+++ src/util.c (revision 821)
@@ -444,3 +444,38 @@
return 1;
}
+int read_timeout(int fd, unsigned char *packet, int size, time_t now, int secs)
+{
+ ssize_t n, done;
+ time_t expire;
+
+ expire = now + secs;
+
+ for (done = 0; done < size; done += n)
+ {
+ retry:
+ if (secs > 0) alarm(secs);
+ n = read(fd, &packet[done], (size_t)(size - done));
+
+ if (n == 0)
+ return 0;
+ else if (n == -1)
+ {
+ if (errno == EINTR) {
+ my_syslog(LOG_INFO, _("read timed out (errno %d)"), errno);
+ return 0;
+ }
+
+ if (retry_send() || errno == ENOMEM || errno == ENOBUFS || errno == EAGAIN)
+ {
+ if (secs == 0 || (secs > 0 && dnsmasq_time() < expire))
+ goto retry;
+ }
+
+ my_syslog(LOG_INFO, _("error in read (timeout %d, errno %d)"), secs, errno);
+ return 0;
+ }
+ }
+ return 1;
+}
+
Index: src/dhcp.c
===================================================================
--- src/dhcp.c (revision 696)
+++ src/dhcp.c (revision 821)
@@ -103,7 +103,7 @@
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
}
-void dhcp_packet(time_t now)
+void dhcp_packet(int piperead, time_t now)
{
struct dhcp_packet *mess;
struct dhcp_context *context;
@@ -239,7 +239,8 @@
if (!iface_enumerate(&parm, complete_context, NULL))
return;
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(piperead, parm.current, ifr.ifr_name, iface_index, (size_t)sz,
now, unicast_dest, &is_inform);
lease_update_file(now);
lease_update_dns();
Index: src/helper.c
===================================================================
--- src/helper.c (revision 696)
+++ src/helper.c (revision 821)
@@ -45,6 +45,7 @@
#endif
unsigned char hwaddr[DHCP_CHADDR_MAX];
char interface[IF_NAMESIZE];
+ unsigned int uid;
};
static struct script_data *buf = NULL;
@@ -60,7 +61,7 @@
then fork our process. */
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, 0);
_exit(0);
}
@@ -87,13 +88,13 @@
{
if (daemon->options & OPT_NO_FORK)
/* send error to daemon process if no-fork */
- send_event(event_fd, EVENT_HUSER_ERR, errno);
+ send_event(event_fd, EVENT_HUSER_ERR, errno, 0);
else
{
/* kill daemon */
- send_event(event_fd, EVENT_DIE, 0);
+ send_event(event_fd, EVENT_DIE, 0, 0);
/* return error */
- send_event(err_fd, EVENT_HUSER_ERR, errno);;
+ send_event(err_fd, EVENT_HUSER_ERR, errno, 0);
}
_exit(0);
}
@@ -122,6 +123,8 @@
action_str = "del";
else if (data.action == ACTION_ADD)
action_str = "add";
+ else if (data.action == ACTION_ACCESS)
+ action_str = "access";
else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
action_str = "old";
else
@@ -178,9 +181,11 @@
{
/* On error send event back to main process for logging */
if (WIFSIGNALED(status))
- send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
- else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
- send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
+ send_event(event_fd, EVENT_KILLED, WTERMSIG(status), data.uid);
+ else if (WIFEXITED(status))
+ send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), data.uid);
+ else
+ send_event(event_fd, EVENT_EXITED, -1, data.uid);
break;
}
@@ -263,7 +268,7 @@
err = errno;
}
/* 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, data.uid);
_exit(0);
}
}
@@ -295,7 +300,7 @@
}
/* 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, unsigned int uid)
{
unsigned char *p;
size_t size;
@@ -332,6 +337,7 @@
buf_size = size;
}
+ buf->uid = uid;
buf->action = action;
buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type;
@@ -393,12 +399,15 @@
return bytes_in_buf == 0;
}
-void helper_write(void)
+/* returns -1 if write failed for a reason, 1 if no data exist
+ * and 0 if everything was ok.
+ */
+int helper_write(void)
{
ssize_t rc;
if (bytes_in_buf == 0)
- return;
+ return 1;
if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
{
@@ -409,9 +418,11 @@
else
{
if (errno == EAGAIN || errno == EINTR)
- return;
+ return -1;
bytes_in_buf = 0;
}
+
+ return 0;
}
#endif
Index: src/rfc2131.c
===================================================================
--- src/rfc2131.c (revision 696)
+++ src/rfc2131.c (revision 821)
@@ -100,8 +100,49 @@
int clid_len, unsigned char *clid, int *len_out);
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
+static int check_access_script( int piperead, struct dhcp_lease *lease, struct dhcp_packet *mess, time_t now)
+{
+#ifndef NO_FORK
+unsigned int uid;
+struct event_desc ev;
+int ret;
+struct dhcp_lease _lease;
+
+ if (daemon->lease_change_command == NULL) return 0; /* ok */
+
+ if (!lease) { /* if host has not been seen before lease is NULL */
+ memset(&_lease, 0, sizeof(_lease));
+ lease = &_lease;
+ lease_set_hwaddr(lease, mess->chaddr, NULL, mess->hlen, mess->htype, 0);
+ }
+
+ uid = rand16();
+ queue_script(ACTION_ACCESS, lease, NULL, now, uid);
+
+ /* send all data to helper process */
+ do
+ {
+ helper_write();
+ } while (helper_buf_empty() == 0);
+
+ /* wait for our event */
+ ret = 0;
+ do
+ {
+ ret = async_event( piperead, now, &ev, SCRIPT_TIMEOUT);
+ }
+ while(ev.priv != uid && ret >= 0);
+
+ if (ret < 0 || ev.data != 0) /* timeout or error */
+ {
+ return -1;
+ }
+
+#endif
+ return 0; /* ok */
+}
-size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
+size_t dhcp_reply(int piperead, struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform)
{
unsigned char *opt, *clid = NULL;
@@ -252,7 +293,7 @@
mac->netid.next = netid;
netid = &mac->netid;
}
-
+
/* Determine network for this packet. Our caller will have already linked all the
contexts which match the addresses of the receiving interface but if the
machine has an address already, or came via a relay, or we have a subnet selector,
@@ -329,7 +370,7 @@
my_syslog(LOG_INFO, _("Available DHCP range: %s -- %s"), daemon->namebuff, inet_ntoa(context_tmp->end));
}
}
-
+
mess->op = BOOTREPLY;
config = find_config(daemon->dhcp_conf, context, clid, clid_len,
@@ -418,7 +459,7 @@
else
mess->yiaddr = lease->addr;
}
-
+
if (!message &&
!lease &&
(!(lease = lease_allocate(mess->yiaddr))))
@@ -641,7 +682,14 @@
memcpy(req_options, option_ptr(opt, 0), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
-
+
+ if (mess_type == DHCPREQUEST || mess_type == DHCPDISCOVER)
+ if (check_access_script(piperead, lease, mess, now) < 0)
+ {
+ my_syslog(LOG_INFO, _("Ignoring client due to access script"));
+ return 0;
+ }
+
switch (mess_type)
{
case DHCPDECLINE:
Index: src/log.c
===================================================================
--- src/log.c (revision 696)
+++ src/log.c (revision 821)
@@ -73,7 +73,7 @@
if (!log_reopen(daemon->log_file))
{
- send_event(errfd, EVENT_LOG_ERR, errno);
+ send_event(errfd, EVENT_LOG_ERR, errno, 0);
_exit(0);
}
Index: src/lease.c
===================================================================
--- src/lease.c (revision 696)
+++ src/lease.c (revision 821)
@@ -511,7 +511,7 @@
if (lease->old_hostname)
{
#ifndef NO_FORK
- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
+ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
#endif
free(lease->old_hostname);
lease->old_hostname = NULL;
@@ -520,7 +520,7 @@
else
{
#ifndef NO_FORK
- queue_script(ACTION_DEL, lease, lease->hostname, now);
+ queue_script(ACTION_DEL, lease, lease->hostname, now, 0);
#endif
old_leases = lease->next;
@@ -540,7 +540,7 @@
if (lease->old_hostname)
{
#ifndef NO_FORK
- queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
+ queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now, 0);
#endif
free(lease->old_hostname);
lease->old_hostname = NULL;
@@ -552,7 +552,7 @@
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{
#ifndef NO_FORK
- queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now);
+ queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now, 0);
#endif
lease->new = lease->changed = lease->aux_changed = 0;
Index: man/dnsmasq.8
===================================================================
--- man/dnsmasq.8 (revision 696)
+++ man/dnsmasq.8 (revision 821)
@@ -724,12 +724,15 @@
.B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the
binary specified by this option is run. The arguments to the process
-are "add", "old" or "del", the MAC
+are "add", "old", "access" or "del", the MAC
address of the host (or "<null>"), the IP address, and the hostname,
if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing
lease (also, lease length or expiry and client-id, if leasefile-ro is set).
+The "access" keyword means that a request was just received and depending
+on the script exit status request for address will be granted, if exit status
+is zero or not if it is non-zero.
The process is run as root (assuming that dnsmasq was originally run as
root) even if dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, and if the
+11
View File
@@ -0,0 +1,11 @@
A remake of patch Bob Carroll had posted to dnsmasq,
now compatible with version 2.47. Hopefully he doesn't
mind (sending a copy of this mail to him too).
Maybe the patch in question is not acceptible
as it doesn't add new switch, rather it binds itself to "strict-order".
What it does is: if you have strict-order in the
dnsmasq config file and query a domain that would result
in NXDOMAIN, it iterates the whole given nameserver list
until the last one says NXDOMAIN.
@@ -0,0 +1,17 @@
diff -ur dnsmasq-2.47/src/forward.c dnsmasq-2.47-patched/src/forward.c
--- dnsmasq-2.47/src/forward.c 2009-02-01 17:59:48.000000000 +0200
+++ dnsmasq-2.47-patched/src/forward.c 2009-03-18 19:10:22.000000000 +0200
@@ -488,9 +488,12 @@
return;
server = forward->sentto;
+
+ if ( (header->rcode == NXDOMAIN) && ((daemon->options & OPT_ORDER) != 0) && (server->next != NULL) )
+ header->rcode = SERVFAIL;
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
- !(daemon->options & OPT_ORDER) &&
+ ((daemon->options & OPT_ORDER) != 0) &&
forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
{
Binary file not shown.
+37
View File
@@ -21,6 +21,9 @@ and avoids startup races with the provider of nameserver information.
Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
and a single object: /uk/org/thekelleys/dnsmasq and a single object: /uk/org/thekelleys/dnsmasq
1. METHODS
----------
Methods are of the form Methods are of the form
uk.org.thekelleys.<method> uk.org.thekelleys.<method>
@@ -91,4 +94,38 @@ Each call to SetServers completely replaces the set of servers
specified by via the DBus, but it leaves any servers specified via the specified by via the DBus, but it leaves any servers specified via the
command line or /etc/dnsmasq.conf or /etc/resolv.conf alone. command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
2. SIGNALS
----------
If dnsmasq's DHCP server is active, it will send signals over DBUS whenever
the DHCP lease database changes. Think of these signals as transactions on
a database with the IP address acting as the primary key.
Signals are of the form:
uk.org.thekelleys.<signal>
and their parameters are:
STRING "192.168.1.115"
STRING "01:23:45:67:89:ab"
STRING "hostname.or.fqdn"
Available signals are:
DhcpLeaseAdded
---------------
This signal is emitted when a DHCP lease for a given IP address is created.
DhcpLeaseDeleted
----------------
This signal is emitted when a DHCP lease for a given IP address is deleted.
DhcpLeaseUpdated
----------------
This signal is emitted when a DHCP lease for a given IP address is updated.
-2
View File
@@ -5,12 +5,10 @@
<policy user="root"> <policy user="root">
<allow own="uk.org.thekelleys.dnsmasq"/> <allow own="uk.org.thekelleys.dnsmasq"/>
<allow send_destination="uk.org.thekelleys.dnsmasq"/> <allow send_destination="uk.org.thekelleys.dnsmasq"/>
<allow send_interface="uk.org.thekelleys.dnsmasq"/>
</policy> </policy>
<policy context="default"> <policy context="default">
<deny own="uk.org.thekelleys.dnsmasq"/> <deny own="uk.org.thekelleys.dnsmasq"/>
<deny send_destination="uk.org.thekelleys.dnsmasq"/> <deny send_destination="uk.org.thekelleys.dnsmasq"/>
<deny send_interface="uk.org.thekelleys.dnsmasq"/>
</policy> </policy>
</busconfig> </busconfig>
+74 -5
View File
@@ -122,6 +122,12 @@
# 3) Provides the domain part for "expand-hosts" # 3) Provides the domain part for "expand-hosts"
#domain=thekelleys.org.uk #domain=thekelleys.org.uk
# Set a different domain for a particular subnet
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
# Same idea, but range rather then subnet
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
# Uncomment this to enable the integrated DHCP server, you need # Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally # to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to # a lease time. If you have more than one network, you will need to
@@ -157,6 +163,14 @@
# the name fred and IP address 192.168.0.60 and lease time 45 minutes # the name fred and IP address 192.168.0.60 and lease time 45 minutes
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m #dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
# Give a host with ethernet address 11:22:33:44:55:66 or
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
# that these two ethernet interfaces will never be in use at the same
# time, and give the IP address to the second, even if it is already
# in use by the first. Useful for laptops with wired and wireless
# addresses.
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
# Give the machine which says its name is "bert" IP address # Give the machine which says its name is "bert" IP address
# 192.168.0.70 and an infinite lease # 192.168.0.70 and an infinite lease
#dhcp-host=bert,192.168.0.70,infinite #dhcp-host=bert,192.168.0.70,infinite
@@ -270,12 +284,12 @@
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt # http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
# adapted for a typical dnsmasq installation where the host running # adapted for a typical dnsmasq installation where the host running
# dnsmasq is also the host running samba. # dnsmasq is also the host running samba.
# you may want to uncomment them if you use Windows clients and Samba. # you may want to uncomment some or all of them if you use
# Windows clients and Samba.
#dhcp-option=19,0 # option ip-forwarding off #dhcp-option=19,0 # option ip-forwarding off
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s) #dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
#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
#dhcp-option=47 # empty netbios scope.
# 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......
@@ -315,7 +329,7 @@
# Reboot time. (Note 'i' to send 32-bit value) # Reboot time. (Note 'i' to send 32-bit value)
#dhcp-option-force=211,30i #dhcp-option-force=211,30i
# Set the boot filename for BOOTP. You will only need # Set the boot filename for netboot/PXE. You will only need
# this is you want to boot machines over the network and you will need # this is you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built in TFTP server or an # a TFTP server; either dnsmasq's built in TFTP server or an
# external one. (See below for how to enable the TFTP server.) # external one. (See below for how to enable the TFTP server.)
@@ -328,6 +342,50 @@
#dhcp-boot=net:#gpxe,undionly.kpxe #dhcp-boot=net:#gpxe,undionly.kpxe
#dhcp-boot=mybootimage #dhcp-boot=mybootimage
# Encapsulated options for Etherboot gPXE. All the options are
# encapsulated within option 175
#dhcp-option=encap:175, 1, 5b # priority code
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
#dhcp-option=encap:175, 177, string # bus-id
#dhcp-option=encap:175, 189, 1b # BIOS drive code
#dhcp-option=encap:175, 190, user # iSCSI username
#dhcp-option=encap:175, 191, pass # iSCSI password
# Test for the architecture of a netboot client. PXE clients are
# supposed to send their architecture as option 93. (See RFC 4578)
#dhcp-match=peecees, option:client-arch, 0 #x86-32
#dhcp-match=itanics, option:client-arch, 2 #IA64
#dhcp-match=hammers, option:client-arch, 6 #x86-64
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
# Do real PXE, rather than just booting a single file, this is an
# alternative to dhcp-boot.
#pxe-prompt="What system shall I netboot?"
# or with timeout before first available action is taken:
#pxe-prompt="Press F8 for menu.", 60
# Available boot services. for PXE.
#pxe-service=x86PC, "Boot from local disk"
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
#pxe-service=x86PC, "Install Linux", pxelinux
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
# Beware this fails on old PXE ROMS.
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
# Use bootserver on network, found my multicast or broadcast.
#pxe-service=x86PC, "Install windows from RIS server", 1
# Use bootserver at a known IP address.
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
# If you have multicast-FTP available,
# information for that can be passed in a similar way using options 1
# to 5. See page 19 of
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
# Enable dnsmasq's built-in TFTP server # Enable dnsmasq's built-in TFTP server
#enable-tftp #enable-tftp
@@ -338,11 +396,17 @@
# the user dnsmasq is running as will be send over the net. # the user dnsmasq is running as will be send over the net.
#tftp-secure #tftp-secure
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
# transfers. It will slow things down, but may rescue some broken TFTP
# clients.
#tftp-no-blocksize
# Set the boot file name only when the "red" tag is set. # Set the boot file name only when the "red" tag is set.
#dhcp-boot=net:red,pxelinux.red-net #dhcp-boot=net:red,pxelinux.red-net
# An example of dhcp-boot with an external server: the name and IP # An example of dhcp-boot with an external TFTP server: the name and IP
# address of the server are given after the filename. # address of the server are given after the filename.
# Can fail with old PXE ROMS. Overridden by --pxe-service.
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3 #dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
# Set the limit on DHCP leases, the default is 150 # Set the limit on DHCP leases, the default is 150
@@ -395,7 +459,8 @@
#alias=1.2.3.4,5.6.7.8 #alias=1.2.3.4,5.6.7.8
# and this maps 1.2.3.x to 5.6.7.x # and this maps 1.2.3.x to 5.6.7.x
#alias=1.2.3.0,5.6.7.0,255.255.255.0 #alias=1.2.3.0,5.6.7.0,255.255.255.0
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
# Change these lines if you want dnsmasq to serve MX records. # Change these lines if you want dnsmasq to serve MX records.
@@ -458,6 +523,10 @@
#Example zeroconf #Example zeroconf
#txt-record=_http._tcp.example.com,name=value,paper=A4 #txt-record=_http._tcp.example.com,name=value,paper=A4
# Provide an alias for a "local" DNS name. Note that this _only_ works
# for targets which are names from DHCP or /etc/hosts. Give host
# "bert" another name, bertrand
#cname=bertand,bert
# For debugging purposes, log each DNS query as it passes through # For debugging purposes, log each DNS query as it passes through
# dnsmasq. # dnsmasq.
+8 -5
View File
@@ -11,7 +11,7 @@ Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
server and allows machines with DHCP-allocated addresses server and allows machines with DHCP-allocated addresses
to appear in the DNS with names configured either in each host or to appear in the DNS with names configured either in each host or
in a central configuration file. Dnsmasq supports static and dynamic in a central configuration file. Dnsmasq supports static and dynamic
DHCP leases and BOOTP/TFTP for network booting of diskless machines. DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
<P> <P>
Dnsmasq is targeted at home networks using NAT and Dnsmasq is targeted at home networks using NAT and
connected to the internet via a modem, cable-modem or ADSL connected to the internet via a modem, cable-modem or ADSL
@@ -89,12 +89,15 @@ 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>. <A HREF="http://ftp.debian.org/debian/pool/main/d/dnsmasq/"> here</A> or installed using <TT>apt</TT>.
<H2>Links.</H2> <H2>Links.</H2>
There is an article in German on dnsmasq at <A 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>
HREF="http://www.linuxnetmag.com/de/issue7/m7dnsmasq1.html">http://www.linuxnetmag.com/de/issue7/m7dnsmasq1.html</A>
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
There is a good article about dnsmasq at <A There is a good article about dnsmasq at <A
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A> HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
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> and another at <A
HREF="http://www.linux.com/articles/149040">http://www.linux.com/articles/149040</A>
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.
+226 -54
View File
@@ -15,8 +15,8 @@ contents of /etc/hosts so that local hostnames
which do not appear in the global DNS can be resolved and also answers which do not appear in the global DNS can be resolved and also answers
DNS queries for DHCP configured hosts. DNS queries for DHCP configured hosts.
.PP .PP
The dnsmasq DHCP server supports static address assignments, multiple The dnsmasq DHCP server supports static address assignments and multiple
networks, DHCP-relay and RFC3011 subnet specifiers. It automatically networks. It automatically
sends a sensible default set of DHCP options, and can be configured to sends a sensible default set of DHCP options, and can be configured to
send any desired set of DHCP options, including vendor-encapsulated send any desired set of DHCP options, including vendor-encapsulated
options. It includes a secure, read-only, options. It includes a secure, read-only,
@@ -31,17 +31,22 @@ BSD, unless the GNU getopt library is linked, the long form of the
options does not work on the command line; it is still recognised in options does not work on the command line; it is still recognised in
the configuration file. the configuration file.
.TP .TP
.B --test
Read and syntax check configuration file(s). Exit with code 0 if all
is OK, or a non-zero code otherwise. Do not start up dnsmasq.
.TP
.B \-h, --no-hosts .B \-h, --no-hosts
Don't read the hostnames in /etc/hosts. Don't read the hostnames in /etc/hosts.
.TP .TP
.B \-H, --addn-hosts=<file> .B \-H, --addn-hosts=<file>
Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read
only the specified file. This option may be repeated for more than one only the specified file. This option may be repeated for more than one
additional hosts file. additional hosts file. If a directory is given, then read all the files contained in that directory.
.TP .TP
.B \-E, --expand-hosts .B \-E, --expand-hosts
Add the domain to simple names (without a period) in /etc/hosts Add the domain to simple names (without a period) in /etc/hosts
in the same way as for DHCP-derived names. in the same way as for DHCP-derived names. Note that this does not
apply to domain names in cnames, PTR records, TXT records etc.
.TP .TP
.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
@@ -118,8 +123,7 @@ to zero completely disables DNS function, leaving only DHCP and/or TFTP.
.TP .TP
.B \-P, --edns-packet-max=<size> .B \-P, --edns-packet-max=<size>
Specify the largest EDNS.0 UDP packet which is supported by the DNS Specify the largest EDNS.0 UDP packet which is supported by the DNS
forwarder. Defaults to 1280, which is the RFC2671-recommended maximum forwarder. Defaults to 4096, which is the RFC5625-recommended size.
for ethernet.
.TP .TP
.B \-Q, --query-port=<query_port> .B \-Q, --query-port=<query_port>
Send outbound DNS queries from, and listen for their replies on, the Send outbound DNS queries from, and listen for their replies on, the
@@ -208,13 +212,17 @@ Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192
which are not found in /etc/hosts or the DHCP leases file are answered which are not found in /etc/hosts or the DHCP leases file are answered
with "no such domain" rather than being forwarded upstream. with "no such domain" rather than being forwarded upstream.
.TP .TP
.B \-V, --alias=<old-ip>,<new-ip>[,<mask>] .B \-V, --alias=[<old-ip>]|[<start-ip>-<end-ip>],<new-ip>[,<mask>]
Modify IPv4 addresses returned from upstream nameservers; old-ip is Modify IPv4 addresses returned from upstream nameservers; old-ip is
replaced by new-ip. If the optional mask is given then any address replaced by new-ip. If the optional mask is given then any address
which matches the masked old-ip will be re-written. So, for instance which matches the masked old-ip will be re-written. So, for instance
.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 .B --alias=1.2.3.0,6.7.8.0,255.255.255.0
will map 1.2.3.56 to 6.7.8.56 and 1.2.3.67 to 6.7.8.67. This is what will map 1.2.3.56 to 6.7.8.56 and 1.2.3.67 to 6.7.8.67. This is what
Cisco PIX routers call "DNS doctoring". Cisco PIX routers call "DNS doctoring". If the old IP is given as
range, then only addresses in the range, rather than a whole subnet,
are re-written. So
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
.TP .TP
.B \-B, --bogus-nxdomain=<ipaddr> .B \-B, --bogus-nxdomain=<ipaddr>
Transform replies which contain the IP address given into "No such Transform replies which contain the IP address given into "No such
@@ -385,6 +393,14 @@ Return a PTR DNS record.
.B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>] .B --naptr-record=<name>,<order>,<preference>,<flags>,<service>,<regexp>[,<replacement>]
Return an NAPTR DNS record, as specified in RFC3403. Return an NAPTR DNS record, as specified in RFC3403.
.TP .TP
.B --cname=<cname>,<target>
Return a CNAME record which indicates that <cname> is really
<target>. There are significant limitations on the target; it must be a
DNS name which is known to dnsmasq from /etc/hosts (or additional
hosts files) or from DHCP. If the target does not satisfy this
criteria, the whole cname is ignored. The cname must be unique, but it
is permissable to have more than one cname pointing to the same target.
.TP
.B --interface-name=<name>,<interface> .B --interface-name=<name>,<interface>
Return a DNS record associating the name with the primary address on Return a DNS record associating the name with the primary address on
the given interface. This flag specifies an A record for the given the given interface. This flag specifies an A record for the given
@@ -410,25 +426,22 @@ Set the maximum number of concurrent DNS queries. The default value is
where this needs to be increased is when using web-server log file where this needs to be increased is when using web-server log file
resolvers, which can generate large numbers of concurrent queries. resolvers, which can generate large numbers of concurrent queries.
.TP .TP
.B \-F, --dhcp-range=[[net:]network-id,]<start-addr>,<end-addr>[[,<netmask>],<broadcast>][,<default lease time>] .B \-F, --dhcp-range=[[net:]network-id,]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
Enable the DHCP server. Addresses will be given out from the range Enable the DHCP server. Addresses will be given out from the range
<start-addr> to <end-addr> and from statically defined addresses given <start-addr> to <end-addr> and from statically defined addresses given
in in
.B dhcp-host .B dhcp-host
options. If the lease time is given, then leases options. If the lease time is given, then leases
will be given for that length of time. The lease time is in seconds, will be given for that length of time. The lease time is in seconds,
or minutes (eg 45m) or hours (eg 1h) or the literal "infinite". The or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
the default lease time is one hour. The
minimum lease time is two minutes. This minimum lease time is two minutes. This
option may be repeated, with different addresses, to enable DHCP option may be repeated, with different addresses, to enable DHCP
service to more than one network. For directly connected networks (ie, service to more than one network. For directly connected networks (ie,
networks on which the machine running dnsmasq has an interface) the networks on which the machine running dnsmasq has an interface) the
netmask is optional. It is, however, required for networks which netmask is optional. It is, however, required for networks which
receive DHCP service via a relay agent. The broadcast address is receive DHCP service via a relay agent. The broadcast address is
always optional. On some broken systems, dnsmasq can listen on only always optional. It is always
one interface when using DHCP, and the name of that interface must be
given using the
.B interface
option. This limitation currently affects OpenBSD before version 4.0. It is always
allowed to have more than one dhcp-range in a single subnet. The optional allowed to have more than one dhcp-range in a single subnet. The optional
network-id is a alphanumeric label which marks this network so that network-id is a alphanumeric label which marks this network so that
dhcp options may be specified on a per-network basis. dhcp options may be specified on a per-network basis.
@@ -437,10 +450,18 @@ a tag to matching it. Only one tag may be set, but more than one tag may be matc
The end address may be replaced by the keyword The end address may be replaced by the keyword
.B static .B static
which tells dnsmasq to enable DHCP for the network specified, but not which tells dnsmasq to enable DHCP for the network specified, but not
to dynamically allocate IP addresses. Only hosts which have static to dynamically allocate IP addresses: only hosts which have static
addresses given via addresses given via
.B dhcp-host .B dhcp-host
or from /etc/ethers will be served. or from /etc/ethers will be served. The end address may be replaced by
the keyword
.B proxy
in which case dnsmasq will provide proxy-DHCP on the specified
subnet. (See
.B pxe-prompt
and
.B pxe-service
for details.)
.TP .TP
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore] .B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,net:<netid>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine Specify per host parameters for the DHCP server. This allows a machine
@@ -465,9 +486,11 @@ hardware addresses to identify hosts by prefixing with 'id:'. Thus:
refers to the host with client identifier 01:02:03:04. It is also refers to the host with client identifier 01:02:03:04. It is also
allowed to specify the client ID as text, like this: allowed to specify the client ID as text, like this:
.B --dhcp-host=id:clientidastext,..... .B --dhcp-host=id:clientidastext,.....
The special option id:* means "ignore any client-id The special option id:* means "ignore any client-id
and use MAC addresses only." This is useful when a client presents a client-id sometimes and use MAC addresses only." This is useful when a client presents a client-id sometimes
but not others. but not others.
If a name appears in /etc/hosts, the associated address can be If a name appears in /etc/hosts, the associated address can be
allocated to a DHCP lease, but only if a allocated to a DHCP lease, but only if a
.B --dhcp-host .B --dhcp-host
@@ -478,8 +501,10 @@ instance
.B --dhcp-host=00:20:e0:3b:13:af,ignore .B --dhcp-host=00:20:e0:3b:13:af,ignore
This is This is
useful when there is another DHCP server on the network which should useful when there is another DHCP server on the network which should
be used by some machines. The net:<network-id> sets the network-id tag be used by some machines.
whenever this dhcp-host directive is in use.This can be used to
The net:<network-id> sets the network-id tag
whenever this dhcp-host directive is in use. This can be used to
selectively send DHCP options just for this host. When a host matches any selectively send DHCP options just for this host. When a host matches any
dhcp-host directive (or one implied by /etc/ethers) then the special dhcp-host directive (or one implied by /etc/ethers) then the special
network-id tag "known" is set. This allows dnsmasq to be configured to network-id tag "known" is set. This allows dnsmasq to be configured to
@@ -490,13 +515,27 @@ wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore .B --dhcp-host=00:20:e0:3b:13:*,ignore
will cause dnsmasq to ignore a range of hardware addresses. Note that will cause dnsmasq to ignore a range of hardware addresses. Note that
the "*" will need to be escaped or quoted on a command line, but not the "*" will need to be escaped or quoted on a command line, but not
in the configuration file. Hardware addresses normally match any in the configuration file.
Hardware addresses normally match any
network (ARP) type, but it is possible to restrict them to a single network (ARP) type, but it is possible to restrict them to a single
ARP type by preceding them with the ARP-type (in HEX) and "-". so ARP type by preceding them with the ARP-type (in HEX) and "-". so
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 .B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
will only match a will only match a
Token-Ring hardware address, since the ARP-address type for token ring Token-Ring hardware address, since the ARP-address type for token ring
is 6. is 6.
As a special case, it is possible to include more than one
hardware address. eg:
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
This allows an IP address to be associated with
multiple hardware addresses, and gives dnsmasq permission to abandon a
DHCP lease to one of the hardware addresses when another one asks for
a lease. Beware that this is a dangerous thing to do, it will only
work reliably if only one of the hardware addresses is active at any
time and there is no way for dnsmasq to enforce this. It is, for instance,
useful to allocate a stable IP address to a laptop which
has both wired and wireless interfaces.
.TP .TP
.B --dhcp-hostsfile=<file> .B --dhcp-hostsfile=<file>
Read DHCP host information from the specified file. The file contains Read DHCP host information from the specified file. The file contains
@@ -508,7 +547,12 @@ the file will be re-read when dnsmasq receives SIGHUP.
.B --dhcp-optsfile=<file> .B --dhcp-optsfile=<file>
Read DHCP option information from the specified file. The advantage of Read DHCP option information from the specified file. The advantage of
using this option is the same as for --dhcp-hostsfile: the using this option is the same as for --dhcp-hostsfile: the
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
it is possible to encode the information in a
.B --dhcp-boot
flag as DHCP options, using the options names bootfile-name,
server-ip-address and tftp-server. This allows these to be included
in a dhcp-optsfile.
.TP .TP
.B \-Z, --read-ethers .B \-Z, --read-ethers
Read /etc/ethers for information about hosts for the DHCP server. The Read /etc/ethers for information about hosts for the DHCP server. The
@@ -519,7 +563,7 @@ have exactly the same effect as
options containing the same information. /etc/ethers is re-read when options containing the same information. /etc/ethers is re-read when
dnsmasq receives SIGHUP. dnsmasq receives SIGHUP.
.TP .TP
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]] .B \-O, --dhcp-option=[<network-id>,[<network-id>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]]
Specify different or extra options to DHCP clients. By default, Specify different or extra options to DHCP clients. By default,
dnsmasq sends some standard options to DHCP clients, the netmask and dnsmasq sends some standard options to DHCP clients, the netmask and
broadcast address are set to the same as the host running dnsmasq, and broadcast address are set to the same as the host running dnsmasq, and
@@ -579,10 +623,24 @@ client. It is
possible to omit the vendorclass completely; possible to omit the vendorclass completely;
.B --dhcp-option=vendor:,1,0.0.0.0 .B --dhcp-option=vendor:,1,0.0.0.0
in which case the encapsulated option is always sent. in which case the encapsulated option is always sent.
Options may be encapsulated within other options: for instance
.B --dhcp-option=encap:175, 190, "iscsi-client0"
will send option 175, within which is the option 190. If multiple
options are given which are encapsulated with the same option number
then they will be correctly combined into one encapsulated option.
encap: and vendor: are may not both be set in the same dhcp-option.
The final variant on encapsulated options is "Vendor-Identifying
Vendor Options" as specified by RFC3925. These are denoted like this:
.B --dhcp-option=vi-encap:2, 10, "text"
The number in the vi-encap: section is the IANA enterprise number
used to identify this option.
The address 0.0.0.0 is not treated specially in The address 0.0.0.0 is not treated specially in
encapsulated vendor class options. encapsulated options.
.TP .TP
.B --dhcp-option-force=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]] .B --dhcp-option-force=[<network-id>,[<network-id>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]]
This works in exactly the same way as This works in exactly the same way as
.B --dhcp-option .B --dhcp-option
except that the option will always be sent, even if the client does except that the option will always be sent, even if the client does
@@ -634,10 +692,26 @@ agent ID and one provided by a relay agent, the network-id tag is set.
.B --dhcp-subscrid=<network-id>,<subscriber-id> .B --dhcp-subscrid=<network-id>,<subscriber-id>
Map from RFC3993 subscriber-id relay agent options to network-id tags. Map from RFC3993 subscriber-id relay agent options to network-id tags.
.TP .TP
.B --dhcp-match=<network-id>,<option number> .B --dhcp-match=<network-id>,<option number>|option:<option name>|vi-encap:<enterprise>[,<value>]
Set the network-id tag if the client sends a DHCP option of the given Without a value, set the network-id tag if the client sends a DHCP
number. This can be used to identify particular clients which send option of the given number or name. When a value is given, set the tag only if
information using private option numbers. the option is sent and matches the value. The value may be of the form
"01:ff:*:02" in which case the value must match (apart from widcards)
but the option sent may have unmatched data past the end of the
value. The value may also be of the same form as in
.B dhcp-option
in which case the option sent is treated as an array, and one element
must match, so
--dhcp-match=efi-ia32,option:client-arch,6
will set the tag "efi-ia32" if the the number 6 appears in the list of
architectures sent by the client in option 93. (See RFC 4578 for
details.) If the value is a string, substring matching is used.
The special form with vi-encap:<enterpise number> matches against
vendor-identifying vendor classes for the specified enterprise. Please
see RFC 3925 for more details of the rare and interesting beasts.
.TP .TP
.B \-J, --dhcp-ignore=<network-id>[,<network-id>] .B \-J, --dhcp-ignore=<network-id>[,<network-id>]
When all the given network-ids match the set of network-ids derived When all the given network-ids match the set of network-ids derived
@@ -670,6 +744,58 @@ is providing a TFTP service (see
If the optional network-id(s) are given, If the optional network-id(s) are given,
they must match for this configuration to be sent. Note that they must match for this configuration to be sent. Note that
network-ids are prefixed by "net:" to distinguish them. network-ids are prefixed by "net:" to distinguish them.
.TP
.B --pxe-service=[net:<network-id>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
Most uses of PXE boot-ROMS simply allow the PXE
system to obtain an IP address and then download the file specified by
.B dhcp-boot
and execute it. However the PXE system is capable of more complex
functions when supported by a suitable DHCP server.
This specifies a boot option which may appear in a PXE boot menu. <CSA> is
client system type, only services of the correct type will appear in a
menu. The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI and X86-64_EFI; an
integer may be used for other types. The
parameter after the menu text may be a file name, in which case dnsmasq acts as a
boot server and directs the PXE client to download the file by TFTP,
either from itself (
.B enable-tftp
must be set for this to work) or another TFTP server if the final IP
address is given.
Note that the "layer"
suffix (normally ".0") is supplied by PXE, and should not be added to
the basename. If an integer boot service type, rather than a basename
is given, then the PXE client will search for a
suitable boot service for that type on the network. This search may be done
by broadcast, or direct to a server if its IP address is provided.
If no boot service type or filename is provided (or a boot service type of 0 is specified)
then the menu entry will abort the net boot procedure and
continue booting from local media.
.TP
.B --pxe-prompt=[net:<network-id>,]<prompt>[,<timeout>]
Setting this provides a prompt to be displayed after PXE boot. If the
timeout is given then after the
timeout has elapsed with no keyboard input, the first available menu
option will be automatically executed. If the timeout is zero then the first available menu
item will be executed immediately. If
.B pxe-prompt
is ommitted the system will wait for user input if there are multiple
items in the menu, but boot immediately if
there is only one. See
.B pxe-service
for details of menu items.
Dnsmasq supports PXE "proxy-DHCP", in this case another DHCP server on
the network is responsible for allocating IP addresses, and dnsmasq
simply provides the information given in
.B pxe-prompt
and
.B pxe-service
to allow netbooting. This mode is enabled using the
.B proxy
keyword in
.B dhcp-range.
.TP .TP
.B \-X, --dhcp-lease-max=<number> .B \-X, --dhcp-lease-max=<number>
Limits dnsmasq to the specified maximum number of DHCP leases. The Limits dnsmasq to the specified maximum number of DHCP leases. The
@@ -693,11 +819,13 @@ port number is used for the server and the port number plus one used
for the client. Finally, two port numbers allows arbitrary for the client. Finally, two port numbers allows arbitrary
specification of both server and client ports for DHCP. specification of both server and client ports for DHCP.
.TP .TP
.B \-3, --bootp-dynamic .B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Enable dynamic allocation of IP addresses to BOOTP clients. Use this Enable dynamic allocation of IP addresses to BOOTP clients. Use this
with care, since each address allocated to a BOOTP client is leased with care, since each address allocated to a BOOTP client is leased
forever, and therefore becomes permanently unavailable for re-use by forever, and therefore becomes permanently unavailable for re-use by
other hosts. other hosts. if this is given without tags, then it unconditionally
enables dynamic allocation. With tags, only when the tags are all
set. It may be repeated with different tag sets.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
By default, the DHCP server will attempt to ensure that an address in By default, the DHCP server will attempt to ensure that an address in
@@ -711,31 +839,28 @@ Extra logging for DHCP: log all the options sent to DHCP clients and
the netid tags used to determine them. the netid tags used to determine them.
.TP .TP
.B \-l, --dhcp-leasefile=<path> .B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information. If this option Use the specified file to store DHCP lease information.
is given but no dhcp-range option is given then dnsmasq version 1
behaviour is activated. The file given is assumed to be an ISC dhcpd
lease file and parsed for leases which are then added to the DNS
system if they have a hostname. This functionality may have been
excluded from dnsmasq at compile time, in which case an error will
occur. In any case note that ISC leasefile integration is a deprecated
feature. It should not be used in new installations, and will be
removed in a future release.
.TP .TP
.B \-6 --dhcp-script=<path> .B \-6 --dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed, the Whenever a new DHCP lease is created, or an old one destroyed, the
binary specified by this option is run. The arguments to the process executable specified by this option is run. The arguments to the process
are "add", "old" or "del", the MAC are "add", "old" or "del", the MAC
address of the host (or "<null>"), the IP address, and the hostname, address of the host, the IP address, and the hostname,
if known. "add" means a lease has been created, "del" means it has if known. "add" means a lease has been created, "del" means it has
been destroyed, "old" is a notification of an existing lease when been destroyed, "old" is a notification of an existing lease when
dnsmasq starts or a change to MAC address or hostname of an existing dnsmasq starts or a change to MAC address or hostname of an existing
lease (also, lease length or expiry and client-id, if leasefile-ro is set). lease (also, lease length or expiry and client-id, if leasefile-ro is set).
The process is run as root (assuming that dnsmasq was originally run as If the MAC address is from a network type other than ethernet,
it will have the network type prepended, eg "06-01:23:45:67:89:ab" for
token ring. The process is run as root (assuming that dnsmasq was originally run as
root) even if dnsmasq is configured to change UID to an unprivileged user. root) even if dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, and if the The environment is inherited from the invoker of dnsmasq, and if the
host provided a client-id, this is stored in the environment variable host provided a client-id, this is stored in the environment variable
DNSMASQ_CLIENT_ID. If the client provides vendor-class or user-class DNSMASQ_CLIENT_ID. If the fully-qualified domain name of the host is
information, these are provided in DNSMASQ_VENDOR_CLASS and known, the domain part is stored in DNSMASQ_DOMAIN.
If the client provides vendor-class, hostname or user-class,
these are provided in DNSMASQ_VENDOR_CLASS
DNSMASQ_SUPPLIED_HOSTNAME and
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn variables, but only for
"add" actions or "old" actions when a host resumes an existing lease, "add" actions or "old" actions when a host resumes an existing lease,
since these data are not held in dnsmasq's lease since these data are not held in dnsmasq's lease
@@ -749,7 +874,10 @@ removed, an "old" event is generated with the new state of the lease,
ie no name, and the former name is provided in the environment ie no name, and the former name is provided in the environment
variable DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE stores the name of variable DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE stores the name of
the interface on which the request arrived; this is not set for "old" the interface on which the request arrived; this is not set for "old"
actions when dnsmasq restarts. actions when dnsmasq restarts. DNSMASQ_RELAY_ADDRESS is set if the client
used a DHCP relay to contact dnsmasq and the IP address of the relay
is known. DNSMASQ_TAGS contains all the network-id tags set during the
DHCP transaction, separated by spaces.
All file descriptors are All file descriptors are
closed except stdin, stdout and stderr which are open to /dev/null closed except stdin, stdout and stderr which are open to /dev/null
(except in debug mode). (except in debug mode).
@@ -781,12 +909,13 @@ to the client-id and lease length and expiry time.
.TP .TP
.B --bridge-interface=<interface>,<alias>[,<alias>] .B --bridge-interface=<interface>,<alias>[,<alias>]
Treat DHCP request packets arriving at any of the <alias> interfaces Treat DHCP request packets arriving at any of the <alias> interfaces
as if they had arrived at <interface>. This option is only available as if they had arrived at <interface>. This option is necessary when
on BSD platforms, and is necessary when using "old style" bridging, since using "old style" bridging on BSD platforms, since
packets arrive at tap interfaces which don't have an IP address. packets arrive at tap interfaces which don't have an IP address.
.TP .TP
.B \-s, --domain=<domain> .B \-s, --domain=<domain>[,<address range>]
Specifies the domain for the DHCP server. This has two effects; Specifies DNS domains for the DHCP server. Domains may be be given
unconditionally (without the IP range) or for limited IP ranges. This has two effects;
firstly it causes the DHCP server to return the domain to any hosts firstly it causes the DHCP server to return the domain to any hosts
which request it, and secondly it sets the domain which it is legal which request it, and secondly it sets the domain which it is legal
for DHCP-configured hosts to claim. The intention is to constrain for DHCP-configured hosts to claim. The intention is to constrain
@@ -803,7 +932,28 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach
.B dnsmasq .B dnsmasq
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
given as "#" then the domain is read from the first "search" directive given as "#" then the domain is read from the first "search" directive
in /etc/resolv.conf (or equivalent). in /etc/resolv.conf (or equivalent). The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask> or just a single
<ip address>. See
.B --dhcp-fqdn
which can change the behaviour of dnsmasq with domains.
.TP
.B --dhcp-fqdn
In the default mode, dnsmasq inserts the unqualified names of
DHCP clients into the DNS. For this reason, the names must be unique,
even if two clients which have the same name are in different
domains. If a second DHCP client appears which has the same name as an
existing client, the name is transfered to the new client. If
.B --dhcp-fqdn
is set, this behaviour changes: the unqualified name is no longer
put in the DNS, only the qualified name. Two DHCP clients with the
same name may both keep the name, provided that the domain part is
different (ie the fully qualified names differ.) To ensure that all
names have a domain part, there must be at least
.B --domain
without an address specified when
.B --dhcp-fqdn
is set.
.TP .TP
.B --enable-tftp .B --enable-tftp
Enable the TFTP server function. This is deliberately limited to that Enable the TFTP server function. This is deliberately limited to that
@@ -865,10 +1015,11 @@ of concurrent TFTP connections is limited by the size of the port range.
Specify a different configuration file. The conf-file option is also allowed in Specify a different configuration file. The conf-file option is also allowed in
configuration files, to include multiple configuration files. configuration files, to include multiple configuration files.
.TP .TP
.B \-7, --conf-dir=<directory> .B \-7, --conf-dir=<directory>[,<file-extension>......]
Read all the files in the given directory as configuration Read all the files in the given directory as configuration
files. Files whose names end in ~ or start with . or start and end files. If extension(s) are given, any files which end in those
with # are skipped. This flag may be given on the command extensions are skipped. Any files whose names end in ~ or start with . or start and end
with # are always skipped. This flag may be given on the command
line or in a configuration file. line or in a configuration file.
.SH CONFIG FILE .SH CONFIG FILE
At startup, dnsmasq reads At startup, dnsmasq reads
@@ -1006,6 +1157,9 @@ collects a set of valid network-id tags, one from the
.B dhcp-range .B dhcp-range
used to allocate the address, one from any matching used to allocate the address, one from any matching
.B dhcp-host .B dhcp-host
(and "known" if a dhcp-host matches)
the tag "bootp" for BOOTP requests, a tag whose name is the
name if the interface on which the request arrived,
and possibly many from matching vendor classes and user and possibly many from matching vendor classes and user
classes sent by the DHCP client. Any classes sent by the DHCP client. Any
.B dhcp-option .B dhcp-option
@@ -1105,6 +1259,24 @@ or an additional hosts file. The list can be very long,
dnsmasq has been tested successfully with one million names. That size dnsmasq has been tested successfully with one million names. That size
file needs a 1GHz processor and about 60Mb of RAM. file needs a 1GHz processor and about 60Mb of RAM.
.SH INTERNATIONALISATION
Dnsmasq can be compiled to support internationalisation. To do this,
the make targets "all-i18n" and "install-i18n" should be used instead of
the standard targets "all" and "install". When internationalisation
is compiled in, dnsmasq will produce log messages in the local
language and support internationalised domain names (IDN). Domain
names in /etc/hosts, /etc/ethers and /etc/dnsmasq.conf which contain
non-ASCII characters will be translated to the DNS-internal punycode
representation. Note that
dnsmasq determines both the language for messages and the assumed
charset for configuration
files from the LANG environment variable. This should be set to the system
default value by the script which is responsible for starting
dnsmasq. When editing the configuration files, be careful to do so
using only the system-default locale and not user-specific one, since
dnsmasq has no direct way of determining the charset in use, and must
assume that it is the system default.
.SH FILES .SH FILES
.IR /etc/dnsmasq.conf .IR /etc/dnsmasq.conf
+249 -80
View File
@@ -17,9 +17,8 @@ resueltos. Tambi
vía DHCP. vía DHCP.
.PP .PP
El servidor DHCP dnsmasq incluye soporte para asignación de direcciones El servidor DHCP dnsmasq incluye soporte para asignación de direcciones
estáticas, redes múltiples, DHCP-relay y especificadores de subredes estáticas y redes múltiples. Automáticamente envía un predeterminado sensible de
RFC3011. Automáticamente envía un predeterminado sensible de opciones opciones DHCP, y puede ser configurado para enviar cualquier opciones DHCP deseadas,
DHCP, y puede ser configurado para enviar cualquier opciones DHCP deseadas,
incluyendo opciones encapsuladas por vendedores. Incluye un servidor seguro incluyendo opciones encapsuladas por vendedores. Incluye un servidor seguro
TFTP solo-lectura para permitir el inicio vía red/PXE de hosts DHCP. Tambíen TFTP solo-lectura para permitir el inicio vía red/PXE de hosts DHCP. Tambíen
incluye soporte para BOOTP. incluye soporte para BOOTP.
@@ -33,17 +32,25 @@ archivo PID. En BSD, a menos que la librer
la forma larga de las opciones no funciona en la línea de comandos, la forma larga de las opciones no funciona en la línea de comandos,
pero todavía es reconocida en el archivo de configuración. pero todavía es reconocida en el archivo de configuración.
.TP .TP
.B --test
Leer archivo(s) de configuración y revisar su sintaxis. Salir con código
0 si todo está bien, o un código no-cero en cualquier otro caso. No
iniciar dnsmasq.
.TP
.B \-h, --no-hosts .B \-h, --no-hosts
No leer los nombres de hosts en /etc/hosts. No leer los nombres de hosts en /etc/hosts.
.TP .TP
.B \-H, --addn-hosts=<archivo> .B \-H, --addn-hosts=<archivo>
Archivo de hosts adicional. Leer el archivo especificado adicionalmente Archivo de hosts adicional. Leer el archivo especificado adicionalmente
a /etc/hosts. Si se brinda -h, leer solo el archivo especificado. Esta a /etc/hosts. Si se brinda -h, leer solo el archivo especificado. Esta
opción puede ser repetida para más de un archivo de hosts adicional. opción puede ser repetida para más de un archivo de hosts adicional. Si
un directorio es brindado, entonces leer todos los archivos contenidos en
ese directorio.
.TP .TP
.B \-E, --expand-hosts .B \-E, --expand-hosts
Agregar el dominio a nombres sencillos (sin punto) en /etc/hosts de la Agregar el dominio a nombres sencillos (sin punto) en /etc/hosts de la
misma manera que con nombres derivados de DHCP. misma manera que con nombres derivados de DHCP. Nótese que esto no
aplica a nombres de dominio en cnames, expedientes PTR, TXT, etc.
.TP .TP
.B \-T, --local-ttl=<tiempo> .B \-T, --local-ttl=<tiempo>
Al responder con información desde /etc/hosts o desde el archivo Al responder con información desde /etc/hosts o desde el archivo
@@ -127,8 +134,8 @@ solo DHCP y/o TFTP.
.TP .TP
.B \-P, --edns-packet-max=<tamaño> .B \-P, --edns-packet-max=<tamaño>
Especificar el paquete UDP EDNS.0 más grande que es soportado por Especificar el paquete UDP EDNS.0 más grande que es soportado por
el reenviador DNS. Por predeterminado es 1280, lo cual es el el reenviador DNS. Por predeterminado es 4096, lo cual es el
máximo recomendado en RFC2671 para ethernet. tamaño recomendado en RFC5625.
.TP .TP
.B \-Q, --query-port=<puerto> .B \-Q, --query-port=<puerto>
Enviar búsquedas outbound desde, y escuchar por respuestas en, Enviar búsquedas outbound desde, y escuchar por respuestas en,
@@ -225,15 +232,19 @@ privados (192.168.x.x, etc.) los cuales no se encuentren en
/etc/hosts o en el archivo de arriendos DHCP es respondida con /etc/hosts o en el archivo de arriendos DHCP es respondida con
"dominio no existente" en vez de ser reenviada upstream. "dominio no existente" en vez de ser reenviada upstream.
.TP .TP
.B \-V, --alias=<IP viejo>,<IP nuevo>[,<máscara>] .B \-V, --alias=[<IP viejo>]|[<IP inicio>-<IP final>],<IP nuevo>[,<máscara>]
Modificar direcciones IPv4 retornadas desde servidores DNS upstream; Modificar direcciones IPv4 retornadas desde servidores DNS upstream;
<IP viejo> es remplazado con <IP nuevo>. Si la máscara opcional <IP viejo> es remplazado con <IP nuevo>. Si la máscara opcional
es brindada, entonces cualquier dirección que coincida con el es brindada, entonces cualquier dirección que coincida con el
<IP viejo> enmascarado será re-escrita. Así que, por ejemplo, <IP viejo> enmascarado será re-escrita. Así que, por ejemplo,
.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 trazará 1.2.3.56 a 6.7.8.56 .B --alias=1.2.3.0,6.7.8.0,255.255.255.0 trazará 1.2.3.56 a 6.7.8.56
y 1.2.3.67 a 6.7.8.67. Esto es lo que y 1.2.3.67 a 6.7.8.67. Esto es lo que
ruteadores Cisco PIX llaman "DNS doctoring". ruteadores Cisco PIX llaman "DNS doctoring". Si la dirección vieja es
.TP brindada como un rango, entonces solo direcciones en ese rango, y no
la subred entera, son re-escritas. De tal manera que
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
relaciona 192.168.0.10->192.168.0.40 a 10.0.0.10->10.0.0.40
.TP
.B \-B, --bogus-nxdomain=<dirección IP> .B \-B, --bogus-nxdomain=<dirección IP>
Transformar respuestas que contienen la dirección IP brindada a Transformar respuestas que contienen la dirección IP brindada a
respuestas tipo "Dominio no existe". La intención de esto es actuar respuestas tipo "Dominio no existe". La intención de esto es actuar
@@ -414,8 +425,15 @@ Retornar un r
.B --naptr-record=<nombre>,<orden>,<preferencia>,<opciones>,<servicio>,<regexp>[,<remplazo>] .B --naptr-record=<nombre>,<orden>,<preferencia>,<opciones>,<servicio>,<regexp>[,<remplazo>]
Retornar un récord DNS NAPTR, como especificado en RFC3403. Retornar un récord DNS NAPTR, como especificado en RFC3403.
.TP .TP
.B --cname=<cname>,<target>
Retornar un expediente CNAME que indica que <cname> es realmente <target>. Hay
limitaciones significativas en el target. Debe ser un nombre DNS que le es conocido
a dnsmasq desde /etc/hosts (o archivos hosts adicionales) o de DHCP. Si el target
no satisface este criterio, el cname entero es ignorado. El cname debe ser único,
pero es permisible tener más de un cname indicando el mismo target.
.TP
.B --interface-name=<nombre>,<interface> .B --interface-name=<nombre>,<interface>
Retornar un récord DNS, asociando el nombre con la dirección primaria Retornar un expediente DNS, asociando el nombre con la dirección primaria
en la interface brindada. Esta opción especifica un expediente tipo A en la interface brindada. Esta opción especifica un expediente tipo A
para el nombre brindado de la misma forma que una línea de /etc/hosts, para el nombre brindado de la misma forma que una línea de /etc/hosts,
excepto que la dirección no es constante y es en vez tomada de la excepto que la dirección no es constante y es en vez tomada de la
@@ -442,39 +460,43 @@ de casos. La
es al usar resolvedores de bitácoras de servidores web, los cuales pueden es al usar resolvedores de bitácoras de servidores web, los cuales pueden
generar un número inmenso de búsquedas simultáneas. generar un número inmenso de búsquedas simultáneas.
.TP .TP
.B \-F, --dhcp-range=[[net:]network-id,]<dirección-inicio>,<dirección-final>[[,<máscara>],<broadcast>][,<tiempo de arriendo predeterminado>] .B \-F, --dhcp-range=[[net:]network-id,]<dirección-inicio>,<dirección-final>[,<máscara>[,<broadcast>]][,<tiempo de arriendo>]
Habilitar el servidor DHCP. Direcciones serán distribuidas desde el Habilitar el servidor DHCP. Direcciones serán distribuidas desde el
rango <dirección-inicio> hasta <dirección-final> y desde direcciones definidas rango <dirección-inicio> hasta <dirección-final> y desde direcciones definidas
estáticamente en opciones estáticamente en opciones
.B dhcp-host .B dhcp-host
Si el tiempo de arriendo es especificado, entonces arriendos serán Si el tiempo de arriendo es especificado, entonces arriendos serán
otorgados por esa cantidad de tiempo. El tiempo de arriendo es en otorgados por esa cantidad de tiempo. El tiempo de arriendo es en
segundos, o minutos (por ejemplo, 45m), o horas (por ejemplo, 1h), o el segundos, o minutos (por ejemplo, 45m), u horas (por ejemplo, 1h), o
literal "infinite". Esta opción puede ser repetida, con diferentes "infinite". Si no es brindada, el tiempo de arriendo predeterminado
es de una hora. El tiempo de arriendo mínimo es de dos minutos.
Esta opción puede ser repetida, con diferentes
direcciones, para habilitar servicio DHCP en más de una red. Para direcciones, para habilitar servicio DHCP en más de una red. Para
redes conectadas diréctamente (en otras palabras, redes en las redes conectadas diréctamente (en otras palabras, redes en las
cuales la máquina corriendo dnsmasq tiene una interface) la cuales la máquina corriendo dnsmasq tiene una interface) la
máscara de subred es opcional. Pero, es requerida para redes que máscara de subred es opcional. Pero, es requerida para redes que
reciben servicio DHCP vía un agente de relay. La dirección de reciben servicio DHCP vía un agente de relay. La dirección de
broadcast siempre es opcional. En algunos sistemas rotos, dnsmasq broadcast siempre es opcional. Siempre se permite tener más de
solo puede escuchar en una interface cuando se usa DHCP, y el un rango dhcp (dhcp-range) en una subred. El parámetro opcional
nombre de esa interface debe ser brindado usando la opción network-id es una etiqueta alfanumérica la cual marca esta red de
.B interface tal forma que opciones dhcp puedan ser especificadas en base a cada red.
Esta limitación actualmente afecta a OpenBSD antes de versión 4.0.
Siempre se permite tener más de un rango dhcp (dhcp-range) en una
subred. El parámetro opcional network-id es una etiqueta alfanumérica
la cual marca esta red de tal forma que opciones dhcp puedan ser
especificadas en base a cada red.
Cuando es prefijada con 'net:' entonces el significado cambia Cuando es prefijada con 'net:' entonces el significado cambia
de "fijar etiqueta" a "coincidir con etiqueta". Solo una etiqueta puede de "fijar etiqueta" a "coincidir con etiqueta". Solo una etiqueta puede
ser fijada, pero más de una puede ser revisada por coincidencias. La ser fijada, pero más de una puede ser revisada por coincidencias. La
dirección final puede ser remplazada por la palabra clave dirección final puede ser remplazada por la palabra clave
.B static .B static
la cual le dice a dnsmasq que debe habilitar DHCP para la red la cual le dice a dnsmasq que debe habilitar DHCP para la red
especificada, pero no alocar dinámicamente direcciones IP. especificada, pero no alocar dinámicamente direcciones IP:
Solo hosts que tienen direcciones estáticas brindadas vía Solo hosts que tienen direcciones estáticas brindadas vía
.B dhcp-host .B dhcp-host
o desde /etc/ethers serán servidas. o desde /etc/ethers serán servidas. La dirección final puede ser
remplazada por la palabra clave
.B proxy
caso en el cual dnsmasq proveerá proxy-DHCP en la subred especificada. (Ver
.B pxe-prompt
y
.B pxe-service
para detalles.)
.TP .TP
.B \-G, --dhcp-host=[<dirección de hardware>][,id:<client_id>|*][,net:<netid>][,<dirección IP>][,<nombre de host>][,<tiempo de arriendo>][,ignore] .B \-G, --dhcp-host=[<dirección de hardware>][,id:<client_id>|*][,net:<netid>][,<dirección IP>][,<nombre de host>][,<tiempo de arriendo>][,ignore]
Especificar parámetros por host para el servidor DHCP. Esto permite Especificar parámetros por host para el servidor DHCP. Esto permite
@@ -500,9 +522,11 @@ hardware para identificar hosts prefijando 'id:'. O sea que:
se refiere al host con identificador de cliente 01:02:03:04. se refiere al host con identificador de cliente 01:02:03:04.
También se permite especificar el ID de cliente como texto, así: También se permite especificar el ID de cliente como texto, así:
.B --dhcp-host=id:iddeclientecomotexto,..... .B --dhcp-host=id:iddeclientecomotexto,.....
La opción especial id:* significa "ignorar cualquier ID de cliente La opción especial id:* significa "ignorar cualquier ID de cliente
y usar solamente direcciones MAC." Esto es útil cuando un cliente y usar solamente direcciones MAC." Esto es útil cuando un cliente
presenta un ID de cliente algunas veces pero otras no. presenta un ID de cliente algunas veces pero otras no.
Si un nombre aparece en /etc/hosts, la dirección asociada puede Si un nombre aparece en /etc/hosts, la dirección asociada puede
ser alocada a un arriendo DHCP, pero solo si existe una opción ser alocada a un arriendo DHCP, pero solo si existe una opción
.B --dhcp-host .B --dhcp-host
@@ -511,14 +535,16 @@ le dice a dnsmasq que no debe ofrecer jam
una máquina. La máquina puede ser especificada por dirección de una máquina. La máquina puede ser especificada por dirección de
hardware, ID de cliente, o nombre de host, por ejemplo: hardware, ID de cliente, o nombre de host, por ejemplo:
.B --dhcp-host=00:20:e0:3b:13:af,ignore .B --dhcp-host=00:20:e0:3b:13:af,ignore
Esto es útil cuando hay otro servidor DHCP en la red para ser Esto es útil cuando hay otro servidor DHCP en la red que debe ser
usado por algúnas máquinas. El net:<network-id> fija la etiqueta usado por algúnas máquinas.
network-id cuando sea que esta directiva dhcp-host está en uso.
Esto puede ser usado para enviar selectivamente opciones DHCP El net:<network-id> fija la etiqueta network-id cuando sea que
a este host. Cuando un host coincide con cualquier directiva esta directiva dhcp-host está en uso. Esto puede ser usado para
dhcp-host (o una implicada por /etc/ethers) entonces la etiqueta enviar selectivamente opciones DHCP a este host. Cuando un host
network-id especial "known" es fijada. Esto permite que dnsmasq sea coincide con cualquier directiva dhcp-host (o una implicada por
configurado para ignorar pedidos desde máquinas desconocidas usando /etc/ethers) entonces la etiqueta network-id especial "known" es
fijada. Esto permite que dnsmasq sea configurado para ignorar
pedidos desde máquinas desconocidas usando
.B --dhcp-ignore=#known .B --dhcp-ignore=#known
Direcciones ethernet (pero no client-ids) pueden tener bytes Direcciones ethernet (pero no client-ids) pueden tener bytes
comodínes, así que por ejemplo comodínes, así que por ejemplo
@@ -526,12 +552,25 @@ comod
causará que dnsmasq ignore un rango de direcciones ethernet. Nótese causará que dnsmasq ignore un rango de direcciones ethernet. Nótese
que el "*" necesitará ser escapado o escrito entre comillas en la que el "*" necesitará ser escapado o escrito entre comillas en la
línea de comandos, pero no en el archivo de configuración. línea de comandos, pero no en el archivo de configuración.
Direcciones de hardware normalmente coinciden con cualquier Direcciones de hardware normalmente coinciden con cualquier
tipo de red (ARP), pero es posible restringirlas a un tipo ARP tipo de red (ARP), pero es posible restringirlas a un tipo ARP
singular precediendolo con el tipo ARP (en HEX) y "-". Así que singular precediendolo con el tipo ARP (en HEX) y "-". Así que
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 .B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
solo coincidiría con una dirección de hardware Token-Ring, dado que solo coincidiría con una dirección de hardware Token-Ring, dado que
el tipo ARP para Token-Ring es 6. el tipo ARP para Token-Ring es 6.
Como caso especial, es posible incluir más de una dirección de
hardware. Ejemplo:
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2
Esto permite que una dirección IP sea asociada con
direcciones de hardware múltiples, y le brinda a dnsmasq permiso
para abandonar un arriendo DHCP a una de las direcciones de hardware
cuando otra pide un arriendo. Nótese que esto es algo peligroso,
sólo funcionará dependiblemente si una de las direcciones de hardware
está activa en cualquier momento y dnsmasq no tiene forma de enforzar
esto. Pero es útil, por ejemplo, para alocar una dirección IP estable
a una laptop que tiene interface alámbrica e inalámbrica.
.TP .TP
.B --dhcp-hostsfile=<archivo> .B --dhcp-hostsfile=<archivo>
Leer información host DHCP desde el archivo especificado. El archivo contiene información de un host por línea. El formato de una línea es igual que texto hacia la derecha de '=' en --dhcp-host. La ventaja de almacenar información host DHCP en este archivo es que puede ser cambiada sin tener que reiniciar dnsmasq. El archivo será re-leído cuando dnsmasq recibe un SIGHUP. Leer información host DHCP desde el archivo especificado. El archivo contiene información de un host por línea. El formato de una línea es igual que texto hacia la derecha de '=' en --dhcp-host. La ventaja de almacenar información host DHCP en este archivo es que puede ser cambiada sin tener que reiniciar dnsmasq. El archivo será re-leído cuando dnsmasq recibe un SIGHUP.
@@ -540,6 +579,11 @@ Leer informaci
Leer información sobre opciones DHCP desde el archivo especificado. La Leer información sobre opciones DHCP desde el archivo especificado. La
ventaja de usar esta opción es la misma que con --dhcp-hostsfile: el ventaja de usar esta opción es la misma que con --dhcp-hostsfile: el
archivo dhcp-optsfile será re-leído cuando dnsmasq recibe un SIGHUP. archivo dhcp-optsfile será re-leído cuando dnsmasq recibe un SIGHUP.
Nótese que es posible colocar la información mediante
.B --dhcp-boot
como opciones DHCP, usando los nombres de opción bootfile-name,
server-ip-address, y tftp-server. Esto permite que sean incluidas en
un archivo dhcp-optsfile.
.TP .TP
.B \-Z, --read-ethers .B \-Z, --read-ethers
Leer /etc/ethers en busca de información sobre hosts para el servidor Leer /etc/ethers en busca de información sobre hosts para el servidor
@@ -549,7 +593,7 @@ dnsmasq, estas l
.B --dhcp-host .B --dhcp-host
que contienen la misma información. /etc/ethers es re-leída cuando dnsmasq recibe un SIGHUP. que contienen la misma información. /etc/ethers es re-leída cuando dnsmasq recibe un SIGHUP.
.TP .TP
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<value>[,<value>]] .B \-O, --dhcp-option=[<network-id>,[<network-id>,]][encap:<opt>,][vi-encap:<enterprise>,][vendor:[<vendor-class>],][<opt>|option:<opt-name>],[<valor>[,<valor>]]
Especificar opciones diferentes o extra a clientes DHCP. Por Especificar opciones diferentes o extra a clientes DHCP. Por
predeterminado, dnsmasq envía algunas opciones estándar a clientes predeterminado, dnsmasq envía algunas opciones estándar a clientes
DHCP. La máscara de subred y dirección broadcast son fijadas igual DHCP. La máscara de subred y dirección broadcast son fijadas igual
@@ -612,11 +656,23 @@ vendor-class (n
seleccionar opciones encapsuladas en preferencia sobre cualquiera enviada seleccionar opciones encapsuladas en preferencia sobre cualquiera enviada
por el cliente. Es posible omitir el vendorclass completamente; por el cliente. Es posible omitir el vendorclass completamente;
.B --dhcp-option=vendor:,1,0.0.0.0 .B --dhcp-option=vendor:,1,0.0.0.0
caso en el cuál la opción encapsulada siempre es enviada. La dirección caso en el cuál la opción encapsulada siempre es enviada.
0.0.0.0 no es tratada de forma especial en opciones de clase de vendedor Opciones pueden ser encapsuladas dentro de otras opciones, por ejemplo:
encapsuladas. .B --dhcp-option=encap:175, 190, "iscsi-client0"
enviará opción 175, dentro de la cual está opción 190. Si múltiples
opciones son brindadas que están encapsuladas con el mismo número de
opción entonces serán correctamente combinadas en una opción encapsulada.
encap: y vendor: no pueden ser fijadas ambas dentro de la misma opción dhcp-option.
La variante final en opciones encapsuladas es "Vendor-Identifying Vendor Options"
como especificado en RFC3925. Estos son denotados así:
.B --dhcp-option=rfc3925-encap:2, 10, "text"
El número en la sección rfc3925-encap: es el número enterprise usado
para identificar esta opción.
La dirección 0.0.0.0 no es tratada de forma especial en opciones encapsuladas.
.TP .TP
.B --dhcp-option-force=[<network-id>,[<network-id>,]][vendor:[<vendor-class>],]<opt>,[<value>[,<value>]] .B --dhcp-option-force=[<network-id>,[<network-id>,]][encap:<opt>,][rfc3925-encap:<enterprise>,][vendor:[<vendor-class>],]<opt>,[<valor>[,<valor>]]
Esto funciona exáctamente de la misma forma que Esto funciona exáctamente de la misma forma que
.B --dhcp-option .B --dhcp-option
excepto que la opción siempre será enviada, aún si el cliente no la pide en excepto que la opción siempre será enviada, aún si el cliente no la pide en
@@ -670,10 +726,26 @@ network-id es fijado.
.B --dhcp-subscrid=<network-id>,<subscriber-id> .B --dhcp-subscrid=<network-id>,<subscriber-id>
Trazar de opciones relay subscriber-id RFC3993 a opciones network-id. Trazar de opciones relay subscriber-id RFC3993 a opciones network-id.
.TP .TP
.B --dhcp-match=<network-id>,<número de opción> .B --dhcp-match=<network-id>,<option number>|option:<option name>|vi-encap:<enterprise>[,<valor>]
Fijar la opción network-id si el cliente envía un opción DHCP del nombre Sin un valor, fijar la etiqueta network-id si el cliente envía una opción
brindado. Esto puede ser utilizado para identificar clientes particulares DHCP del número o valor brindado. Cuando un valor es brindado, fijar la
que envían información usando números privados de opciones. etiqueta solo si la opción es enviada y coincide con el valor. El valor puede
ser de la forma "01:ff:*:02", caso en el cual el valor debe coincidir (aparte
de los comodines) pero la opción enviada puede tener data que no coincide despues
del final del valor. El valor también puede ser de la misma forma que
.B dhcp-option
caso en el cual la opción enviada es tratada como un array, y un elemento debe
coincidir, así que
--dhcp-match=efi-ia32,option:client-arch,6
fijará la etiqueta a "efi-ia32" si el número 6 aparece en la lista de
architecturas enviada por los clientes en opción 93. (Ver RFC 4578 para
detalles.) Si el valor es un string, coincidencia substring es usada.
La forma especial con vi-encap:<enterpise number> busca coincidencia con
clases de vendedor identificadoras para el enterprise especificado. Por
favor ver RFC 3925 para mas detalles sobre las bestias raras e interesantes.
.TP .TP
.B \-J, --dhcp-ignore=<network-id>[,<network-id>] .B \-J, --dhcp-ignore=<network-id>[,<network-id>]
Cuando todos los network ids brindados coincidan con el juego de Cuando todos los network ids brindados coincidan con el juego de
@@ -707,7 +779,59 @@ dnsmasq. Si dnsmasq est
el inicio atravéz de una red. Si las opcionales network-ids son brindadas, el inicio atravéz de una red. Si las opcionales network-ids son brindadas,
ellas deberán coincidir para que esta configuración sea enviada. Nótese ellas deberán coincidir para que esta configuración sea enviada. Nótese
que network-ids están prefijadas con "net:" para distinguirlas. que network-ids están prefijadas con "net:" para distinguirlas.
.TP .TP
.B --pxe-service=[net:<network-id>,]<CSA>,<texto de menú>[,<nombre base>|<tipo de servicio boot>][,<dirección de servidor>]
La mayoría de usos para boot-ROMS PXE simplemente permiten al sistema PXE
obtener una dirección IP y entonces bajar el archivo especificado por
.B dhcp-boot
y ejecutarlo. Sin embargo, el sistema PXE es capaz de llevar
a cabo funciones más complejas cuando están soportadas por un
servidor DHCP adecuado.
Esto especifica una opción boot que puede aparecer en un menú de boot
PXE. <CSA> es tipo de sistema de cliente, solo servicios del tipo correcto
aparecerán en un menú. Los tipos conocidos son x86PC, PC98, IA64_EFI,
Alpha, Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI y X86-64_EFI;
un número entero puede ser utilizado para otros tipos. El parámetro después
del texto de menú puede ser un nombre de archivo, caso en el cuál dnsmasq
actúa como un servidor boot y le ordena al cliente PXE bajar el archivo
vía TFTP, ya sea de sí mismo (
.B enable-tftp
debe estar fijado para que esto funcione) o desde otro servidor TFTP si la
dirección IP final es brindada.
Nótese que el sufijo "layer" (normalmente ".0") es brindado por PXE, y
no debe ser agregado al nombre base. Si un número entero es brindado en vez
de un nombre base, entonces el cliente PXE buscará un servicio boot adecuado
para ese tipo de red. Esta búsqueda puede ser hecha mediante broadcast,
o directamente a un servidor si la dirección IP es brindada. Si ningún tipo
de servicio boot o nombre de archivo es brindado (o un tipo de servicio boot
de 0 es especificado), entonces la opción de menú abortará el proceso net boot
y continuará desde el medio local.
.TP
.B --pxe-prompt=[net:<network-id>,]<prompt>[,<timeout>]
Fijar esto hace que un aviso sea expuesto despues del boot PXE. Si el timeout
es brindado, entonces despues que el timeout se haya vencido sin input del
teclado, la primera opción del menú sera automaticamente ejecutada. Si el
timeout es cero entonces la primera opción del menú sera automaticamente
ejecutada. Si
.B pxe-prompt
es omitido, el sistema esperará para el input del usuario si hay múltiples
artículos en el menú, pero hará boot imediatamente si hay solo uno. Ver
.B pxe-service
para detalles sobre artículos de menu.
Dnsmasq tiene soporte para "proxy-DHCP" PXE, en este caso otro servidor
DHCP en la red es responsable por asignar direcciones IP, y dnsmasq
simplemente provee la dirección brindada en
.B pxe-prompt
y
.B pxe-service
para permitir boot a travez de la red. Este modo es habilitado usando
la palabra clave
.B proxy
en
.B dhcp-range.
.TP
.B \-X, --dhcp-lease-max=<número> .B \-X, --dhcp-lease-max=<número>
Limita a dnsmasq a el número especificado de arriendos DHCP. El Limita a dnsmasq a el número especificado de arriendos DHCP. El
predeterminado es 150. El limite es para prevenir ataques DoS desde predeterminado es 150. El limite es para prevenir ataques DoS desde
@@ -731,11 +855,14 @@ es usado para el servidor y el n
para el cliente. Finalmente, dos números permiten que se especifiquen para el cliente. Finalmente, dos números permiten que se especifiquen
ambos los puertos de servidor y cliente para DHCP. ambos los puertos de servidor y cliente para DHCP.
.TP .TP
.B \-3, --bootp-dynamic .B \-3, --bootp-dynamic[=<network-id>[,<network-id>]]
Habilitar alocación dinámica de direcciones IP a clientes BOOTP. Usar Habilitar alocación dinámica de direcciones IP a clientes BOOTP. Usar
esto con cuidado, ya que cada dirección alocada a un cliente BOOTP esto con cuidado, ya que cada dirección alocada a un cliente BOOTP
es arrendada para siempre, y consecuentemente queda no-disponible es arrendada para siempre, y consecuentemente queda no-disponible
para re-uso por otros hosts. para re-uso por otros hosts. Si esto es brindado sin etiquetas,
entonces incondicionalmente habilita alocación dinámica. Con
etiquetas, solo cuando todas las etiquetas están fijadas. Puede
ser repetido con diferentes juegos de etiquetas.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
Por predetermindado, el servidor DHCP tratará de asegurarse que una Por predetermindado, el servidor DHCP tratará de asegurarse que una
@@ -751,34 +878,31 @@ clientes DHCP y las etiquetas netid usadas para determinarlos.
.TP .TP
.B \-l, --dhcp-leasefile=<path> .B \-l, --dhcp-leasefile=<path>
Usar el archivo especificado para almacenar información de arriendos Usar el archivo especificado para almacenar información de arriendos
DHCP. Si esta opción es brindada, pero ninguna opcion dhcp-range es DHCP.
brindada, entonces se activa comportamiento tipo dnsmasq versión 1.
El archivo brindado se asume es un archivo de arriendos dhcpd ISC y
es analizado en busca de arriendos los cuales son agregados al sistema
DNS si tienen un nombre de host. Esta funcionalidad pudo haber sido
excluida de dnsmasq a la hora de compilación, y en tal caso ocurrirá
un error. Nótese que la integración de archivos de
arriendo ISC es una caracterísctica depreciada. No debería ser usada
en instalaciones nuevas, y será eliminada en una versión futura.
.TP .TP
.B \-6 --dhcp-script=<path> .B \-6 --dhcp-script=<path>
Cuando un arriendo DHCP nuevo es creado, o uno viejo es Cuando un arriendo DHCP nuevo es creado, o uno viejo es
destruido, el binario especificado por esta opción es ejecutado. destruido, el ejecutable especificado por esta opción es ejecutado.
Los argumentos para el binario son "add", "old", o "del", la dirección Los argumentos para el binario son "add", "old", o "del", la dirección
MAC del host (o "<null>"), la dirección IP, y el hostname, si es MAC del host, la dirección IP, y el hostname, si es
conocido. "add" significa que un arriendo ha sido creado, "del" que conocido. "add" significa que un arriendo ha sido creado, "del" que
ha sido destruido, y "old" es una notificación de un arriendo existente ha sido destruido, y "old" es una notificación de un arriendo existente
cuando dnsmasq inicia o un cambio a una MAC o nombre host de un arriendo cuando dnsmasq inicia o un cambio a una MAC o nombre host de un arriendo
existente (también, tiempo de arriendo o vencimiento y client-id, si existente (también, tiempo de arriendo o vencimiento y client-id, si
leasefile-ro está fijado). El proceso es ejecutado como root (asumiendo leasefile-ro está fijado). Si la dirección MAC es de un tipo de red
que dnsmasq fue originalmente ejecutado como root) aún si dnsmasq está que no es ethernet, tendrá el tipo de red precolocado, por ejemplo
configurado para cambiar su UID a un usuario sin privilegios. "06-01:23:45:67:89:ab" para token ring. El proceso es ejecutado como root
(asumiendo que dnsmasq fue originalmente ejecutado como root) aún si dnsmasq
está configurado para cambiar su UID a un usuario sin privilegios.
El ambiente es heredado del usuario que ha invocado a dnsmasq, y si el El ambiente es heredado del usuario que ha invocado a dnsmasq, y si el
host brindó un client-id, es almacenado en la variable de ambiente host brindó un client-id, es almacenado en la variable de ambiente
DNSMASQ_CLIENT_ID. Si el cliente brinda información de clase de vendedor DNSMASQ_CLIENT_ID. Si el dominio completamente calificado del host
o usuario, estos son brindados en las variables DNSMASQ_VENDOR_CLASS y es conocido, la parte de dominio es almacenada en DNSMASQ_DOMAIN. Si
el cliente brinda información de clase de vendedor, nombre de host,
o clase de usuario, estos son brindados en las variables
DNSMASQ_VENDOR_CLASS, DNSMASQ_SUPPLIED_HOSTNAME, y
DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn, pero solo para acciones "add" DNSMASQ_USER_CLASS0..DNSMASQ_USER_CLASSn, pero solo para acciones "add"
y "old" cuando un host resume un arriendo existente, dado a que estos y "old" cuando un host reanuda un arriendo existente, dado a que estos
datos no son almacenados en la base de datos de arriendos de dnsmasq. datos no son almacenados en la base de datos de arriendos de dnsmasq.
Si dnsmasq fue compilado con HAVE_BROKEN_RTC, entonces la duración del Si dnsmasq fue compilado con HAVE_BROKEN_RTC, entonces la duración del
arriendo (en segundos) es almacenada en DNSMASQ_LEASE_LENGTH, de otra arriendo (en segundos) es almacenada en DNSMASQ_LEASE_LENGTH, de otra
@@ -790,7 +914,10 @@ evento "old" es generado con el nuevo estado del arriendo, (por ejemplo, sin
nombre), y el nombre anterior es brindado en la variable de ambiente nombre), y el nombre anterior es brindado en la variable de ambiente
DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE almacena el nombre de la interface DNSMASQ_OLD_HOSTNAME. DNSMASQ_INTERFACE almacena el nombre de la interface
en la cual llegó el pedido; esto no es fijado para acciones "viejas" en la cual llegó el pedido; esto no es fijado para acciones "viejas"
cuando dnsmasq re-inicia. cuando dnsmasq re-inicia. DNSMASQ_RELAY_ADDRESS es fijado si el cliente
usó un relay DHCP para contactar a dnsmasq y la dirección IP del relay
es conocida. DNSMASQ_TAGS contiene todas las etiquetas network-id fijadas
durante la transacción DHCP, separadas por espacios.
Todos los descriptores de archivo están cerrados Todos los descriptores de archivo están cerrados
excepto stdin, stdout, y stderr los cuales están abiertos a /dev/null excepto stdin, stdout, y stderr los cuales están abiertos a /dev/null
(excepto en modo debug). (excepto en modo debug).
@@ -824,16 +951,16 @@ cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
.TP .TP
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>] .B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias> Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
como si hubieran llegado a la interface <nombre de interface>. Esta opción solo como si hubieran llegado a la interface <nombre de interface>. Esta opción
está disponible en plataformas BSD, y es necesaria cuando se usan es necesaria al usar bridging estilo viejo en plataformas BSD, dado a que
puentes "estilo viejo", ya que los paquetes llegan a interfaces tap que no los paquetes llegan a interfaces tap que no tienen una dirección IP.
tienen una dirección IP.
.TP .TP
.B \-s, --domain=<dominio> .B \-s, --domain=<dominio>[,<rango de IPs>]
Especifica el dominio para el servidor DHCP. Esto tiene dos efectos: Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser
Primeramente, causa que el servidor DHCP le devuelva el dominio a brindados incondicionalmente (sin el rango de IPs) o para rangos limitados. Esto
cualquier host que lo pida. Segundamente, fija el dominio para el cual tiene dos efectos: Primeramente, causa que el servidor DHCP le devuelva el
es legal para hosts configurados mediante DHCP reclamar. La intención es dominio a cualquier host que lo pida. Segundamente, fija el dominio para el
cual es legal para hosts configurados mediante DHCP reclamar. La intención es
restringir nombres de host para que un host no-confiado en la LAN no restringir nombres de host para que un host no-confiado en la LAN no
pueda proclamar su nombre vía DHCP, como por ejemplo "microsoft.com" y pueda proclamar su nombre vía DHCP, como por ejemplo "microsoft.com" y
capturar tráfico no destinado a ella. Si ningún sufijo de dominio es capturar tráfico no destinado a ella. Si ningún sufijo de dominio es
@@ -850,7 +977,28 @@ de esa m
.B dnsmasq .B dnsmasq
como "laptop" y "laptop.thekelleys.org.uk". Si el dominio es brindado como "laptop" y "laptop.thekelleys.org.uk". Si el dominio es brindado
como "#" entonces el dominio es leido desde la primera directiva search como "#" entonces el dominio es leido desde la primera directiva search
en /etc/resolv.conf (o equivalente). en /etc/resolv.conf (o equivalente). El rango de direcciones puede ser
<dirección IP>,<dirección IP> or <dirección IP>/<máscara de subred>. Ver
.B --dhcp-fqdn el cual puede cambiar el comportamiento de dnsmasq con
dominios.
.TP
.B --dhcp-fqdn
En el modo predeterminado, dnsmasq pone los nombres no-calificados
de clientes DHCP en el DNS. Por esta razón, los nombres deben ser únicos,
aún si dos clientes que tienen el mismo nombre están en dominios
diferentes. Si un segundo cliente DHCP aparece el cual tiene el mismo
nombre que un cliente existente, el nombre es transferido al cliente nuevo. Si
.B --dhcp-fqdn
está fijado, este comportamiento cambia: El nombre no-calificado
no es puesto en el DNS, solo el nombre calificado. Dos clientes DHCP con
el mismo nombre pueden ambos quedarse con el nombre, con tal que la parte
de dominio sea diferente (o sea que los nombres completamente calificados
difieran). Para asegurar que todos los nombres tengan una parte de dominio,
debe haber al menos
.B --domain
sin una dirección especificada cuando
.B --dhcp-fqdn
está fijado.
.TP .TP
.B --enable-tftp .B --enable-tftp
Habilitar la función de servidor TFTP. Esto está deliberadamente limitado Habilitar la función de servidor TFTP. Esto está deliberadamente limitado
@@ -915,11 +1063,13 @@ Especificar un archivo de configuraci
también es permitida en archivos de configuración, para incluir múltiples también es permitida en archivos de configuración, para incluir múltiples
archivos de configuración. archivos de configuración.
.TP .TP
.B \-7, --conf-dir=<directorio> .B \-7, --conf-dir=<directorio>[,<file-extension>......]
Leer todos los archivos dentro del directorio brindado como archivos Leer todos los archivos dentro del directorio brindado como archivos
de configuración. Archivos cuyos nombres terminen con ~ o comienzen de configuración. Si extensiones son brindadas, cualquier archivo que
con . o comienzen y terminen con # son ignorados. Esta opción puede termine en esas extensiones son ignorados. Cualquier archivos cuyos nombres
ser brindada en la línea de comandos o en un archivo de configuración. terminen con ~ o comienzen con . o comienzen y terminen con # siempre son
ignorados. Esta opción puede ser brindada en la línea de comandos o en un
archivo de configuración.
.SH ARCHIVO DE CONFIGURACION .SH ARCHIVO DE CONFIGURACION
Al inicio, dnsmasq lee Al inicio, dnsmasq lee
.I /etc/dnsmasq.conf, .I /etc/dnsmasq.conf,
@@ -1056,9 +1206,11 @@ una del
.B dhcp-range .B dhcp-range
usado para alocar la dirección, una de cualquier usado para alocar la dirección, una de cualquier
.B dhcp-host .B dhcp-host
que coincida, y posiblemente muchas de clases de vendedor y usuario que coincida (y "known" si un dhcp-host coincide), la etiqueta "bootp"
que coinicdan que hayan sido enviadas por el cliente DHCP. para pedidos BOOTP, una etiqueta cuyo nombre es el nombre de la
Cualquier opción interface donde llegó el pedido, y posiblemente muchas de clases
de vendedor y usuario que coincidan que hayan sido enviadas por
el cliente DHCP. Cualquier opción
.B dhcp-option .B dhcp-option
que tenga etiquetas network-id será usada en preferencia de una opción que tenga etiquetas network-id será usada en preferencia de una opción
.B dhcp-option, .B dhcp-option,
@@ -1158,6 +1310,23 @@ o en un archivo hosts adicional. La lista puede ser muy larga. Dnsmasq ha sido
probado exitósamente con un millón de nombres. Ese tamaño de archivo necesita probado exitósamente con un millón de nombres. Ese tamaño de archivo necesita
un CPU de 1GHz y aproximadamente 60MB de RAM. un CPU de 1GHz y aproximadamente 60MB de RAM.
.SH INTERNACIONALIZACION
Dnsmasq puede ser compilado con soporte para internacionalización. Para hacer esto,
los targets make "all-i18n" y "install-i18n" deberán ser usados en vez de
los targets estándares "all" y "install". Cuando internacionalización es
compilada, dnsmasq producirá mensajes de bitácora en el lenguaje local y soportará
dominios internacionalizados (IDN). Nombres de dominio en /etc/hosts, /etc/ethers,
y /etc/dnsmasq.conf que contienen carácteres no-ASCII serán traducidos a
representación interna DNS punycode. Nótese que dnsmasq determina ambos el
lenguaje para mensajes y el juego de carácteres asumido para archivos de configuración
de la variable ambiental LANG. Esto debe estar fijado al valor predeterminado del sistema
por el guión responsable de iniciar dnsmasq. Al editar archivos de configuración,
tener cuidado de hacerlo usando solo el locale predeterminado del sistema y no
uno especifico del usuario, dado a que dnsmasq no tiene ninguna manera directa de
determinar el juego de caracteres en uso, y debe asumir que es el predeterminado
del sistema.
.SH ARCHIVOS .SH ARCHIVOS
.IR /etc/dnsmasq.conf .IR /etc/dnsmasq.conf
+260 -74
View File
@@ -16,9 +16,8 @@ fichier /etc/hosts afin que les noms locaux n'apparaissant pas dans les DNS
globaux soient tout de même résolus, et assure également la résolution de nom globaux soient tout de même résolus, et assure également la résolution de nom
pour les hôtes présents dans le service DHCP. pour les hôtes présents dans le service DHCP.
.PP .PP
Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques, les Le serveur DHCP Dnsmasq DHCP supporte les définitions d'adresses statiques et les
réseaux multiples, le relai DHCP et les spécifications de sous-réseaux conformes réseaux multiples. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
à la RFC3011. Il envoie par défaut un jeu raisonnable de paramètres DHCP, et
peut être configuré pour envoyer n'importe quel option DHCP. peut être configuré pour envoyer n'importe quel option DHCP.
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP. le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
@@ -33,6 +32,11 @@ Sur BSD, à moins que le logiciel ne soit compilé avec la bibliothèque GNU
getopt, la forme longue des options ne fonctionne pas en ligne de commande; Elle getopt, la forme longue des options ne fonctionne pas en ligne de commande; Elle
est toujours supportée dans le fichier de configuration. est toujours supportée dans le fichier de configuration.
.TP .TP
.B --test
Vérifie la syntaxe du ou des fichiers de configurations. Se termine avec le
code de retour 0 si tout est OK, ou un code différent de 0 dans le cas
contraire. Ne démarre pas Dnsmasq.
.TP
.B \-h, --no-hosts .B \-h, --no-hosts
Ne pas charger les noms du fichier /etc/hosts. Ne pas charger les noms du fichier /etc/hosts.
.TP .TP
@@ -41,12 +45,14 @@ Fichiers d'hôtes additionnels. Lire le fichier spécifié en plus de /etc/hosts
Si Si
.B -h .B -h
est spécifié, lire uniquement le fichier spécifié. Cette option peut être est spécifié, lire uniquement le fichier spécifié. Cette option peut être
répétée afin d'ajouter d'autres fichiers. répétée afin d'ajouter d'autres fichiers. Si un répertoire est donné, lis les
fichiers contenus dans ce répertoire.
.TP .TP
.B \-E, --expand-hosts .B \-E, --expand-hosts
Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le Ajoute le nom de domaine aux noms simples (ne contenant pas de point dans le
nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service nom) contenus dans le fichier /etc/hosts, de la même façon que pour le service
DHCP. DHCP. Notez que cela ne s'applique pas au nom de domaine dans les CNAME, les
enregistrements PTR, TXT, etc...
.TP .TP
.B \-T, --local-ttl=<durée> .B \-T, --local-ttl=<durée>
Lorsque Dnsmasq répond avec une information provenant du fichier /etc/hosts ou Lorsque Dnsmasq répond avec une information provenant du fichier /etc/hosts ou
@@ -134,8 +140,7 @@ que le DHCP ou le TFTP.
.TP .TP
.B \-P, --edns-packet-max=<taille> .B \-P, --edns-packet-max=<taille>
Spécifie la taille maximum de paquet UDP EDNS.0 supporté par le relai DNS. Le Spécifie la taille maximum de paquet UDP EDNS.0 supporté par le relai DNS. Le
défaut est de 1280, qui est la valeur maximale défaut est de 4096, qui est la valeur recommandée dans la RFC5625.
recommandée pour ethernet dans la RFC2671.
.TP .TP
.B \-Q, --query-port=<numéro de port> .B \-Q, --query-port=<numéro de port>
Envoie et écoute les requêtes DNS sortantes depuis le port UDP spécifié par Envoie et écoute les requêtes DNS sortantes depuis le port UDP spécifié par
@@ -236,7 +241,7 @@ trouvées dans /etc/hosts ou dans le fichier de baux DHCP se voient retournées
une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises une réponse "pas de tel domaine" ("no such domain") au lieu d'être transmises
aux serveurs de nom amont ("upstream server"). aux serveurs de nom amont ("upstream server").
.TP .TP
.B \-V, --alias=<ancienne IP>,<nouvelle IP>[,<masque>] .B \-V, --alias=[<ancienne IP>]|[<IP de début>-<IP de fin>],<nouvelle IP>[,<masque>]
Modifie les adresses IPv4 retournées par les serveurs de nom amont; Modifie les adresses IPv4 retournées par les serveurs de nom amont;
<ancienne IP> est remplacée par <nouvelle IP>. Si le <masque> optionnel est <ancienne IP> est remplacée par <nouvelle IP>. Si le <masque> optionnel est
fourni, alors toute adresse correspondant à l'adresse <ancienne IP>/<masque> fourni, alors toute adresse correspondant à l'adresse <ancienne IP>/<masque>
@@ -244,7 +249,11 @@ sera réécrite. Ainsi par exemple
.B --alias=1.2.3.0,6.7.8.0,255.255.255.0 .B --alias=1.2.3.0,6.7.8.0,255.255.255.0
modifiera 1.2.3.56 en 6.7.8.56 et 1.2.3.67 en 6.7.8.67. modifiera 1.2.3.56 en 6.7.8.56 et 1.2.3.67 en 6.7.8.67.
Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent Cette fonctionnalité correspond à ce que les routeurs Cisco PIX appellent
"bidouillage DNS" ("DNS doctoring"). "bidouillage DNS" ("DNS doctoring"). Si l'ancienne IP est donnée sous la forme
d'une gamme d'adresses, alors seules les adresses dans cette gamme seront
réecrites, et non le sous-réseau dans son ensemble. Ainsi,
.B --alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
fait correspondre 192.168.0.10->192.168.0.40 à 10.0.0.10->10.0.0.40
.TP .TP
.B \-B, --bogus-nxdomain=<adresse IP> .B \-B, --bogus-nxdomain=<adresse IP>
Transforme les réponses contenant l'adresse IP fournie en réponses "pas de tel Transforme les réponses contenant l'adresse IP fournie en réponses "pas de tel
@@ -455,6 +464,14 @@ Définit un enregistrement DNS de type PTR.
.B --naptr-record=<nom>,<ordre>,<préférence>,<drapeaux>,<service>,<expr. régulière>[,<remplacement>] .B --naptr-record=<nom>,<ordre>,<préférence>,<drapeaux>,<service>,<expr. régulière>[,<remplacement>]
Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403. Retourne un enregistrement de type NAPTR, tel que spécifié dans le RFC3403.
.TP .TP
.B --cname=<cname>,<cible>
Retourne un enregistrement de type CNAME qui indique que <cname> est en
réalité <cible>. Il existe des contraintes significatives sur la valeur
de cible; il doit s'agir d'un nom DNS qui est connu de dnsmasq via /etc/hosts
(ou un fichier hôtes additionnel) ou via DHCP. Si une cible ne satisfait
pas ces critères, le CNAME est ignoré. Le CNAME doit être unique, mais
il est autorisé d'avoir plus d'un CNAME pointant vers la même cible.
.TP
.B --interface-name=<nom>,<interface> .B --interface-name=<nom>,<interface>
Définit un entregistrement DNS associant le nom avec l'adresse primaire sur Définit un entregistrement DNS associant le nom avec l'adresse primaire sur
l'interface donnée en argument. Cette option spécifie un enregistrement de type l'interface donnée en argument. Cette option spécifie un enregistrement de type
@@ -485,7 +502,7 @@ lorsqu'un serveur web a la résolution de nom activée pour l'enregistrement de
son journal des requêtes, ce qui peut générer un nombre important de requêtes son journal des requêtes, ce qui peut générer un nombre important de requêtes
simultanées. simultanées.
.TP .TP
.B \-F, --dhcp-range=[[net:]identifiant de réseau,]<adresse de début>,<adresse de fin>[[,<masque de réseau>],<broadcast>][,<durée de bail par défaut>] .B \-F, --dhcp-range=[[net:]identifiant de réseau,]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
<adresse de début> et <adresse de fin> et à partir des adresses définies <adresse de début> et <adresse de fin> et à partir des adresses définies
statiquement dans l'option statiquement dans l'option
@@ -493,7 +510,9 @@ statiquement dans l'option
Si une durée de bail est donnée, alors les baux seront donnés pour cette Si une durée de bail est donnée, alors les baux seront donnés pour cette
durée. La durée de bail est donnée en secondes, en minutes (exemple : 45m), durée. La durée de bail est donnée en secondes, en minutes (exemple : 45m),
en heures (exemple : 1h) ou être la chaine de caractère "infinite" pour une en heures (exemple : 1h) ou être la chaine de caractère "infinite" pour une
durée indéterminée. La valeur minimum pour un bail DHCP est de 2 minutes. durée indéterminée. Si aucune valeur n'est donnée, une durée de bail par défaut
de une heure est appliquée. La valeur minimum pour un bail DHCP est de 2
minutes.
Cette option peut être répétée, avec différentes adresses, Cette option peut être répétée, avec différentes adresses,
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
@@ -501,11 +520,8 @@ Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par
contre requis pour les réseaux pour lesquels le service DHCP se fait via un contre requis pour les réseaux pour lesquels le service DHCP se fait via un
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle. relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
Sur certains systèmes, Dnsmasq ne peut écouter que sur une interface lorsqu'il Il est toujours possible d'avoir plus d'une plage DHCP pour un même
utilise DHCP, et le nom de l'interface doit être spécifié par l'option sous-réseau.
.B interface.
Cette limitation affecte tous les systèmes OpenBSD avant la version 4.0. Il
est toujours possible d'avoir plus d'une plage DHCP pour un même sous-réseau.
L'identifiant de réseau optionnel est un label alphanumérique qui permet de L'identifiant de réseau optionnel est un label alphanumérique qui permet de
marquer ce réseau afin de fournir des options DHCP spécifiques à chaque réseau. marquer ce réseau afin de fournir des options DHCP spécifiques à chaque réseau.
@@ -516,10 +532,19 @@ label, il définit le label pour laquelle la règle s'applique. Un seul label pe
L'adresse de fin peut être remplacée par le mot-clef L'adresse de fin peut être remplacée par le mot-clef
.B static .B static
("statique") qui indique à Dnsmasq d'activer le service DHCP pour le réseau ("statique") qui indique à Dnsmasq d'activer le service DHCP pour le réseau
spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP. Seuls les spécifié, mais de ne pas activer l'allocation dynamique d'adresses IP : Seuls
hôtes possédant des adresses IP statiques fournies via les hôtes possédant des adresses IP statiques fournies via
.B dhcp-host .B dhcp-host
ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP. ou présentes dans le fichier /etc/ethers seront alors servis par le DHCP.
L'adresse de fin peut-être remplacée par le mot-clef
.B proxy
, auquel cas Dnsmasq fournira un service de DHCP proxy pour le sous-réseau
spécifié. (voir
.B pxe-prompt
et
.B pxe-service
pour plus de détails).
.TP .TP
.B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,net:<identifiant de réseau>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore] .B \-G, --dhcp-host=[<adresse matérielle>][,id:<identifiant client>|*][,net:<identifiant de réseau>][,<adresse IP>][,<nom d'hôte>][,<durée de bail>][,ignore]
Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine Spécifie les paramètres DHCP relatifs à un hôte. Cela permet à une machine
@@ -545,6 +570,7 @@ réfère à l'hôte d'identifiant 01:02:03:04. Il est également possible de
spécifier l'identifiant client sous la forme d'une chaîne de caractères, comme spécifier l'identifiant client sous la forme d'une chaîne de caractères, comme
ceci : ceci :
.B --dhcp-host=id:identifiantclientsousformedechaine,..... .B --dhcp-host=id:identifiantclientsousformedechaine,.....
L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser L'option spéciale id:* signifie : "ignorer tout identifiant client et n'utiliser
que l'adresse matérielle". Cela est utile lorsqu'un client présente un que l'adresse matérielle". Cela est utile lorsqu'un client présente un
identifiant client mais pas les autres. identifiant client mais pas les autres.
@@ -558,7 +584,9 @@ spécifiée par son adresse matérielle, son identifiant client ou son nom d'hô
Par exemple Par exemple
.B --dhcp-host=00:20:e0:3b:13:af,ignore .B --dhcp-host=00:20:e0:3b:13:af,ignore
Cela est utile lorsqu'un autre serveur DHCP sur le réseau doit être utilisé par Cela est utile lorsqu'un autre serveur DHCP sur le réseau doit être utilisé par
certaines machines. Le paramètre net:<identifiant réseau> permet de définir un certaines machines.
Le paramètre net:<identifiant réseau> permet de définir un
identifiant de réseau lorsque l'option dhcp-host est utilisée. Cela peut servir identifiant de réseau lorsque l'option dhcp-host est utilisée. Cela peut servir
à sélectionner des options DHCP juste pour cet hôte. Lorsqu'une machine coïncide à sélectionner des options DHCP juste pour cet hôte. Lorsqu'une machine coïncide
avec une directive dhcp-host (ou une impliquée par /etc/ethers), alors avec une directive dhcp-host (ou une impliquée par /etc/ethers), alors
@@ -573,12 +601,26 @@ avec des octets joker, ainsi par exemple
demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est à noter demande à Dnsmasq d'ignorer une gamme d'adresses matérielles. Il est à noter
que "*" doit-être précédé d'un caractère d'échappement ou mis entre guillemets que "*" doit-être précédé d'un caractère d'échappement ou mis entre guillemets
lorsque spécifié en option de ligne de commande, mais pas dans le fichier de lorsque spécifié en option de ligne de commande, mais pas dans le fichier de
configuration. Les adresses matérielles coïncident en principe avec n'importe configuration.
Les adresses matérielles coïncident en principe avec n'importe
quel type de réseau (ARP), mais il est possible de les limiter à un seul type quel type de réseau (ARP), mais il est possible de les limiter à un seul type
ARP en les précédant du type ARP (en Hexadécimal) et de "-". Ainsi ARP en les précédant du type ARP (en Hexadécimal) et de "-". Ainsi
.B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4 .B --dhcp-host=06-00:20:e0:3b:13:af,1.2.3.4
coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type coïncidera uniquement avec des adresses matérielles Token-Ring, puisque le type
ARP pour une adresse Token-Ring est 6. ARP pour une adresse Token-Ring est 6.
Un cas spécial correspond à l'inclusion d'une ou plusieurs adresses
matérielles, c-à-d :
.B --dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.2.
Cela permet à une adresse IP d'être associé à plusieurs adresses
matérielles, et donne à dnsmasq la permission d'abandonner un bail DHCP
attribué à l'une de ces adresses lorsqu'une autre adresse dans la liste
demande un bail. Ceci est une opération dangereuse qui ne fonctionnera
de manière fiable que si une adresse matérielle est active à un moment
donné et dnsmasq n'a aucun moyen de s'assurer de cela. Cela est utile,
par exemple, pour allouer une adresse IP stable à un laptop qui
aurait à la fois une connexion filaire et sans-fil.
.TP .TP
.B --dhcp-hostsfile=<fichier> .B --dhcp-hostsfile=<fichier>
Lis les informations d'hôtes DHCP dans le fichier spécifié. Le fichier contient Lis les informations d'hôtes DHCP dans le fichier spécifié. Le fichier contient
@@ -592,7 +634,11 @@ relu lorsque Dnsmasq reçoit un signal SIGHUP.
.B --dhcp-optsfile=<fichier> .B --dhcp-optsfile=<fichier>
Lis les informations relatives aux options DHCP dans le fichier spécifié. Lis les informations relatives aux options DHCP dans le fichier spécifié.
L'intérêt d'utiliser cette option est le même que pour --dhcp-hostsfile : le L'intérêt d'utiliser cette option est le même que pour --dhcp-hostsfile : le
fichier spécifié ser rechargé à la réception par dnsmasq d'un signal SIGHUP. fichier spécifié sera rechargé à la réception par dnsmasq d'un signal SIGHUP.
Notez qu'il est possible d'encoder l'information via
.B --dhcp-boot
en utilisant les noms optionnels bootfile-name, server-ip-address et
tftp-server. Ceci permet d'inclure ces options dans un fichier "dhcp-optsfile".DNSMASQ_SUPPLIED_HOSTNAME
.TP .TP
.B \-Z, --read-ethers .B \-Z, --read-ethers
Lis les informations d'hôtes DHCP dans le fichier /etc/ethers. Le format de Lis les informations d'hôtes DHCP dans le fichier /etc/ethers. Le format de
@@ -603,7 +649,7 @@ par Dnsmasq, ces lignes ont exactement le même effet que l'option
contenant les mêmes informations. /etc/ethers est relu à la réception d'un contenant les mêmes informations. /etc/ethers est relu à la réception d'un
signal SIGHUP par Dnsmasq. signal SIGHUP par Dnsmasq.
.TP .TP
.B \-O, --dhcp-option=[<identifiant_de_réseau>,[<identifiant_de_réseau>,]][vendor:[<classe_vendeur>],][<opt>|option:<nom d'option>],[<valeur>[,<valeur>]] .B \-O, --dhcp-option=[<identifiant_de_réseau>,[<identifiant_de_réseau>,]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe_vendeur>],][<option>|option:<nom d'option>],[<valeur>[,<valeur>]]
Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par Spécifie des options différentes ou supplémentaires pour des clients DHCP. Par
défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le défaut, Dnsmasq envoie un ensemble standard d'options aux clients DHCP : le
masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte masque de réseau et l'adresse de broadcast sont les mêmes que pour l'hôte
@@ -673,10 +719,26 @@ pour sélectionner les options encapsulées, de préférence à toute option env
par le client. Il est possible d'omettre complètement une classe de vendeur : par le client. Il est possible d'omettre complètement une classe de vendeur :
.B --dhcp-option=vendor:,1,0.0.0.0 .B --dhcp-option=vendor:,1,0.0.0.0
Dans ce cas l'option encapsulée est toujours envoyée. Dans ce cas l'option encapsulée est toujours envoyée.
Les options peuvent-être encapsulées au sein d'autres options :
par exemple
.B --dhcp-option=encap:175, 190, "iscsi-client0"
enverra l'option 175, au sein de laquelle se trouve l'option 190.
Plusieurs options encapsulées avec le même numéro d'option seront correctement
combinées au sein d'une seule option encapsulée. Il n'est pas possible de
spécifier encap: et vendor: au sein d'une même option dhcp.
La dernière variante pour les options encapsulées est "l'option de Vendeur
identifiant le vendeur" ("Vendor-Identifying Vendor Options") telle que
décrite dans le RFC3925. Celles-ci sont spécifiées comme suit :
.B --dhcp-option=vi-encap:2, 10, "text"
Le numéro dans la section vi-encap: est le numéro IANA de l'entreprise servant
à identifier cette option.
L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans L'adresse 0.0.0.0 n'est pas traitée de manière particulière lorsque fournie dans
une option encapsulée de classe de vendeur. une option encapsulée.
.TP .TP
.B --dhcp-option-force=[<identifiant de réseau>,[<identifiant de réseau>,]][vendor:[<classe de vendeur>],]<opt>,[<valeur>[,<valeur>]] .B --dhcp-option-force=[<identifiant de réseau>,[<identifiant de réseau>,]][encap:<option>,][vi-encap:<entreprise>,][vendor:[<classe de vendeur>],]<option>,[<valeur>[,<valeur>]]
Cela fonctionne exactement de la même façon que Cela fonctionne exactement de la même façon que
.B --dhcp-option .B --dhcp-option
sauf que cette option sera toujours envoyée, même si le client ne la demande pas sauf que cette option sera toujours envoyée, même si le client ne la demande pas
@@ -738,11 +800,28 @@ relais DHCP, alors l'identifiant de réseau est positionné.
Associe des options de relais DHCP issues de la RFC3993 à des identifiants de Associe des options de relais DHCP issues de la RFC3993 à des identifiants de
réseau. réseau.
.TP .TP
.B --dhcp-match=<identifiant de réseau>,<numéro d'option> .B --dhcp-match=<identifiant de réseau>,<numéro d'option>|option:<nom d'option>|vi-encap:<entreprise>[,<valeur>]
Associe l'identifiant de réseau si le client envoie une option DHCP Si aucune valeur n'est spécifiée, associe l'identifiant de réseau si le client
avec le numéro spécifié. Cela peut-être utilisé pour identifier des envoie une option DHCP avec le numéro ou le nom spécifié. Lorsqu'une valeur est
clients spécifiques qui envoient des informations par le biais de fournie, positionne le label seulement dans le cas où l'option est fournie et
numéros privés d'option. correspond à la valeur. La valeur peut-être de la forme "01:ff:*:02", auquel
cas le début de l'option doit correspondre (en respectant les jokers). La
valeur peut aussi être de la même forme que dans
.B dhcp-option
, auquel cas l'option est traitée comme un tableau de valeur, et un des
éléments doit correspondre, ainsi
--dhcp-match=efi-ia32,option:client-arch,6
spécifie le label "efi-ia32" si le numéro 6 apparaît dnas la liste
d'architectures envoyé par le client au sein de l'option 93. (se réferer
au RFC 4578 pour plus de détails). Si la valeur est un chaine de caractères,
celle-ci est recherchée (correspondance en temps que sous-chaîne).
Pour la forme particulière vi-encap:<numéro d'entreprise>, la comparaison se
fait avec les classes de vendeur "identifiant de vendeur" ("vendor-identifying
vendor classes") pour l'entreprise dont le numéro est fourni en option.
Veuillez vous réferer à la RFC 3925 pour plus de détail.
.TP .TP
.B \-J, --dhcp-ignore=<identifiant de réseau>[,<identifiant de réseau>] .B \-J, --dhcp-ignore=<identifiant de réseau>[,<identifiant de réseau>]
Lorsque tous les identifiants de réseau fournis coïncident avec la liste Lorsque tous les identifiants de réseau fournis coïncident avec la liste
@@ -778,7 +857,61 @@ le réseau.
Si d'éventuels identifiants de réseau sont fournis, ils doivent coïncider avec Si d'éventuels identifiants de réseau sont fournis, ils doivent coïncider avec
ceux du client pour que cet élement de configuration lui soit envoyé. Il est à ceux du client pour que cet élement de configuration lui soit envoyé. Il est à
noter que les identifiants de réseau doivent-être préfixés par "net:". noter que les identifiants de réseau doivent-être préfixés par "net:".
.TP .TP
.B --pxe-service=[net:<identifiant de réseau>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
obtention d'une adresse IP, le téléchargement du fichier spécifié dans
.B dhcp-boot
et son exécution. Cependant, le système PXE est capable de fonctions bien plus
complexes pour peu que le serveur DHCP soit adapté.
Ceci spécifie l'option de démarrage qui apparaitra dans un menu de démarrage
PXE. <CSA> est le type du système client. Seuls des types de services valides
apparaitront dans un menu. Les types connus sont x86PC, PC98, IA64_EFI, Alpha,
Arc_x86, Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI et X86-64_EFI;
D'autres types peuvent-être spécifiés sous la forme d'une valeur entière. Le
paramètre après le texte correspondant à l'entrée dans le menu peut être un nom
de fichier, auquel cas Dnsmasq agit comme un serveur de démarrage et indique au
client PXE qu'il faut télécharger ce fichier via TFTP, soit depuis ce serveur
(l'option
.B enable-tftp
doit être spécifiée pour que cela marche), soit depuis un autre serveur TFTP
si une adresse de serveur est fournie.
Veuillez noter que le suffixe de "couche" (en principe ".0") est fourni par PXE
et ne doit pas être rajouté au nom de fichier. Si une valeur numérique entière
est fournir pour le type de démarrage, en remplacement du nom de fichier, le
client PXE devra chercher un service de démarrage de ce type sur le réseau.
Cette recherche peut être faite via broadcast ou directement auprès d'un
serveur si son adresse IP est fournie dans l'option.
Si aucun nom de fichier n'est donné ni aucune valeur de type de service de
démarrage n'est fournie (ou qu'une valeur de 0 est donnée pour le type de
service), alors l'entrée de menu provoque l'interruption du démarrage par
le réseau et la poursuite du démarrage sur un média local.
.TP
.B --pxe-prompt=[net:<identifiant de réseau>,]<invite>[,<délai>]
Cette option permet d'afficher une invite à la suite du démarrage PXE. Si un
délai est fourni, alors la première entrée du menu de démarrage sera
automatiquement exécutée après ce délai. Si le délai vaut 0, alors la première
entrée disponible sera exécutée immédiatement. Si
.B pxe-prompt
est omis, le système attendra un choix de l'utilisateur s'il existe plusieurs
entrées dans le menu, ou démarrera immédiatement dans le cas où il n'y a qu'une
seule entrée. Voir
.B pxe-service
pour plus de détails sur les entrées de menu.
Dnsmasq peut servir de "proxy-DHCP" PXE, dans le cas où un autre serveur DHCP
sur le réseau est responsable de l'allocation des adresses IP, auquel cas
Dnsmasq se contente de fournir les informations données dans les options
.B pxe-prompt
et
.B pxe-service
pour permettre le démarrage par le réseau. Ce mode est activé en utilisant le
mot-clef
.B proxy
dans
.B dhcp-range.
.TP
.B \-X, --dhcp-lease-max=<nombre> .B \-X, --dhcp-lease-max=<nombre>
Limite Dnsmasq à un maximum de <nombre> baux DHCP. Le défaut est de 150. Cette Limite Dnsmasq à un maximum de <nombre> baux DHCP. Le défaut est de 150. Cette
limite permet d'éviter des attaques de déni de service ("DoS") par des hôtes limite permet d'éviter des attaques de déni de service ("DoS") par des hôtes
@@ -802,10 +935,14 @@ numéro est utilisé pour le port serveur et ce numéro plus 1 est utilisé pour
port client. Enfin, en fournissant deux numéros de ports, il est possible de port client. Enfin, en fournissant deux numéros de ports, il est possible de
spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP. spécifier arbitrairement 2 ports à la fois pour le serveur et pour le client DHCP.
.TP .TP
.B \-3, --bootp-dynamic .B \-3, --bootp-dynamic[=<identifiant de réseau>[,<identifiant de réseau>]]
Permet l'allocation dynamique d'adresses IP à des clients BOOTP. Utiliser cette Permet l'allocation dynamique d'adresses IP à des clients BOOTP. Utiliser cette
option avec précaution, une adresse allouée à un client BOOTP étant perpétuelle, option avec précaution, une adresse allouée à un client BOOTP étant perpétuelle,
et de fait n'est plus disponibles pour d'autres hôtes. et de fait n'est plus disponibles pour d'autres hôtes. Si aucun argument n'est
donné, alors cette option permet une allocation dynamique dans tous les cas. Si
des arguments sont spécifiés, alors l'allocation ne se fait que lorsque tous
les identifiants coïncident. Il est possible de répeter cette option avec
plusieurs jeux d'arguments.
.TP .TP
.B \-5, --no-ping .B \-5, --no-ping
Par défaut, le serveur DHCP tente de s'assurer qu'une adresse n'est pas utilisée Par défaut, le serveur DHCP tente de s'assurer qu'une adresse n'est pas utilisée
@@ -822,46 +959,47 @@ détermination de celles-ci.
.TP .TP
.B \-l, --dhcp-leasefile=<chemin de fichier> .B \-l, --dhcp-leasefile=<chemin de fichier>
Utilise le fichier dont le chemin est fourni pour stocker les informations de Utilise le fichier dont le chemin est fourni pour stocker les informations de
baux DHCP. Si cette option est fournie mais qu'aucune option de type dhcp-range baux DHCP.
n'est donnée, alors un comportement de type Dnsmasq version 1 est activé. Le
fichier fourni est supposé être un fichier de baux DHCP de type ISC DHCPD et est
parcouru à la recherche de baux contenant des noms d'hôtes. Les noms trouvés
sont rajoutés au DNS. Cette fonctionalité peut être exclue de Dnsmasq à la
compilation, auquel cas une erreur sera produite. Il est à noter que
l'intégration avec un fichier de baux au format ISC est une fonctionalité
obsolète. Elle ne devrait pas être utilisée dans les nouvelles installations et
sera retirée dans une future version.
.TP .TP
.B \-6 --dhcp-script=<chemin de fichier> .B \-6 --dhcp-script=<chemin de fichier>
Lorsqu'un bail DHCP est créé, ou qu'un ancien est supprimé, le fichier dont le Lorsqu'un bail DHCP est créé, ou qu'un ancien est supprimé, le fichier dont le
chemin est spécifié est exécuté. Les arguments fournis à celui-ci sont soit chemin est spécifié est exécuté. Les arguments fournis à celui-ci sont soit
"add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse "add" ("ajouter"), "old" ("ancien") ou "del" ("supprimer"), suivi de l'adresse
MAC de l'hôte (ou "<null>") puis l'adresse IP et le nom d'hôte si celui-ci est MAC de l'hôte puis l'adresse IP et le nom d'hôte si celui-ci est
connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a été supprimé, connu."add" signifie qu'un bail a été créé, "del" signifie qu'il a été supprimé,
"old" notifie que le bail existait au lancement de Dnsmasq, ou un changement "old" notifie que le bail existait au lancement de Dnsmasq, ou un changement
d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas où d'adresse MAC ou de nom d'hôte pour un bail existant (ou, dans le cas où
leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant leasefile-ro est spécifié, un changement de durée de bail ou d'identifiant
d'hôte). Le processus est exécuté en temps que super-utilisateur (si Dnsmasq a d'hôte). Si l'adresse Mac est d'un type de réseau autre qu'ethernet, il est
été lancé en temps que "root"), même si Dnsmasq est configuré pour changer son nécessaire de la préceder du type de réseau, par exemple "06-01:23:45:67:89:ab"
UID pour celle d'un utilisateur non-privilégié. L'environnement est hérité de pour du token ring. Le processus est exécuté en temps que super-utilisateur
celui de l'invocation du processus Dnsmasq, et si l'hôte fournit un identifiant (si Dnsmasq a été lancé en temps que "root"), même si Dnsmasq est configuré
de client, celui-ci est stocké dans la variable d'environnement pour changer son UID pour celle d'un utilisateur non-privilégié.
DNSMASQ_CLIENT_ID. Si le client fournit une information de classe de vendeur ou L'environnement est hérité de celui de l'invocation du processus Dnsmasq, et
de classe d'utilisateur, celles-ci sont positionnées dans les variables si l'hôte fournit un identifiant de client, celui-ci est stocké dans la
DNSMASQ_VENDOR_CLASS et DNSMASQ_USER_CLASS0 à DNSMASQ_USER_CLASSn variable d'environnement DNSMASQ_CLIENT_ID. Si un nom de domaine pleinement
respectivement, mais seulement pour les actions "add" et "old" lorsqu'un hôte qualifié (FQDN) est connu pour l'hôte, la part relative au domaine est stockée
reprend un bail existant, ces variables n'étant pas stockées dans la base de dans DNSMASQ_DOMAIN. Si le client fournit une information de classe de vendeur,
baux de Dnsmasq. Si Dnsmasq a été compilé avec l'option HAVE_BROKEN_RTC de classe d'utilisateur ou un nom d'hôte, celles-ci sont positionnées dans les
("horloge RTC défectueuse"), alors la durée du bail (en secondes) est stockée variables DNSMASQ_VENDOR_CLASS et DNSMASQ_USER_CLASS0 à DNSMASQ_USER_CLASSn
dans la variable DNSMASQ_LEASE_LENGTH, sinon la date d'expiration du bail est et DNSMASQ_SUPPLIED_HOSTNAME respectivement, mais seulement pour les actions
toujours stocké dans la variable d'environnement DNSMASQ_LEASE_EXPIRES. Le "add" et "old" lorsqu'un hôte reprend un bail existant, ces variables n'étant
nombre de secondes avant expiration est toujours stocké dans pas stockées dans la base de baux de Dnsmasq. Si Dnsmasq a été compilé avec
DNSMASQ_TIME_REMAINING. Si un bail était associé à un nom d'hôte et que celui-ci l'option HAVE_BROKEN_RTC ("horloge RTC défectueuse"), alors la durée du bail
est supprimé, un évênement de type "old" est généré avec le nouveau statut du (en secondes) est stockée dans la variable DNSMASQ_LEASE_LENGTH, sinon la date
bail, c-à-d sans nom d'hôte, et le nom initial est fourni dans la variable d'expiration du bail est toujours stocké dans la variable d'environnement
d'environnement DNSMASQ_OLD_HOSTNAME. La variable DNSMASQ_INTERFACE contient le nom de DNSMASQ_LEASE_EXPIRES. Le nombre de secondes avant expiration est toujours
l'interface sur laquelle la requête est arrivée; ceci n'est pas renseigné stocké dans DNSMASQ_TIME_REMAINING. Si un bail était associé à un nom d'hôte et
dans le cas des actions "old" ayant lieu après un redémarrage de dnsmasq. que celui-ci est supprimé, un évênement de type "old" est généré avec le
nouveau statut du bail, c-à-d sans nom d'hôte, et le nom initial est fourni
dans la variable d'environnement DNSMASQ_OLD_HOSTNAME. La variable
DNSMASQ_INTERFACE contient le nom de l'interface sur laquelle la requête est
arrivée; ceci n'est pas renseigné dans le cas des actions "old" ayant lieu
après un redémarrage de dnsmasq. La variable DNSMASQ_RELAY_ADDRESS est
renseignée si le client a utilisé un relai DHCP pour contacter Dnsmasq, si
l'adresse IP du relai est connue. DNSMASQ_TAGS contient tous les labels
d'identifiants de réseau fournis pendant la transaction DHCP, séparés par des
espaces.
Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui Tous les descripteurs de fichiers sont fermés, sauf stdin, stdout et stderr qui
sont ouverts sur /dev/null (sauf en mode déverminage). sont ouverts sur /dev/null (sauf en mode déverminage).
Le script n'est pas lancé de manière concurrente : si un autre changement de Le script n'est pas lancé de manière concurrente : si un autre changement de
@@ -901,12 +1039,14 @@ longueur de bail ou de date d'expiration.
.B --bridge-interface=<interface>,<alias>[,<alias>] .B --bridge-interface=<interface>,<alias>[,<alias>]
Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias> Traiter les requêtes DHCP arrivant sur n'importe laquelle des interfaces <alias>
comme si elles arrivaient de l'interface <interface>. Cette option est comme si elles arrivaient de l'interface <interface>. Cette option est
uniquement disponible sur les plateformes BSD, et est uniquement nécessaire nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
lors de l'utilisation de pont ethernet "ancien mode", puisque dans ce cas les BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
paquets arrivent sur des interfaces "tap" n'ayant pas d'adresse IP. pas d'adresse IP.
.TP .TP
.B \-s, --domain=<domaine> .B \-s, --domain=<domaine>[,<gamme d'adresses>]
Spécifie le domaine du serveur DHCP. Cela a deux effets; tout d'abord, le Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
inconditionnelle (sans spécifier de gamme d'adresses IP) ou pour des gammes
d'adresses IP limitées. Cela a deux effets; tout d'abord, le
serveur DHCP retourne le domaine à tous les hôtes le demandant, deuxièmement, serveur DHCP retourne le domaine à tous les hôtes le demandant, deuxièmement,
cela spécifie le domaine valide pour les hôtes DHCP configurés. Le but de cela cela spécifie le domaine valide pour les hôtes DHCP configurés. Le but de cela
est de contraindre les noms d'hôte afin qu'aucun hôte sur le LAN ne puisse est de contraindre les noms d'hôte afin qu'aucun hôte sur le LAN ne puisse
@@ -925,7 +1065,29 @@ et avoir une machine dont le nom DHCP serait "laptop". L'adresse IP de cette
machine sera disponible à la fois pour "laptop" et "laptop.thekelleys.org.uk". machine sera disponible à la fois pour "laptop" et "laptop.thekelleys.org.uk".
Si la valeur fournie pour <domaine> est "#", alors le nom de domaine est Si la valeur fournie pour <domaine> est "#", alors le nom de domaine est
positionné à la première valeur de la directive "search" du fichier positionné à la première valeur de la directive "search" du fichier
/etc/resolv.conf (ou équivalent). /etc/resolv.conf (ou équivalent). La gamme d'adresses peut être de la forme
<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple
<adresse ip>. Voir
.B --dhcp-fqdn
qui peut changer le comportement de dnsmasq relatif aux domaines.
.TP
.B --dhcp-fqdn
Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
DHCP dans le DNS. Pour cette raison, les noms doivent être uniques, même si
deux clients ayant le même nom sont dans deux domaines différents. Si un
deuxième client DHCP apparaît ayant le même nom qu'un client déjà existant,
ce nom est transféré au nouveau client. Si
.B --dhcp-fqdn
est spécifié, ce comportement change : les noms non qualifiés ne sont plus
rajoutés dans le DNS, seuls les noms qualifiés le sont. Deux clients DHCP
avec le même nom peuvent tous les deux garder le nom, pour peu que la partie
relative au domaine soit différente (c-à-d que les noms pleinements qualifiés
diffèrent). Pour d'assurer que tous les noms ont une partie domaine, il doit-y
avoir au moins un
.B --domain
sans gamme d'adresses de spécifié lorsque l'option
.B --dhcp-fqdn
est configurée.
.TP .TP
.B --enable-tftp .B --enable-tftp
Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux Active la fonction serveur TFTP. Celui-ci est de manière délibérée limité aux
@@ -1013,10 +1175,12 @@ Spécifie un fichier de configuration différent. L'option "conf-file" est
également autorisée dans des fichiers de configuration, ce qui permet également autorisée dans des fichiers de configuration, ce qui permet
l'inclusion de multiples fichiers de configuration. l'inclusion de multiples fichiers de configuration.
.TP .TP
.B \-7, --conf-dir=<répertoire> .B \-7, --conf-dir=<répertoire>[,<extension de fichier>...]
Lis tous les fichiers du répertoire spécifié et les traite comme des fichiers de Lis tous les fichiers du répertoire spécifié et les traite comme des fichiers de
configuration. Les fichiers dont les noms se terminent en ~ ou commençant par ., configuration. Si des extensions sont données, tout fichier finissant par ces
ainsi que ceux commençant ou se terminant par # ne sont pas pris en compte. extensions seront ignorés. Tout fichier dont le nom se termine en ~ ou commence
par ., ainsi que ceux commençant ou se terminant par # seront systématiquement
ignorés.
Cette option peut être donnée en ligne de commande ou dans un fichier de Cette option peut être donnée en ligne de commande ou dans un fichier de
configuration. configuration.
.SH FICHIER DE CONFIGURATION .SH FICHIER DE CONFIGURATION
@@ -1164,9 +1328,12 @@ les identifiants de réseau fonctionnent comme suit : Dnsmasq associe à chaque
requête DHCP un ensemble d'identifiants de réseau; un pour la plage d'adresse requête DHCP un ensemble d'identifiants de réseau; un pour la plage d'adresse
DHCP ( DHCP (
.B dhcp-range .B dhcp-range
) utilisée pour allouer l'adresse, une pour chaque entrée ) utilisée pour allouer l'adresse, un identifiant pour chaque entrée
.B dhcp-host .B dhcp-host
associée et éventuellement une pour chaque classe de vendeur ou d'utilisateur associée (il ajoute "known" lorsqu'une entrée dhcp-host coïncide), l'étiquette
"bootp" pour les requêtes BOOTP, un identifiant dont le nom est le nom de
l'interface sur laquelle la requête est arrivée, et éventuellement un
identifiant pour chaque classe de vendeur ou d'utilisateur
fournie par le client DHCP dans sa requête. Les options DHCP ( fournie par le client DHCP dans sa requête. Les options DHCP (
.B dhcp-option .B dhcp-option
) ayant un identifiant de réseau seront utilisés de préférence à celles ) ayant un identifiant de réseau seront utilisés de préférence à celles
@@ -1269,6 +1436,25 @@ ou d'un fichier d'hôte additionnel. Cette liste peut-être très longue, Dnsmas
ayant été testé avec succès avec un million de noms. Cette taille de fichier ayant été testé avec succès avec un million de noms. Cette taille de fichier
nécessite un processeur à 1 Ghz et environ 60 Mo de RAM. nécessite un processeur à 1 Ghz et environ 60 Mo de RAM.
.SH INTERNATIONALISATION
Dnsmasq peut être compilé pour supporter l'internationalisation. Pour cela,
les cibles "all-i18n" et "install-i18n" doivent être données à make, en lieu
et place des cibles standards "all" et "install". Lorsque compilé avec le
support de l'internationalisation, dnsmasq supporte les noms de domaines
internationalisés ("internationalised domain names" ou IDN), et les messages de
traces ("logs") sont écrits dans la langue locale. Les noms de domaines dans
/etc/hosts, /etc/ethers et /etc/dnsmasq.conf contenant des caractères
non-ASCII seront transformés selon la représentation punycode interne
aux DNS. Veuillez noter que dnsmasq détermine la langue pour les messages
ainsi que le jeu de caractères susceptible d'être utilisé dans les fichiers
de configuration à partir de la variable d'environnement LANG. Ceci devrait
être configuré à la valeur par défaut du système par les scripts démarrant
dnsmasq. Lorsque les fichiers de configuration sont édités, veuillez faire
attention à le faire en utilisant la valeur de locale par défaut du système
et non une valeur spécifique à l'utilisateur, puisque dnsmasq n'a aucun
moyen de déterminer directement la valeur de jeu de caractère utilisé,
et assume de ce fait qu'il s'agit de la valeur par défaut du système.
.SH FICHIERS .SH FICHIERS
.IR /etc/dnsmasq.conf .IR /etc/dnsmasq.conf
+424 -374
View File
File diff suppressed because it is too large. Load diff
+473 -393
View File
File diff suppressed because it is too large. Load diff
+424 -374
View File
File diff suppressed because it is too large. Load diff
+565 -485
View File
File diff suppressed because it is too large. Load diff
+478 -402
View File
File diff suppressed because it is too large. Load diff
+424 -374
View File
File diff suppressed because it is too large. Load diff
+463 -390
View File
File diff suppressed because it is too large. Load diff
+461 -409
View File
File diff suppressed because it is too large. Load diff
+424 -374
View File
File diff suppressed because it is too large. Load diff
+462 -392
View File
File diff suppressed because it is too large. Load diff
+13 -9
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -63,16 +63,20 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
} }
} }
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len; ptr += len ) for (ptr = ifc.ifc_buf; ptr < (char *)(ifc.ifc_buf + ifc.ifc_len); ptr += len)
{ {
/* subsequent entries may not be aligned, so copy into /* subsequent entries may not be aligned, so copy into
an aligned buffer to avoid nasty complaints about an aligned buffer to avoid nasty complaints about
unaligned accesses. */ unaligned accesses. */
#ifdef HAVE_SOCKADDR_SA_LEN
len = ((struct ifreq *)ptr)->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#else
len = sizeof(struct ifreq); len = sizeof(struct ifreq);
#ifdef HAVE_SOCKADDR_SA_LEN
ifr = (struct ifreq *)ptr;
if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru))
len = ifr->ifr_addr.sa_len + offsetof(struct ifreq, ifr_ifru);
#endif #endif
if (!expand_buf(&ifreq, len)) if (!expand_buf(&ifreq, len))
goto err; goto err;
@@ -126,7 +130,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
#endif #endif
#if defined(HAVE_BSD_NETWORK) #if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
#include <net/bpf.h> #include <net/bpf.h>
void init_bpf(void) void init_bpf(void)
@@ -171,7 +175,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
/* Only know how to do ethernet on *BSD */ /* Only know how to do ethernet on *BSD */
if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN) if (mess->htype != ARPHRD_ETHER || mess->hlen != ETHER_ADDR_LEN)
{ {
my_syslog(LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"), my_syslog(MS_DHCP | LOG_WARNING, _("DHCP request for unsupported hardware type (%d) received on %s"),
mess->htype, ifr->ifr_name); mess->htype, ifr->ifr_name);
return; return;
} }
+338 -133
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,14 +10,17 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL; static struct crec *cache_head = NULL, *cache_tail = NULL, **hash_table = NULL;
static struct crec *dhcp_spare = NULL, *new_chain = NULL; #ifdef HAVE_DHCP
static struct crec *dhcp_spare = NULL;
#endif
static struct crec *new_chain = NULL;
static int cache_inserted = 0, cache_live_freed = 0, insert_error; 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;
@@ -223,7 +226,7 @@ char *cache_get_name(struct crec *crecp)
{ {
if (crecp->flags & F_BIGNAME) if (crecp->flags & F_BIGNAME)
return crecp->name.bname->name; return crecp->name.bname->name;
else if (crecp->flags & F_DHCP) else if (crecp->flags & (F_DHCP | F_CONFIG))
return crecp->name.namep; return crecp->name.namep;
return crecp->name.sname; return crecp->name.sname;
@@ -363,7 +366,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
log_query(flags | F_UPSTREAM, name, addr, NULL); log_query(flags | F_UPSTREAM, name, addr, NULL);
/* CONFIG bit no needed except for logging */ /* CONFIG bit means something else when stored in cache entries */
flags &= ~F_CONFIG; flags &= ~F_CONFIG;
/* if previous insertion failed give up now. */ /* if previous insertion failed give up now. */
@@ -642,153 +645,231 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
unsigned short flags, int index, int addr_dup) unsigned short flags, int index, int addr_dup)
{ {
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; int i, nameexists = 0;
struct cname *a;
/* Remove duplicates in hosts files. */ /* Remove duplicates in hosts files. */
if (lookup && (lookup->flags & F_HOSTS) && if (lookup && (lookup->flags & F_HOSTS))
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
free(cache);
else
{ {
/* Ensure there is only one address -> name mapping (first one trumps) nameexists = 1;
We do this by steam here, first we see if the address is the same as if (memcmp(&lookup->addr.addr, addr, addrlen) == 0)
the last one we saw, which eliminates most in the case of an ad-block {
file with thousands of entries for the same address. free(cache);
Then we search and bail at the first matching address that came from return;
a HOSTS file. Since the first host entry gets reverse, we know }
then that it must exist without searching exhaustively for it. */ }
if (addr_dup) /* Ensure there is only one address -> name mapping (first one trumps)
flags &= ~F_REVERSE; We do this by steam here, first we see if the address is the same as
else the last one we saw, which eliminates most in the case of an ad-block
for (i=0; i<hash_size; i++) file with thousands of entries for the same address.
{ Then we search and bail at the first matching address that came from
for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next) a HOSTS file. Since the first host entry gets reverse, we know
if ((lookup->flags & F_HOSTS) && then that it must exist without searching exhaustively for it. */
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0) if (addr_dup)
{ flags &= ~F_REVERSE;
flags &= ~F_REVERSE; else
break; for (i=0; i<hash_size; i++)
} {
if (lookup) for (lookup = hash_table[i]; lookup; lookup = lookup->hash_next)
if ((lookup->flags & F_HOSTS) &&
(lookup->flags & flags & (F_IPV4 | F_IPV6)) &&
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
{
flags &= ~F_REVERSE;
break; break;
} }
if (lookup)
break;
}
cache->flags = flags;
cache->uid = index;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache);
/* don't need to do alias stuff for second and subsequent addresses. */
if (!nameexists)
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(cache->name.sname, a->target) &&
(lookup = whine_malloc(sizeof(struct crec))))
{
lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
lookup->name.namep = a->alias;
lookup->addr.cname.cache = cache;
lookup->addr.cname.uid = index;
cache_hash(lookup);
}
}
static int eatspace(FILE *f)
{
int c, nl = 0;
while (1)
{
if ((c = getc(f)) == '#')
while (c != '\n' && c != EOF)
c = getc(f);
cache->flags = flags; if (c == EOF)
cache->uid = index; return 1;
memcpy(&cache->addr.addr, addr, addrlen);
cache_hash(cache); if (!isspace(c))
{
ungetc(c, f);
return nl;
}
if (c == '\n')
nl = 1;
}
}
static int gettok(FILE *f, char *token)
{
int c, count = 0;
while (1)
{
if ((c = getc(f)) == EOF)
return (count == 0) ? EOF : 1;
if (isspace(c) || c == '#')
{
ungetc(c, f);
return eatspace(f);
}
if (count < (MAXDNAME - 1))
{
token[count++] = c;
token[count] = 0;
}
} }
} }
static int read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index, int cache_size) static int read_hostsfile(char *filename, int index, int cache_size)
{ {
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "r");
char *line; 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, saved_flags = 0; unsigned short flags = 0, saved_flags = 0;
struct all_addr addr, saved_addr; struct all_addr addr, saved_addr;
int atnl, addrlen = 0, addr_dup;
if (!f) if (!f)
{ {
my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno)); my_syslog(LOG_ERR, _("failed to load names from %s: %s"), filename, strerror(errno));
return 0; return 0;
} }
while ((line = fgets(buff, MAXDNAME, f))) eatspace(f);
while ((atnl = gettok(f, token)) != EOF)
{ {
char *token = strtok(line, " \t\n\r"); addr_dup = 0;
int addrlen, addr_dup = 0;
lineno++; lineno++;
if (!token || (*token == '#'))
continue;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (inet_pton(AF_INET, token, &addr) > 0) if (inet_pton(AF_INET, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ; addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
} }
else if (inet_pton(AF_INET6, token, &addr) > 0) else if (inet_pton(AF_INET6, token, &addr) > 0)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ; addrlen = IN6ADDRSZ;
domain_suffix = daemon->domain_suffix;
} }
#else #else
if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1) if ((addr.addr.addr4.s_addr = inet_addr(token)) != (in_addr_t) -1)
{ {
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4; flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ; addrlen = INADDRSZ;
domain_suffix = get_domain(addr.addr.addr4);
} }
#endif #endif
else else
{ {
my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno);
while (atnl == 0)
atnl = gettok(f, token);
continue; continue;
} }
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while (atnl == 0)
{
struct crec *cache;
int fqdn, nomem;
char *canon;
if ((atnl = gettok(f, token)) == EOF)
break;
fqdn = !!strchr(token, '.');
if ((canon = canonicalise(token, &nomem)))
{
/* If set, add a version of the name with a default domain appended */
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, canon);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(canon)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, canon);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
free(canon);
}
else if (!nomem)
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
if (saved_flags == flags && memcmp(&addr, &saved_addr, addrlen) == 0)
addr_dup = 1;
else
{
saved_flags = flags;
saved_addr = addr;
}
addr_count++;
/* rehash every 1000 names. */
if ((name_count - cache_size) > 1000)
{
rehash(name_count);
cache_size = name_count;
}
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
{
struct crec *cache;
int fqdn = !!strchr(token, '.');
if (canonicalise(token))
{
/* If set, add a version of the name with a default domain appended */
if ((opts & OPT_EXPAND) && domain_suffix && !fqdn &&
(cache = whine_malloc(sizeof(struct crec) +
strlen(token)+2+strlen(domain_suffix)-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
strcat(cache->name.sname, ".");
strcat(cache->name.sname, domain_suffix);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
addr_dup = 1;
name_count++;
}
if ((cache = whine_malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
{
strcpy(cache->name.sname, token);
add_hosts_entry(cache, &addr, addrlen, flags, index, addr_dup);
name_count++;
}
}
else
my_syslog(LOG_ERR, _("bad name at %s line %d"), filename, lineno);
}
}
fclose(f); fclose(f);
rehash(name_count); rehash(name_count);
my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count); my_syslog(LOG_INFO, _("read %s - %d addresses"), filename, addr_count);
return name_count; return name_count;
} }
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts) 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;
cache_inserted = cache_live_freed = 0; cache_inserted = cache_live_freed = 0;
@@ -815,22 +896,125 @@ void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *a
up = &cache->hash_next; up = &cache->hash_next;
} }
if ((opts & OPT_NO_HOSTS) && !addn_hosts) if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
{ {
if (daemon->cachesize > 0) if (daemon->cachesize > 0)
my_syslog(LOG_INFO, _("cleared cache")); my_syslog(LOG_INFO, _("cleared cache"));
return; return;
} }
if (!(opts & OPT_NO_HOSTS)) if (!(daemon->options & OPT_NO_HOSTS))
total_size = read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0, total_size); total_size = read_hostsfile(HOSTSFILE, 0, total_size);
while (addn_hosts)
for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next)
{ {
total_size = read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index, total_size); if (i <= ah->index)
addn_hosts = addn_hosts->next; i = ah->index + 1;
}
if (ah->flags & AH_DIR)
ah->flags |= AH_INACTIVE;
else
ah->flags &= ~AH_INACTIVE;
}
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE))
{
struct stat buf;
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
{
DIR *dir_stream;
struct dirent *ent;
/* don't read this as a file */
ah->flags |= AH_INACTIVE;
if (!(dir_stream = opendir(ah->fname)))
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
ah->fname, strerror(errno));
else
{
while ((ent = readdir(dir_stream)))
{
size_t lendir = strlen(ah->fname);
size_t lenfile = strlen(ent->d_name);
struct hostsfile *ah1;
char *path;
/* ignore emacs backups and dotfiles */
if (lenfile == 0 ||
ent->d_name[lenfile - 1] == '~' ||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
ent->d_name[0] == '.')
continue;
/* see if we have an existing record.
dir is ah->fname
file is ent->d_name
path to match is ah1->fname */
for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next)
{
if (lendir < strlen(ah1->fname) &&
strstr(ah1->fname, ah->fname) == ah1->fname &&
ah1->fname[lendir] == '/' &&
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
{
ah1->flags &= ~AH_INACTIVE;
break;
}
}
/* make new record */
if (!ah1)
{
if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
continue;
if (!(path = whine_malloc(lendir + lenfile + 2)))
{
free(ah1);
continue;
}
strcpy(path, ah->fname);
strcat(path, "/");
strcat(path, ent->d_name);
ah1->fname = path;
ah1->index = i++;
ah1->flags = AH_DIR;
ah1->next = daemon->addn_hosts;
daemon->addn_hosts = ah1;
}
/* inactivate record if not regular file */
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
ah1->flags |= AH_INACTIVE;
}
closedir(dir_stream);
}
}
}
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (!(ah->flags & AH_INACTIVE))
total_size = read_hostsfile(ah->fname, ah->index, total_size);
} }
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
for (c = daemon->cond_domain; c; c = c->next)
if (ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return c->domain;
return daemon->domain_suffix;
}
#ifdef HAVE_DHCP
void cache_unhash_dhcp(void) void cache_unhash_dhcp(void)
{ {
struct crec *cache, **up; struct crec *cache, **up;
@@ -851,13 +1035,11 @@ void cache_unhash_dhcp(void)
void cache_add_dhcp_entry(char *host_name, void cache_add_dhcp_entry(char *host_name,
struct in_addr *host_address, time_t ttd) struct in_addr *host_address, time_t ttd)
{ {
struct crec *crec = NULL; struct crec *crec = NULL, *aliasc;
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE; unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
int in_hosts = 0; int in_hosts = 0;
struct cname *a;
if (!host_name)
return;
while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME))) while ((crec = cache_find_by_name(crec, host_name, 0, F_IPV4 | F_CNAME)))
{ {
/* check all addresses associated with name */ /* check all addresses associated with name */
@@ -870,7 +1052,7 @@ void cache_add_dhcp_entry(char *host_name,
_("not giving name %s to the DHCP lease of %s because " _("not giving name %s to the DHCP lease of %s because "
"the name exists in %s with address %s"), "the name exists in %s with address %s"),
host_name, inet_ntoa(*host_address), host_name, inet_ntoa(*host_address),
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff); record_source(crec->uid), daemon->namebuff);
return; return;
} }
else else
@@ -911,9 +1093,34 @@ void cache_add_dhcp_entry(char *host_name,
crec->ttd = ttd; crec->ttd = ttd;
crec->addr.addr.addr.addr4 = *host_address; crec->addr.addr.addr.addr4 = *host_address;
crec->name.namep = host_name; crec->name.namep = host_name;
crec->uid = uid++;
cache_hash(crec); cache_hash(crec);
for (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(host_name, a->target))
{
if ((aliasc = dhcp_spare))
dhcp_spare = dhcp_spare->next;
else /* need new one */
aliasc = whine_malloc(sizeof(struct crec));
if (aliasc)
{
aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
if (ttd == 0)
aliasc->flags |= F_IMMORTAL;
else
aliasc->ttd = ttd;
aliasc->name.namep = a->alias;
aliasc->addr.cname.cache = crec;
aliasc->addr.cname.uid = crec->uid;
cache_hash(aliasc);
}
}
} }
} }
#endif
void dump_cache(time_t now) void dump_cache(time_t now)
{ {
@@ -1003,20 +1210,18 @@ void dump_cache(time_t now)
} }
} }
char *record_source(struct hostsfile *addn_hosts, int index) char *record_source(int index)
{ {
char *source = HOSTSFILE; struct hostsfile *ah;
while (addn_hosts)
{
if (addn_hosts->index == index)
{
source = addn_hosts->fname;
break;
}
addn_hosts = addn_hosts->next;
}
return source; if (index == 0)
return HOSTSFILE;
for (ah = daemon->addn_hosts; ah; ah = ah->next)
if (ah->index == index)
return ah->fname;
return "<unknown>";
} }
void querystr(char *str, unsigned short type) void querystr(char *str, unsigned short type)
@@ -1083,12 +1288,12 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
dest = "<CNAME>"; dest = "<CNAME>";
} }
if (flags & F_DHCP) if (flags & F_CONFIG)
source = "config";
else if (flags & F_DHCP)
source = "DHCP"; source = "DHCP";
else if (flags & F_HOSTS) else if (flags & F_HOSTS)
source = arg; source = arg;
else if (flags & F_CONFIG)
source = "config";
else if (flags & F_UPSTREAM) else if (flags & F_UPSTREAM)
source = "reply"; source = "reply";
else if (flags & F_SERVER) else if (flags & F_SERVER)
+56 -68
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,21 +10,23 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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 VERSION "2.45" #define VERSION "2.52"
#define FTABSIZ 150 /* max number of outstanding requests (default) */ #define FTABSIZ 150 /* max number of outstanding requests (default) */
#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 1280 /* default max EDNS.0 UDP packet from RFC2671 */ #define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */ #define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 10 /* or 10 seconds */
#define RANDOM_SOCKS 64 /* max simultaneous random ports */ #define RANDOM_SOCKS 64 /* max simultaneous random ports */
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */ #define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
#define CACHESIZ 150 /* default cache size */ #define CACHESIZ 150 /* default cache size */
#define MAXLEASES 150 /* maximum number of DHCP leases */ #define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */ #define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */ #define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */ #define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
@@ -38,18 +40,25 @@
# define RESOLVFILE "/etc/resolv.conf" # define RESOLVFILE "/etc/resolv.conf"
#endif #endif
#define RUNFILE "/var/run/dnsmasq.pid" #define RUNFILE "/var/run/dnsmasq.pid"
#if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__)
# define LEASEFILE "/var/db/dnsmasq.leases" #ifndef LEASEFILE
#elif defined(__sun__) || defined (__sun) # if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
# define LEASEFILE "/var/cache/dnsmasq.leases" # define LEASEFILE "/var/db/dnsmasq.leases"
#else # elif defined(__sun__) || defined (__sun)
# define LEASEFILE "/var/lib/misc/dnsmasq.leases" # define LEASEFILE "/var/cache/dnsmasq.leases"
# else
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
# endif
#endif #endif
#if defined(__FreeBSD__)
# define CONFFILE "/usr/local/etc/dnsmasq.conf" #ifndef CONFFILE
#else # if defined(__FreeBSD__)
# define CONFFILE "/etc/dnsmasq.conf" # define CONFFILE "/usr/local/etc/dnsmasq.conf"
# else
# define CONFFILE "/etc/dnsmasq.conf"
# endif
#endif #endif
#define DEFLEASE 3600 /* default lease time, 1 hour */ #define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody" #define CHUSER "nobody"
#define CHGRP "dip" #define CHGRP "dip"
@@ -57,10 +66,12 @@
#define DHCP_CLIENT_PORT 68 #define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_ALTPORT 1067 #define DHCP_SERVER_ALTPORT 1067
#define DHCP_CLIENT_ALTPORT 1068 #define DHCP_CLIENT_ALTPORT 1068
#define PXE_PORT 4011
#define TFTP_PORT 69 #define TFTP_PORT 69
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */ #define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */ #define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom" #define RANDFILE "/dev/urandom"
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
/* DBUS interface specifics */ /* DBUS interface specifics */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
@@ -98,9 +109,6 @@ 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_SOLARIS_PRIVS
define for Solaris > 10 which can split privileges.
HAVE_BROKEN_RTC HAVE_BROKEN_RTC
define this on embedded systems which don't have an RTC define this on embedded systems which don't have an RTC
which keeps time over reboots. Causes dnsmasq to use uptime which keeps time over reboots. Causes dnsmasq to use uptime
@@ -115,13 +123,15 @@ HAVE_BROKEN_RTC
NOTE: when enabling or disabling this, be sure to delete any old NOTE: when enabling or disabling this, be sure to delete any old
leases file, otherwise dnsmasq may get very confused. leases file, otherwise dnsmasq may get very confused.
HAVE_ISC_READER
define this to include the old ISC dhcpcd integration. Note that you cannot
set both HAVE_ISC_READER and HAVE_BROKEN_RTC.
HAVE_TFTP HAVE_TFTP
define this to get dnsmasq's built-in TFTP server. 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. define this if you have GNU libc or GNU getopt.
@@ -137,14 +147,6 @@ HAVE_DBUS
define some methods to allow (re)configuration of the upstream DNS define some methods to allow (re)configuration of the upstream DNS
servers via DBus. servers via DBus.
HAVE_BSD_BRIDGE
Define this to enable the --bridge-interface option, useful on some
BSD systems.
HAVE_LARGFILE
Define this if the C library supports large (>2GB) files probably true everywhere
except some builds of uclibc
NOTES: NOTES:
For Linux you should define For Linux you should define
HAVE_LINUX_NETWORK HAVE_LINUX_NETWORK
@@ -164,20 +166,29 @@ NOTES:
*/ */
/* platform independent options- uncomment to enable */ /* platform independent options- uncomment to enable */
#define HAVE_DHCP
#define HAVE_TFTP #define HAVE_TFTP
#define HAVE_SCRIPT
/* #define HAVE_BROKEN_RTC */ /* #define HAVE_BROKEN_RTC */
/* #define HAVE_ISC_READER */
/* #define HAVE_DBUS */ /* #define HAVE_DBUS */
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */ /* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
#ifdef NO_TFTP #ifdef NO_TFTP
#undef HAVE_TFTP #undef HAVE_TFTP
#endif #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. */ /* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */ /* Must preceed __linux__ since uClinux defines __linux__ too. */
@@ -215,13 +226,6 @@ NOTES:
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN #undef HAVE_SOCKADDR_SA_LEN
/* glibc < 2.2 has broken Sockaddr_in6 so we have to use our own. */
/* glibc < 2.2 doesn't define in_addr_t */
#if defined(__GLIBC__) && (__GLIBC__ == 2) && \
defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ < 2)
typedef unsigned long in_addr_t;
# define HAVE_BROKEN_SOCKADDR_IN6
#endif
#elif defined(__FreeBSD__) || \ #elif defined(__FreeBSD__) || \
defined(__OpenBSD__) || \ defined(__OpenBSD__) || \
@@ -236,11 +240,10 @@ typedef unsigned long in_addr_t;
# define HAVE_ARC4RANDOM # define HAVE_ARC4RANDOM
#endif #endif
#define HAVE_SOCKADDR_SA_LEN #define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define HAVE_BSD_NETWORK #define HAVE_BSD_NETWORK
#undef HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM #define HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN #define HAVE_SOCKADDR_SA_LEN
/* Define before sys/socket.h is included so we get socklen_t */ /* Define before sys/socket.h is included so we get socklen_t */
@@ -251,34 +254,14 @@ typedef unsigned long in_addr_t;
#define HAVE_GETOPT_LONG #define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN #define HAVE_SOCKADDR_SA_LEN
#define HAVE_BSD_BRIDGE
#elif defined(__sun) || defined(__sun__) #elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK #define HAVE_SOLARIS_NETWORK
/* only Solaris 10 does split privs. */ #define HAVE_GETOPT_LONG
#if (SUNOS_VER >= 10)
# define HAVE_SOLARIS_PRIVS
# define HAVE_GETOPT_LONG
#endif
/* some CMSG stuff missing on early solaris */
#ifndef OSSH_ALIGNBYTES
# define OSSH_ALIGNBYTES (sizeof(int) - 1)
#endif
#ifndef __CMSG_ALIGN
# define __CMSG_ALIGN(p) (((u_int)(p) + OSSH_ALIGNBYTES) &~ OSSH_ALIGNBYTES)
#endif
#ifndef CMSG_LEN
# define CMSG_LEN(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
#endif
#ifndef CMSG_SPACE
# define CMSG_SPACE(len) (__CMSG_ALIGN(sizeof(struct cmsghdr)) + __CMSG_ALIGN(len))
#endif
#undef HAVE_ARC4RANDOM #undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN #undef HAVE_SOCKADDR_SA_LEN
#define ETHER_ADDR_LEN 6
#define _XPG4_2
#define __EXTENSIONS__
#define ETHER_ADDR_LEN 6
#endif #endif
/* Decide if we're going to support IPv6 */ /* Decide if we're going to support IPv6 */
@@ -302,3 +285,8 @@ typedef unsigned long in_addr_t;
# 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
# undef HAVE_SCRIPT
#endif
+97 -14
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,17 +10,52 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h> #include <dbus/dbus.h>
const char* introspection_xml =
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
"\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node name=\"" DNSMASQ_PATH "\">\n"
" <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
" <method name=\"Introspect\">\n"
" <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" </interface>\n"
" <interface name=\"" DNSMASQ_SERVICE "\">\n"
" <method name=\"ClearCache\">\n"
" </method>\n"
" <method name=\"GetVersion\">\n"
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" <method name=\"SetServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
" </method>\n"
" <signal name=\"DhcpLeaseAdded\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"DhcpLeaseDeleted\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" <signal name=\"DhcpLeaseUpdated\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
" </interface>\n"
"</node>\n";
struct watch { struct watch {
DBusWatch *watch; DBusWatch *watch;
struct watch *next; struct watch *next;
@@ -229,7 +264,15 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{ {
char *method = (char *)dbus_message_get_member(message); char *method = (char *)dbus_message_get_member(message);
if (strcmp(method, "GetVersion") == 0) if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection_xml, DBUS_TYPE_INVALID);
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
else if (strcmp(method, "GetVersion") == 0)
{ {
char *v = VERSION; char *v = VERSION;
DBusMessage *reply = dbus_message_new_method_return(message); DBusMessage *reply = dbus_message_new_method_return(message);
@@ -283,7 +326,10 @@ char *dbus_init(void)
daemon->dbus = connection; daemon->dbus = connection;
if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up"))) if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
dbus_connection_send(connection, message, NULL); {
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
return NULL; return NULL;
} }
@@ -298,11 +344,7 @@ void set_dbus_listeners(int *maxfdp,
if (dbus_watch_get_enabled(w->watch)) if (dbus_watch_get_enabled(w->watch))
{ {
unsigned int flags = dbus_watch_get_flags(w->watch); unsigned int flags = dbus_watch_get_flags(w->watch);
#if (DBUS_MINOR > 0)
int fd = dbus_watch_get_unix_fd(w->watch); int fd = dbus_watch_get_unix_fd(w->watch);
#else
int fd = dbus_watch_get_fd(w->watch);
#endif
bump_maxfd(fd, maxfdp); bump_maxfd(fd, maxfdp);
@@ -325,11 +367,7 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
if (dbus_watch_get_enabled(w->watch)) if (dbus_watch_get_enabled(w->watch))
{ {
unsigned int flags = 0; unsigned int flags = 0;
#if (DBUS_MINOR > 0)
int fd = dbus_watch_get_unix_fd(w->watch); int fd = dbus_watch_get_unix_fd(w->watch);
#else
int fd = dbus_watch_get_fd(w->watch);
#endif
if (FD_ISSET(fd, rset)) if (FD_ISSET(fd, rset))
flags |= DBUS_WATCH_READABLE; flags |= DBUS_WATCH_READABLE;
@@ -352,4 +390,49 @@ void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
} }
} }
#ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
DBusMessage* message = NULL;
DBusMessageIter args;
char *action_str, *addr, *mac = daemon->namebuff;
unsigned char *p;
int i;
if (!connection)
return;
if (!hostname)
hostname = "";
p = extended_hwaddr(lease->hwaddr_type, lease->hwaddr_len,
lease->hwaddr, lease->clid_len, lease->clid, &i);
print_mac(mac, p, i);
if (action == ACTION_DEL)
action_str = "DhcpLeaseDeleted";
else if (action == ACTION_ADD)
action_str = "DhcpLeaseAdded";
else if (action == ACTION_OLD)
action_str = "DhcpLeaseUpdated";
else
return;
addr = inet_ntoa(lease->addr);
if (!(message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, action_str)))
return;
dbus_message_iter_init_append(message, &args);
if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &addr) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &mac) &&
dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &hostname))
dbus_connection_send(connection, message, NULL);
dbus_message_unref(message);
}
#endif
#endif #endif
+187 -118
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,12 +10,14 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_DHCP
struct iface_param { struct iface_param {
struct in_addr relay, primary; struct in_addr relay, primary;
struct dhcp_context *current; struct dhcp_context *current;
@@ -25,7 +27,7 @@ struct iface_param {
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);
void dhcp_init(void) static int make_fd(int port)
{ {
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in saddr; struct sockaddr_in saddr;
@@ -35,7 +37,7 @@ void dhcp_init(void)
#endif #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)
@@ -43,7 +45,7 @@ void dhcp_init(void)
#endif #endif
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 || setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
#elif defined(IP_RECVIF) #else
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 || setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
#endif #endif
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1) setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
@@ -51,12 +53,7 @@ void dhcp_init(void)
/* When bind-interfaces is set, there might be more than one dnmsasq /* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 67. That's OK if they serve different networks. instance binding port 67. That's OK if they serve different networks.
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
OpenBSD <= 4.0 screws up IP_RECVIF when SO_REUSEPORT is set, but
OpenBSD <= 3.9 doesn't have IP_RECVIF anyway, so we just have to elide
this for OpenBSD 4.0, if you want more than one instance on oBSD4.0, tough. */
#ifndef OpenBSD4_0
if (daemon->options & OPT_NOWILD) if (daemon->options & OPT_NOWILD)
{ {
#ifdef SO_REUSEPORT #ifdef SO_REUSEPORT
@@ -67,11 +64,10 @@ void dhcp_init(void)
if (rc == -1) if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET); die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
} }
#endif
memset(&saddr, 0, sizeof(saddr)); memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET; saddr.sin_family = AF_INET;
saddr.sin_port = htons(daemon->dhcp_server_port); saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = INADDR_ANY; saddr.sin_addr.s_addr = INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN #ifdef HAVE_SOCKADDR_SA_LEN
saddr.sin_len = sizeof(struct sockaddr_in); saddr.sin_len = sizeof(struct sockaddr_in);
@@ -80,7 +76,20 @@ void dhcp_init(void)
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))) if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)))
die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET); die(_("failed to bind DHCP server socket: %s"), NULL, EC_BADNET);
daemon->dhcpfd = fd; return fd;
}
void dhcp_init(void)
{
#if defined(HAVE_BSD_NETWORK)
int oneopt = 1;
#endif
daemon->dhcpfd = make_fd(daemon->dhcp_server_port);
if (daemon->enable_pxe)
daemon->pxefd = make_fd(PXE_PORT);
else
daemon->pxefd = -1;
#if defined(HAVE_BSD_NETWORK) #if defined(HAVE_BSD_NETWORK)
/* When we're not using capabilities, we need to do this here before /* When we're not using capabilities, we need to do this here before
@@ -103,8 +112,9 @@ void dhcp_init(void)
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len); daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
} }
void dhcp_packet(time_t now) void dhcp_packet(time_t now, int pxe_fd)
{ {
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
struct dhcp_packet *mess; struct dhcp_packet *mess;
struct dhcp_context *context; struct dhcp_context *context;
struct iname *tmp; struct iname *tmp;
@@ -124,7 +134,7 @@ void dhcp_packet(time_t now)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK) #elif defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(unsigned int))]; char control[CMSG_SPACE(sizeof(unsigned int))];
#elif defined(IP_RECVIF) #elif defined(HAVE_BSD_NETWORK)
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif #endif
} control_u; } control_u;
@@ -136,13 +146,30 @@ void dhcp_packet(time_t now)
msg.msg_iov = &daemon->dhcp_packet; msg.msg_iov = &daemon->dhcp_packet;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
do while (1)
{ {
msg.msg_flags = 0; msg.msg_flags = 0;
while ((sz = recvmsg(daemon->dhcpfd, &msg, MSG_PEEK)) == -1 && errno == EINTR); 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;
}
} }
while (sz != -1 && (msg.msg_flags & MSG_TRUNC) &&
expand_buf(&daemon->dhcp_packet, daemon->dhcp_packet.iov_len + 100));
/* expand_buf may have moved buffer */ /* expand_buf may have moved buffer */
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base; mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
@@ -152,9 +179,9 @@ void dhcp_packet(time_t now)
msg.msg_name = &dest; msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest); msg.msg_namelen = sizeof(dest);
while ((sz = recvmsg(daemon->dhcpfd, &msg, 0)) == -1 && errno == EINTR); while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
if (sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))) 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)
@@ -166,41 +193,31 @@ void dhcp_packet(time_t now)
if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST) if (((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_addr.s_addr != INADDR_BROADCAST)
unicast_dest = 1; unicast_dest = 1;
} }
if (!(ifr.ifr_ifindex = iface_index) || #elif defined(HAVE_BSD_NETWORK)
ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) == -1)
return;
#elif defined(IP_RECVIF)
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 == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
#ifdef HAVE_SOLARIS_NETWORK
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
#else
iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index; iface_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
#endif
if (!iface_index || !if_indextoname(iface_index, ifr.ifr_name))
return;
#elif defined(HAVE_SOLARIS_NETWORK)
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
iface_index = *((unsigned int *)CMSG_DATA(cmptr));
#endif
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
#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
#else
/* fallback for systems without IP_RECVIF - allow only one interface
and assume packets arrive from it - yuk. */
{
struct iname *name;
for (name = daemon->if_names; name->isloop; name = name->next);
strcpy(ifr.ifr_name, name->name);
iface_index = if_nametoindex(name->name);
}
#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 )
{ {
@@ -208,7 +225,7 @@ void dhcp_packet(time_t now)
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr; iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
} }
if (!iface_check(AF_INET, (struct all_addr *)addrp, &ifr, &iface_index)) if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
return; return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -218,9 +235,9 @@ void dhcp_packet(time_t now)
/* interface may have been changed by alias in iface_check */ /* interface may have been changed by alias in iface_check */
if (!addrp) if (!addrp)
{ {
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1) if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
{ {
my_syslog(LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name); my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return; return;
} }
else else
@@ -240,7 +257,7 @@ void dhcp_packet(time_t now)
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); now, unicast_dest, &is_inform, pxe_fd);
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
@@ -261,7 +278,12 @@ void dhcp_packet(time_t now)
dest.sin_len = sizeof(struct sockaddr_in); dest.sin_len = sizeof(struct sockaddr_in);
#endif #endif
if (mess->giaddr.s_addr) if (pxe_fd)
{
if (mess->ciaddr.s_addr != 0)
dest.sin_addr = mess->ciaddr;
}
else if (mess->giaddr.s_addr)
{ {
/* Send to BOOTP relay */ /* Send to BOOTP relay */
dest.sin_port = htons(daemon->dhcp_server_port); dest.sin_port = htons(daemon->dhcp_server_port);
@@ -319,7 +341,7 @@ void dhcp_packet(time_t now)
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);
/* note that we don't specify the interface here: that's done by the /* note that we don't specify the interface here: that's done by the
IP_XMIT_IF sockopt lower down. */ IP_BOUND_IF sockopt lower down. */
} }
else else
{ {
@@ -345,10 +367,10 @@ void dhcp_packet(time_t now)
#endif #endif
#ifdef HAVE_SOLARIS_NETWORK #ifdef HAVE_SOLARIS_NETWORK
setsockopt(daemon->dhcpfd, IPPROTO_IP, IP_XMIT_IF, &iface_index, sizeof(iface_index)); setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
#endif #endif
while(sendmsg(daemon->dhcpfd, &msg, 0) == -1 && retry_send()); while(sendmsg(fd, &msg, 0) == -1 && retry_send());
} }
/* 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
@@ -379,7 +401,7 @@ static int complete_context(struct in_addr local, int if_index,
{ {
strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
my_syslog(LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"), my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask)); daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
} }
context->netmask = netmask; context->netmask = netmask;
@@ -469,9 +491,9 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
if (!(tmp = address_available(context, taddr, netids))) if (!(tmp = address_available(context, taddr, netids)))
{ {
for (tmp = context; tmp; tmp = tmp->current) for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net(taddr, tmp->start, tmp->netmask) && if (is_same_net(taddr, tmp->start, tmp->netmask) &&
(tmp->flags & CONTEXT_STATIC)) (tmp->flags & CONTEXT_STATIC))
break; break;
if (!tmp) if (!tmp)
for (tmp = context; tmp; tmp = tmp->current) for (tmp = context; tmp; tmp = tmp->current)
@@ -560,9 +582,16 @@ int address_allocate(struct dhcp_context *context,
if (addr.s_addr == d->router.s_addr) if (addr.s_addr == d->router.s_addr)
break; break;
/* Addresses which end in .255 and .0 are broken in Windows even when using
supernetting. ie dhcp-range=192.168.0.1,192.168.1.254,255,255,254.0
then 192.168.0.255 is a valid IP address, but not for Windows as it's
in the class C range. See KB281579. We therefore don't allocate these
addresses to avoid hard-to-diagnose problems. Thanks Bill. */
if (!d && if (!d &&
!lease_find_by_addr(addr) && !lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr)) !config_find_by_address(daemon->dhcp_conf, addr) &&
(!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
{ {
struct ping_result *r, *victim = NULL; struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/ int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
@@ -635,6 +664,19 @@ static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *
return 0; return 0;
} }
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs, struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
@@ -642,8 +684,10 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
unsigned char *hwaddr, int hw_len, unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname) int hw_type, char *hostname)
{ {
struct dhcp_config *config; int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid) if (clid)
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID) if (config->flags & CONFIG_CLID)
@@ -663,11 +707,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
for (config = configs; config; config = config->next) for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) && if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
config->wildcard_mask == 0 &&
config->hwaddr_len == hw_len &&
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) &&
memcmp(config->hwaddr, hwaddr, hw_len) == 0 &&
is_addr_in_context(context, config)) is_addr_in_context(context, config))
return config; return config;
@@ -677,17 +717,21 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
hostname_isequal(config->hostname, hostname) && hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config)) is_addr_in_context(context, config))
return config; return config;
for (config = configs; config; config = config->next) /* use match with fewest wildcast octets */
if ((config->flags & CONFIG_HWADDR) && for (candidate = NULL, count = 0, config = configs; config; config = config->next)
config->wildcard_mask != 0 && if (is_addr_in_context(context, config))
config->hwaddr_len == hw_len && for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
(config->hwaddr_type == hw_type || config->hwaddr_type == 0) && if (conf_addr->wildcard_mask != 0 &&
is_addr_in_context(context, config) && conf_addr->hwaddr_len == hw_len &&
memcmp_masked(config->hwaddr, hwaddr, hw_len, config->wildcard_mask)) (conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
return config; (new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
return NULL; count = new;
candidate = config;
}
return candidate;
} }
void dhcp_read_ethers(void) void dhcp_read_ethers(void)
@@ -706,7 +750,7 @@ void dhcp_read_ethers(void)
if (!f) if (!f)
{ {
my_syslog(LOG_ERR, _("failed to read %s:%s"), ETHERSFILE, strerror(errno)); my_syslog(MS_DHCP | LOG_ERR, _("failed to read %s: %s"), ETHERSFILE, strerror(errno));
return; return;
} }
@@ -720,6 +764,7 @@ void dhcp_read_ethers(void)
/* cannot have a clid */ /* cannot have a clid */
if (config->flags & CONFIG_NAME) if (config->flags & CONFIG_NAME)
free(config->hostname); free(config->hostname);
free(config->hwaddr);
free(config); free(config);
} }
else else
@@ -728,12 +773,14 @@ void dhcp_read_ethers(void)
while (fgets(buff, MAXDNAME, f)) while (fgets(buff, MAXDNAME, f))
{ {
char *host = NULL;
lineno++; lineno++;
while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1])) while (strlen(buff) > 0 && isspace((int)buff[strlen(buff)-1]))
buff[strlen(buff)-1] = 0; buff[strlen(buff)-1] = 0;
if ((*buff == '#') || (*buff == '+')) if ((*buff == '#') || (*buff == '+') || (*buff == 0))
continue; continue;
for (ip = buff; *ip && !isspace((int)*ip); ip++); for (ip = buff; *ip && !isspace((int)*ip); ip++);
@@ -741,7 +788,7 @@ void dhcp_read_ethers(void)
*ip = 0; *ip = 0;
if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN) if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN)
{ {
my_syslog(LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno);
continue; continue;
} }
@@ -754,7 +801,7 @@ void dhcp_read_ethers(void)
{ {
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1) if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
{ {
my_syslog(LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno); my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
continue; continue;
} }
@@ -766,35 +813,49 @@ void dhcp_read_ethers(void)
} }
else else
{ {
if (!canonicalise(ip) || strip_hostname(ip)) int nomem;
if (!(host = canonicalise(ip, &nomem)) || !legal_hostname(host))
{ {
my_syslog(LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno); if (!nomem)
my_syslog(MS_DHCP | LOG_ERR, _("bad name at %s line %d"), ETHERSFILE, lineno);
free(host);
continue; continue;
} }
flags = CONFIG_NAME; flags = CONFIG_NAME;
for (config = daemon->dhcp_conf; config; config = config->next) for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, ip)) if ((config->flags & CONFIG_NAME) && hostname_isequal(config->hostname, host))
break; break;
} }
if (config && (config->flags & CONFIG_FROM_ETHERS))
{
my_syslog(MS_DHCP | LOG_ERR, _("ignoring %s line %d, duplicate name or IP address"), ETHERSFILE, lineno);
continue;
}
if (!config) if (!config)
{ {
for (config = daemon->dhcp_conf; config; config = config->next) for (config = daemon->dhcp_conf; config; config = config->next)
if ((config->flags & CONFIG_HWADDR) && {
config->wildcard_mask == 0 && struct hwaddr_config *conf_addr = config->hwaddr;
config->hwaddr_len == ETHER_ADDR_LEN && if (conf_addr &&
(config->hwaddr_type == ARPHRD_ETHER || config->hwaddr_type == 0) && conf_addr->next == NULL &&
memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0) conf_addr->wildcard_mask == 0 &&
break; conf_addr->hwaddr_len == ETHER_ADDR_LEN &&
(conf_addr->hwaddr_type == ARPHRD_ETHER || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
break;
}
if (!config) if (!config)
{ {
if (!(config = whine_malloc(sizeof(struct dhcp_config)))) if (!(config = whine_malloc(sizeof(struct dhcp_config))))
continue; continue;
config->flags = CONFIG_FROM_ETHERS; config->flags = CONFIG_FROM_ETHERS;
config->wildcard_mask = 0; config->hwaddr = NULL;
config->domain = NULL;
config->next = daemon->dhcp_conf; config->next = daemon->dhcp_conf;
daemon->dhcp_conf = config; daemon->dhcp_conf = config;
} }
@@ -803,26 +864,34 @@ void dhcp_read_ethers(void)
if (flags & CONFIG_NAME) if (flags & CONFIG_NAME)
{ {
if ((config->hostname = whine_malloc(strlen(ip)+1))) config->hostname = host;
strcpy(config->hostname, ip); host = NULL;
else
config->flags &= ~CONFIG_NAME;
} }
if (flags & CONFIG_ADDR) if (flags & CONFIG_ADDR)
config->addr = addr; config->addr = addr;
} }
config->flags |= CONFIG_HWADDR | CONFIG_NOCLID; config->flags |= CONFIG_NOCLID;
memcpy(config->hwaddr, hwaddr, ETHER_ADDR_LEN); if (!config->hwaddr)
config->hwaddr_len = ETHER_ADDR_LEN; config->hwaddr = whine_malloc(sizeof(struct hwaddr_config));
config->hwaddr_type = ARPHRD_ETHER; if (config->hwaddr)
{
memcpy(config->hwaddr->hwaddr, hwaddr, ETHER_ADDR_LEN);
config->hwaddr->hwaddr_len = ETHER_ADDR_LEN;
config->hwaddr->hwaddr_type = ARPHRD_ETHER;
config->hwaddr->wildcard_mask = 0;
config->hwaddr->next = NULL;
}
count++; count++;
free(host);
} }
fclose(f); fclose(f);
my_syslog(LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count); my_syslog(MS_DHCP | LOG_INFO, _("read %s - %d addresses"), ETHERSFILE, count);
} }
void check_dhcp_hosts(int fatal) void check_dhcp_hosts(int fatal)
@@ -847,20 +916,14 @@ void check_dhcp_hosts(int fatal)
die(_("duplicate IP address %s in dhcp-config directive."), die(_("duplicate IP address %s in dhcp-config directive."),
inet_ntoa(cp->addr), EC_BADCONF); inet_ntoa(cp->addr), EC_BADCONF);
else else
my_syslog(LOG_ERR, _("duplicate IP address %s in %s."), my_syslog(MS_DHCP | LOG_ERR, _("duplicate IP address %s in %s."),
inet_ntoa(cp->addr), daemon->dhcp_hosts_file); inet_ntoa(cp->addr), daemon->dhcp_hosts_file);
configs->flags &= ~CONFIG_ADDR; configs->flags &= ~CONFIG_ADDR;
} }
/* split off domain part */
if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname))) if ((configs->flags & CONFIG_NAME) && (domain = strip_hostname(configs->hostname)))
{ configs->domain = domain;
if (fatal)
die(_("illegal domain %s in dhcp-config directive."), domain, EC_BADCONF);
else
my_syslog(LOG_ERR, _("illegal domain %s in %s."), domain, daemon->dhcp_hosts_file);
free(configs->hostname);
configs->flags &= ~CONFIG_NAME;
}
} }
} }
} }
@@ -896,12 +959,12 @@ void dhcp_update_configs(struct dhcp_config *configs)
crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4); crec = cache_find_by_name(crec, config->hostname, 0, F_IPV4);
if (!crec) if (!crec)
continue; /* should be never */ continue; /* should be never */
my_syslog(LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"), my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, inet_ntoa(crec->addr.addr.addr.addr4)); config->hostname, inet_ntoa(crec->addr.addr.addr.addr4));
} }
if (config_find_by_address(configs, crec->addr.addr.addr.addr4)) if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
my_syslog(LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"), my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
inet_ntoa(crec->addr.addr.addr.addr4), config->hostname); inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
else else
{ {
@@ -913,11 +976,13 @@ void dhcp_update_configs(struct dhcp_config *configs)
/* If we've not found a hostname any other way, try and see if there's one in /etc/hosts /* If we've not found a hostname any other way, try and see if there's one in /etc/hosts
for this address. If it has a domain part, that must match the set domain and for this address. If it has a domain part, that must match the set domain and
it gets stripped. */ it gets stripped. The set of legal domain names is bigger than the set of legal hostnames
so check here that the domain name is legal as a hostname. */
char *host_from_dns(struct in_addr addr) char *host_from_dns(struct in_addr addr)
{ {
struct crec *lookup; struct crec *lookup;
char *hostname = NULL; char *hostname = NULL;
char *d1, *d2;
if (daemon->port == 0) if (daemon->port == 0)
return NULL; /* DNS disabled. */ return NULL; /* DNS disabled. */
@@ -928,14 +993,16 @@ char *host_from_dns(struct in_addr addr)
hostname = daemon->dhcp_buff; hostname = daemon->dhcp_buff;
strncpy(hostname, cache_get_name(lookup), 256); strncpy(hostname, cache_get_name(lookup), 256);
hostname[255] = 0; hostname[255] = 0;
if (strip_hostname(hostname)) d1 = strip_hostname(hostname);
d2 = get_domain(addr);
if (!legal_hostname(hostname) || (d1 && (!d2 || !hostname_isequal(d1, d2))))
hostname = NULL; hostname = NULL;
} }
return hostname; return hostname;
} }
/* return illegal domain or NULL if OK */ /* return domain or NULL if none. */
char *strip_hostname(char *hostname) char *strip_hostname(char *hostname)
{ {
char *dot = strchr(hostname, '.'); char *dot = strchr(hostname, '.');
@@ -944,9 +1011,11 @@ char *strip_hostname(char *hostname)
return NULL; return NULL;
*dot = 0; /* truncate */ *dot = 0; /* truncate */
if (strlen(dot+1) != 0)
if (*(dot+1) && (!daemon->domain_suffix || !hostname_isequal(dot+1, daemon->domain_suffix)))
return dot+1; return dot+1;
return NULL; return NULL;
} }
#endif
+81 -54
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -33,13 +33,6 @@ static char *compile_opts =
#ifdef NO_FORK #ifdef NO_FORK
"no-MMU " "no-MMU "
#endif #endif
#ifdef HAVE_BSD_BRIDGE
"BSD-bridge "
#endif
#ifndef HAVE_ISC_READER
"no-"
#endif
"ISC-leasefile "
#ifndef HAVE_DBUS #ifndef HAVE_DBUS
"no-" "no-"
#endif #endif
@@ -48,11 +41,20 @@ static char *compile_opts =
"no-" "no-"
#endif #endif
"I18N " "I18N "
#ifndef HAVE_DHCP
"no-"
#endif
"DHCP "
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
"no-scripts "
#endif
#ifndef HAVE_TFTP #ifndef HAVE_TFTP
"no-" "no-"
#endif #endif
"TFTP"; "TFTP";
static volatile pid_t pid = 0; static volatile pid_t pid = 0;
static volatile int pipewrite; static volatile int pipewrite;
@@ -66,14 +68,16 @@ static void poll_resolv(void);
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
int bind_fallback = 0; int bind_fallback = 0;
time_t now, last = 0; time_t now;
struct sigaction sigact; struct sigaction sigact;
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)
uid_t script_uid = 0; uid_t script_uid = 0;
gid_t script_gid = 0; gid_t script_gid = 0;
struct group *gp= NULL; #endif
struct group *gp = NULL;
long i, max_fd = sysconf(_SC_OPEN_MAX); long i, max_fd = sysconf(_SC_OPEN_MAX);
char *baduser = NULL; char *baduser = NULL;
int log_err; int log_err;
@@ -112,14 +116,12 @@ 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);
#ifdef HAVE_DHCP
if (!daemon->lease_file) if (!daemon->lease_file)
{ {
if (daemon->dhcp) if (daemon->dhcp)
daemon->lease_file = LEASEFILE; daemon->lease_file = LEASEFILE;
} }
#ifndef HAVE_ISC_READER
else if (!daemon->dhcp)
die(_("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h"), NULL, EC_BADCONF);
#endif #endif
/* Close any file descriptors we inherited apart from std{in|out|err} */ /* Close any file descriptors we inherited apart from std{in|out|err} */
@@ -153,23 +155,16 @@ int main (int argc, char **argv)
now = dnsmasq_time(); now = dnsmasq_time();
#ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp)
{ {
#if !defined(HAVE_LINUX_NETWORK) && !defined(IP_RECVIF)
int c;
struct iname *tmp;
for (c = 0, tmp = daemon->if_names; tmp; tmp = tmp->next)
if (!tmp->isloop)
c++;
if (c != 1)
die(_("must set exactly one interface on broken systems without IP_RECVIF"), NULL, EC_BADCONF);
#endif
/* Note that order matters here, we must call lease_init before /* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked creating any file descriptors which shouldn't be leaked
to the lease-script init process. */ to the lease-script init process. */
lease_init(now); lease_init(now);
dhcp_init(); dhcp_init();
} }
#endif
if (!enumerate_interfaces()) if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC); die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
@@ -212,6 +207,7 @@ 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)
/* Note getpwnam returns static storage */ /* Note getpwnam returns static storage */
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser) if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
{ {
@@ -223,6 +219,7 @@ int main (int argc, char **argv)
else else
baduser = daemon->scriptuser; baduser = daemon->scriptuser;
} }
#endif
if (daemon->username && !(ent_pw = getpwnam(daemon->username))) if (daemon->username && !(ent_pw = getpwnam(daemon->username)))
baduser = daemon->username; baduser = daemon->username;
@@ -298,8 +295,9 @@ int main (int argc, char **argv)
When startup is complete we close this and the process terminates. */ When startup is complete we close this and the process terminates. */
safe_pipe(err_pipe, 0); safe_pipe(err_pipe, 0);
if ((pid = fork()) == -1 ) if ((pid = fork()) == -1)
die(_("cannot fork into background: %s"), NULL, EC_MISC); /* fd == -1 since we've not forked, never returns. */
send_event(-1, EVENT_FORK_ERR, errno);
if (pid != 0) if (pid != 0)
{ {
@@ -320,9 +318,11 @@ int main (int argc, char **argv)
/* NO calls to die() from here on. */ /* NO calls to die() from here on. */
setsid(); setsid();
pid = fork();
if ((pid = fork()) == -1)
if (pid != 0 && pid != -1) send_event(err_pipe[1], EVENT_FORK_ERR, errno);
if (pid != 0)
_exit(0); _exit(0);
} }
#endif #endif
@@ -357,7 +357,7 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */ /* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1; daemon->helperfd = -1;
#ifndef NO_FORK #if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
if (daemon->dhcp && daemon->lease_change_command) if (daemon->dhcp && daemon->lease_change_command)
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
@@ -388,7 +388,7 @@ int main (int argc, char **argv)
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1) if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
bad_capabilities = errno; bad_capabilities = errno;
#elif defined(HAVE_SOLARIS_PRIVS) #elif defined(HAVE_SOLARIS_NETWORK)
/* http://developers.sun.com/solaris/articles/program_privileges.html */ /* http://developers.sun.com/solaris/articles/program_privileges.html */
priv_set_t *priv_set; priv_set_t *priv_set;
@@ -408,9 +408,6 @@ int main (int argc, char **argv)
if (priv_set) if (priv_set)
priv_freeset(priv_set); priv_freeset(priv_set);
#elif defined(HAVE_SOLARIS_NETWORK)
bad_capabilities = ENOTSUP;
#endif #endif
if (bad_capabilities != 0) if (bad_capabilities != 0)
@@ -490,6 +487,7 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0) if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs); my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
#ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp)
{ {
struct dhcp_context *dhcp_tmp; struct dhcp_context *dhcp_tmp;
@@ -498,13 +496,16 @@ int main (int argc, char **argv)
{ {
prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time); prettyprint_time(daemon->dhcp_buff2, dhcp_tmp->lease_time);
strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start)); strcpy(daemon->dhcp_buff, inet_ntoa(dhcp_tmp->start));
my_syslog(LOG_INFO, my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_STATIC) ? (dhcp_tmp->flags & CONTEXT_STATIC) ?
_("DHCP, static leases only on %.0s%s, lease time %s") : _("DHCP, static leases only on %.0s%s, lease time %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
_("DHCP, IP range %s -- %s, lease time %s"), _("DHCP, IP range %s -- %s, lease time %s"),
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2); daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), daemon->dhcp_buff2);
} }
} }
#endif
#ifdef HAVE_TFTP #ifdef HAVE_TFTP
if (daemon->options & OPT_TFTP) if (daemon->options & OPT_TFTP)
@@ -514,7 +515,7 @@ int main (int argc, char **argv)
max_fd = FD_SETSIZE; max_fd = FD_SETSIZE;
#endif #endif
my_syslog(LOG_INFO, "TFTP %s%s %s", my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
daemon->tftp_prefix ? _("root is ") : _("enabled"), daemon->tftp_prefix ? _("root is ") : _("enabled"),
daemon->tftp_prefix ? daemon->tftp_prefix: "", daemon->tftp_prefix ? daemon->tftp_prefix: "",
daemon->options & OPT_TFTP_SECURE ? _("secure mode") : ""); daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
@@ -542,7 +543,7 @@ int main (int argc, char **argv)
if (daemon->tftp_max > max_fd) if (daemon->tftp_max > max_fd)
{ {
daemon->tftp_max = max_fd; daemon->tftp_max = max_fd;
my_syslog(LOG_WARNING, my_syslog(MS_TFTP | LOG_WARNING,
_("restricting maximum simultaneous TFTP transfers to %d"), _("restricting maximum simultaneous TFTP transfers to %d"),
daemon->tftp_max); daemon->tftp_max);
} }
@@ -590,11 +591,18 @@ int main (int argc, char **argv)
set_dbus_listeners(&maxfd, &rset, &wset, &eset); set_dbus_listeners(&maxfd, &rset, &wset, &eset);
#endif #endif
#ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp)
{ {
FD_SET(daemon->dhcpfd, &rset); FD_SET(daemon->dhcpfd, &rset);
bump_maxfd(daemon->dhcpfd, &maxfd); bump_maxfd(daemon->dhcpfd, &maxfd);
if (daemon->pxefd != -1)
{
FD_SET(daemon->pxefd, &rset);
bump_maxfd(daemon->pxefd, &maxfd);
}
} }
#endif
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
FD_SET(daemon->netlinkfd, &rset); FD_SET(daemon->netlinkfd, &rset);
@@ -604,7 +612,8 @@ int main (int argc, char **argv)
FD_SET(piperead, &rset); FD_SET(piperead, &rset);
bump_maxfd(piperead, &maxfd); bump_maxfd(piperead, &maxfd);
#ifndef NO_FORK #ifdef HAVE_DHCP
# ifdef HAVE_SCRIPT
while (helper_buf_empty() && do_script_run(now)); while (helper_buf_empty() && do_script_run(now));
if (!helper_buf_empty()) if (!helper_buf_empty())
@@ -612,11 +621,12 @@ int main (int argc, char **argv)
FD_SET(daemon->helperfd, &wset); FD_SET(daemon->helperfd, &wset);
bump_maxfd(daemon->helperfd, &maxfd); bump_maxfd(daemon->helperfd, &maxfd);
} }
#else # else
/* need this for other side-effects */ /* need this for other side-effects */
while (do_script_run(now)); while (do_script_run(now));
# endif
#endif #endif
/* must do this just before select(), when we know no /* must do this just before select(), when we know no
more calls to my_syslog() can occur */ more calls to my_syslog() can occur */
set_log_writer(&wset, &maxfd); set_log_writer(&wset, &maxfd);
@@ -633,14 +643,11 @@ int main (int argc, char **argv)
/* Check for changes to resolv files once per second max. */ /* Check for changes to resolv files once per second max. */
/* Don't go silent for long periods if the clock goes backwards. */ /* Don't go silent for long periods if the clock goes backwards. */
if (last == 0 || difftime(now, last) > 1.0 || difftime(now, last) < -1.0) if (daemon->last_resolv == 0 ||
difftime(now, daemon->last_resolv) > 1.0 ||
difftime(now, daemon->last_resolv) < -1.0)
{ {
last = now; daemon->last_resolv = now;
#ifdef HAVE_ISC_READER
if (daemon->lease_file && !daemon->dhcp)
load_dhcp(now);
#endif
if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL)) if (daemon->port != 0 && !(daemon->options & OPT_NO_POLL))
poll_resolv(); poll_resolv();
@@ -673,12 +680,19 @@ int main (int argc, char **argv)
check_tftp_listeners(&rset, now); check_tftp_listeners(&rset, now);
#endif #endif
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset)) #ifdef HAVE_DHCP
dhcp_packet(now); if (daemon->dhcp)
{
if (FD_ISSET(daemon->dhcpfd, &rset))
dhcp_packet(now, 0);
if (daemon->pxefd != -1 && FD_ISSET(daemon->pxefd, &rset))
dhcp_packet(now, 1);
}
#ifndef NO_FORK # ifdef HAVE_SCRIPT
if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset)) if (daemon->helperfd != -1 && FD_ISSET(daemon->helperfd, &wset))
helper_write(); helper_write();
# endif
#endif #endif
} }
@@ -748,6 +762,9 @@ static void fatal_event(struct event_desc *ev)
{ {
case EVENT_DIE: case EVENT_DIE:
exit(0); exit(0);
case EVENT_FORK_ERR:
die(_("cannot fork into background: %s"), NULL, EC_MISC);
case EVENT_PIPE_ERR: case EVENT_PIPE_ERR:
die(_("failed to create helper: %s"), NULL, EC_MISC); die(_("failed to create helper: %s"), NULL, EC_MISC);
@@ -788,7 +805,9 @@ static void async_event(int pipe, time_t now)
reload_servers(daemon->resolv_files->name); reload_servers(daemon->resolv_files->name);
check_servers(); check_servers();
} }
#ifdef HAVE_DHCP
rerun_scripts(); rerun_scripts();
#endif
break; break;
case EVENT_DUMP: case EVENT_DUMP:
@@ -797,11 +816,13 @@ static void async_event(int pipe, time_t now)
break; break;
case EVENT_ALARM: case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp)
{ {
lease_prune(NULL, now); lease_prune(NULL, now);
lease_update_file(now); lease_update_file(now);
} }
#endif
break; break;
case EVENT_CHILD: case EVENT_CHILD:
@@ -851,7 +872,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);
#ifndef NO_FORK #if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
/* handle pending lease transitions */ /* handle pending lease transitions */
if (daemon->helperfd != -1) if (daemon->helperfd != -1)
{ {
@@ -867,6 +888,9 @@ static void async_event(int pipe, time_t now)
if (daemon->lease_stream) if (daemon->lease_stream)
fclose(daemon->lease_stream); fclose(daemon->lease_stream);
if (daemon->runfile)
unlink(daemon->runfile);
my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM")); my_syslog(LOG_INFO, _("exiting on receipt of SIGTERM"));
flush_log(); flush_log();
@@ -912,7 +936,7 @@ static void poll_resolv()
warned = 0; warned = 0;
check_servers(); check_servers();
if (daemon->options & OPT_RELOAD) if (daemon->options & OPT_RELOAD)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); cache_reload();
} }
else else
{ {
@@ -929,8 +953,9 @@ static void poll_resolv()
void clear_cache_and_reload(time_t now) void clear_cache_and_reload(time_t now)
{ {
if (daemon->port != 0) if (daemon->port != 0)
cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts); cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp) if (daemon->dhcp)
{ {
if (daemon->options & OPT_ETHERS) if (daemon->options & OPT_ETHERS)
@@ -942,6 +967,7 @@ void clear_cache_and_reload(time_t now)
lease_update_file(now); lease_update_file(now);
lease_update_dns(); lease_update_dns();
} }
#endif
} }
static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp) static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
@@ -1143,7 +1169,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
} }
} }
#ifdef HAVE_DHCP
int make_icmp_sock(void) int make_icmp_sock(void)
{ {
int fd; int fd;
@@ -1266,5 +1292,6 @@ int icmp_ping(struct in_addr addr)
return gotreply; return gotreply;
} }
#endif
+118 -64
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2008 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,11 +10,11 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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 COPYRIGHT "Copyright (C) 2000-2008 Simon Kelley" #define COPYRIGHT "Copyright (c) 2000-2010 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) */
@@ -28,8 +28,15 @@
# include <features.h> # include <features.h>
#endif #endif
/* Need these defined early */
#if defined(__sun) || defined(__sun__)
# define _XPG4_2
# define __EXTENSIONS__
#endif
/* 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 <netinet/in.h> #include <netinet/in.h>
#ifdef __APPLE__ #ifdef __APPLE__
@@ -55,10 +62,9 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#if defined(HAVE_SOLARIS_NETWORK) #if defined(HAVE_SOLARIS_NETWORK)
#include <sys/sockio.h> # include <sys/sockio.h>
#endif #endif
#include <sys/select.h> #include <sys/select.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -66,6 +72,10 @@
#include <sys/un.h> #include <sys/un.h>
#include <limits.h> #include <limits.h>
#include <net/if.h> #include <net/if.h>
#if defined(HAVE_SOLARIS_NETWORK) && !defined(ifr_mtu)
/* Some solaris net/if./h omit this. */
# define ifr_mtu ifr_ifru.ifru_metric
#endif
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -106,7 +116,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_3 0x20080522 #define LINUX_CAPABILITY_VERSION_3 0x20080522
#include <sys/prctl.h> #include <sys/prctl.h>
#elif defined(HAVE_SOLARIS_PRIVS) #elif defined(HAVE_SOLARIS_NETWORK)
#include <priv.h> #include <priv.h>
#endif #endif
@@ -135,6 +145,7 @@ struct event_desc {
#define EVENT_GROUP_ERR 15 #define EVENT_GROUP_ERR 15
#define EVENT_DIE 16 #define EVENT_DIE 16
#define EVENT_LOG_ERR 17 #define EVENT_LOG_ERR 17
#define EVENT_FORK_ERR 18
/* Exit codes. */ /* Exit codes. */
#define EC_GOOD 0 #define EC_GOOD 0
@@ -172,7 +183,7 @@ struct event_desc {
#define OPT_AUTHORITATIVE (1u<<17) #define OPT_AUTHORITATIVE (1u<<17)
#define OPT_LOCALISE (1u<<18) #define OPT_LOCALISE (1u<<18)
#define OPT_DBUS (1u<<19) #define OPT_DBUS (1u<<19)
#define OPT_BOOTP_DYNAMIC (1u<<20) #define OPT_DHCP_FQDN (1u<<20)
#define OPT_NO_PING (1u<<21) #define OPT_NO_PING (1u<<21)
#define OPT_LEASE_RO (1u<<22) #define OPT_LEASE_RO (1u<<22)
#define OPT_ALL_SERVERS (1u<<23) #define OPT_ALL_SERVERS (1u<<23)
@@ -185,6 +196,11 @@ struct event_desc {
#define OPT_NO_OVERRIDE (1u<<30) #define OPT_NO_OVERRIDE (1u<<30)
#define OPT_NO_REBIND (1u<<31) #define OPT_NO_REBIND (1u<<31)
/* 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. */
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON
struct all_addr { struct all_addr {
union { union {
struct in_addr addr4; struct in_addr addr4;
@@ -201,7 +217,7 @@ struct bogus_addr {
/* dns doctor param */ /* dns doctor param */
struct doctor { struct doctor {
struct in_addr in, out, mask; struct in_addr in, end, out, mask;
struct doctor *next; struct doctor *next;
}; };
@@ -229,6 +245,11 @@ struct ptr_record {
struct ptr_record *next; struct ptr_record *next;
}; };
struct cname {
char *alias, *target;
struct cname *next;
};
struct interface_name { struct interface_name {
char *name; /* domain name */ char *name; /* domain name */
char *intr; /* interface name */ char *intr; /* interface name */
@@ -282,19 +303,7 @@ struct crec {
union mysockaddr { union mysockaddr {
struct sockaddr sa; struct sockaddr sa;
struct sockaddr_in in; struct sockaddr_in in;
#ifdef HAVE_BROKEN_SOCKADDR_IN6 #if defined(HAVE_IPV6)
/* early versions of glibc don't include sin6_scope_id in sockaddr_in6
but latest kernels _require_ it to be set. The choice is to have
dnsmasq fail to compile on back-level libc or fail to run
on latest kernels with IPv6. Or to do this: sorry that it's so gross. */
struct my_sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
uint16_t sin6_port; /* transport layer port # */
uint32_t sin6_flowinfo; /* IPv6 traffic class & flow info */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* set of interfaces for a scope */
} in6;
#elif defined(HAVE_IPV6)
struct sockaddr_in6 in6; struct sockaddr_in6 in6;
#endif #endif
}; };
@@ -336,7 +345,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 dhcp_ok; int dhcp_ok, mtu;
struct irec *next; struct irec *next;
}; };
@@ -363,8 +372,11 @@ struct resolvc {
}; };
/* adn-hosts parms from command-line */ /* adn-hosts parms from command-line */
#define AH_DIR 1
#define AH_INACTIVE 2
struct hostsfile { struct hostsfile {
struct hostsfile *next; struct hostsfile *next;
int flags;
char *fname; char *fname;
int index; /* matches to cache entries for logging */ int index; /* matches to cache entries for logging */
}; };
@@ -408,9 +420,9 @@ struct dhcp_lease {
#endif #endif
int hwaddr_len, hwaddr_type; int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX]; unsigned char hwaddr[DHCP_CHADDR_MAX];
struct in_addr addr, override; struct in_addr addr, override, giaddr;
unsigned char *vendorclass, *userclass; unsigned char *extradata;
unsigned int vendorclass_len, userclass_len; unsigned int extradata_len, extradata_size;
int last_interface; int last_interface;
struct dhcp_lease *next; struct dhcp_lease *next;
}; };
@@ -425,23 +437,28 @@ struct dhcp_netid_list {
struct dhcp_netid_list *next; struct dhcp_netid_list *next;
}; };
struct hwaddr_config {
int hwaddr_len, hwaddr_type;
unsigned char hwaddr[DHCP_CHADDR_MAX];
unsigned int wildcard_mask;
struct hwaddr_config *next;
};
struct dhcp_config { struct dhcp_config {
unsigned int flags; unsigned int flags;
int clid_len; /* length of client identifier */ int clid_len; /* length of client identifier */
unsigned char *clid; /* clientid */ unsigned char *clid; /* clientid */
int hwaddr_len, hwaddr_type; char *hostname, *domain;
unsigned char hwaddr[DHCP_CHADDR_MAX];
char *hostname;
struct dhcp_netid netid; struct dhcp_netid netid;
struct in_addr addr; struct in_addr addr;
time_t decline_time; time_t decline_time;
unsigned int lease_time, wildcard_mask; unsigned int lease_time;
struct hwaddr_config *hwaddr;
struct dhcp_config *next; struct dhcp_config *next;
}; };
#define CONFIG_DISABLE 1 #define CONFIG_DISABLE 1
#define CONFIG_CLID 2 #define CONFIG_CLID 2
#define CONFIG_HWADDR 4
#define CONFIG_TIME 8 #define CONFIG_TIME 8
#define CONFIG_NAME 16 #define CONFIG_NAME 16
#define CONFIG_ADDR 32 #define CONFIG_ADDR 32
@@ -454,7 +471,12 @@ struct dhcp_config {
struct dhcp_opt { struct dhcp_opt {
int opt, len, flags; int opt, len, flags;
unsigned char *val, *vendor_class; union {
int encap;
unsigned int wildcard_mask;
unsigned char *vendor_class;
} u;
unsigned char *val;
struct dhcp_netid *netid; struct dhcp_netid *netid;
struct dhcp_opt *next; struct dhcp_opt *next;
}; };
@@ -462,9 +484,15 @@ struct dhcp_opt {
#define DHOPT_ADDR 1 #define DHOPT_ADDR 1
#define DHOPT_STRING 2 #define DHOPT_STRING 2
#define DHOPT_ENCAPSULATE 4 #define DHOPT_ENCAPSULATE 4
#define DHOPT_VENDOR_MATCH 8 #define DHOPT_ENCAP_MATCH 8
#define DHOPT_FORCE 16 #define DHOPT_FORCE 16
#define DHOPT_BANK 32 #define DHOPT_BANK 32
#define DHOPT_ENCAP_DONE 64
#define DHOPT_MATCH 128
#define DHOPT_VENDOR 256
#define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024
#define DHOPT_RFC3925 2048
struct dhcp_boot { struct dhcp_boot {
char *file, *sname; char *file, *sname;
@@ -473,12 +501,19 @@ struct dhcp_boot {
struct dhcp_boot *next; struct dhcp_boot *next;
}; };
struct pxe_service {
unsigned short CSA, type;
char *menu, *basename;
struct in_addr server;
struct dhcp_netid *netid;
struct pxe_service *next;
};
#define MATCH_VENDOR 1 #define MATCH_VENDOR 1
#define MATCH_USER 2 #define MATCH_USER 2
#define MATCH_CIRCUIT 3 #define MATCH_CIRCUIT 3
#define MATCH_REMOTE 4 #define MATCH_REMOTE 4
#define MATCH_SUBSCRIBER 5 #define MATCH_SUBSCRIBER 5
#define MATCH_OPTION 6
/* vendorclass, userclass, remote-id or cicuit-id */ /* vendorclass, userclass, remote-id or cicuit-id */
struct dhcp_vendor { struct dhcp_vendor {
@@ -496,12 +531,16 @@ struct dhcp_mac {
struct dhcp_mac *next; struct dhcp_mac *next;
}; };
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge { struct dhcp_bridge {
char iface[IF_NAMESIZE]; char iface[IF_NAMESIZE];
struct dhcp_bridge *alias, *next; struct dhcp_bridge *alias, *next;
}; };
#endif
struct cond_domain {
char *domain;
struct in_addr start, end;
struct cond_domain *next;
};
struct dhcp_context { struct dhcp_context {
unsigned int lease_time, addr_epoch; unsigned int lease_time, addr_epoch;
@@ -516,6 +555,7 @@ struct dhcp_context {
#define CONTEXT_STATIC 1 #define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2 #define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4 #define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8
typedef unsigned char u8; typedef unsigned char u8;
@@ -565,16 +605,19 @@ extern struct daemon {
unsigned int options; unsigned int options;
struct resolvc default_resolv, *resolv_files; struct resolvc default_resolv, *resolv_files;
time_t last_resolv;
struct mx_srv_record *mxnames; struct mx_srv_record *mxnames;
struct naptr *naptr; struct naptr *naptr;
struct txt_record *txt; struct txt_record *txt;
struct ptr_record *ptr; struct ptr_record *ptr;
struct cname *cnames;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain;
char *runfile; char *runfile;
char *lease_change_command; char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except; struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
@@ -589,11 +632,13 @@ extern struct daemon {
struct hostsfile *addn_hosts; struct hostsfile *addn_hosts;
struct dhcp_context *dhcp; struct dhcp_context *dhcp;
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts; struct dhcp_opt *dhcp_opts, *dhcp_match;
struct dhcp_vendor *dhcp_vendors; struct dhcp_vendor *dhcp_vendors;
struct dhcp_mac *dhcp_macs; struct dhcp_mac *dhcp_macs;
struct dhcp_boot *boot_config; struct dhcp_boot *boot_config;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast; struct pxe_service *pxe_services;
int enable_pxe;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
char *dhcp_hosts_file, *dhcp_opts_file; char *dhcp_hosts_file, *dhcp_opts_file;
int dhcp_max, tftp_max; int dhcp_max, tftp_max;
int dhcp_server_port, dhcp_client_port; int dhcp_server_port, dhcp_client_port;
@@ -613,26 +658,27 @@ extern struct daemon {
struct irec *interfaces; struct irec *interfaces;
struct listener *listeners; struct listener *listeners;
struct server *last_server; struct server *last_server;
time_t forwardtime;
int forwardcount;
struct server *srv_save; /* Used for resend on DoD */ struct server *srv_save; /* Used for resend on DoD */
size_t packet_len; /* " " */ size_t packet_len; /* " " */
struct randfd *rfd_save; /* " " */ struct randfd *rfd_save; /* " " */
pid_t tcp_pids[MAX_PROCS]; pid_t tcp_pids[MAX_PROCS];
struct randfd randomsocks[RANDOM_SOCKS]; struct randfd randomsocks[RANDOM_SOCKS];
int v6pktinfo;
/* DHCP state */ /* DHCP state */
int dhcpfd, helperfd; int dhcpfd, helperfd, pxefd;
#ifdef HAVE_LINUX_NETWORK #if defined(HAVE_LINUX_NETWORK)
int netlinkfd; int netlinkfd;
#else #elif defined(HAVE_BSD_NETWORK)
int dhcp_raw_fd, dhcp_icmp_fd; int dhcp_raw_fd, dhcp_icmp_fd;
#endif #endif
struct iovec dhcp_packet; struct iovec dhcp_packet;
char *dhcp_buff, *dhcp_buff2; char *dhcp_buff, *dhcp_buff2;
struct ping_result *ping_results; struct ping_result *ping_results;
FILE *lease_stream; FILE *lease_stream;
#ifdef HAVE_BSD_BRIDGE
struct dhcp_bridge *bridges; struct dhcp_bridge *bridges;
#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 */
@@ -649,7 +695,7 @@ pid_t tcp_pids[MAX_PROCS];
/* cache.c */ /* cache.c */
void cache_init(void); void cache_init(void);
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg); void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
char *record_source(struct hostsfile *addn_hosts, int index); char *record_source(int index);
void querystr(char *str, unsigned short type); void querystr(char *str, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp, struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now, struct all_addr *addr, time_t now,
@@ -660,11 +706,12 @@ void cache_end_insert(void);
void cache_start_insert(void); void cache_start_insert(void);
struct crec *cache_insert(char *name, struct all_addr *addr, struct crec *cache_insert(char *name, struct all_addr *addr,
time_t now, unsigned long ttl, unsigned short flags); time_t now, unsigned long ttl, unsigned short flags);
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts); void cache_reload(void);
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd); void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
void cache_unhash_dhcp(void); void cache_unhash_dhcp(void);
void dump_cache(time_t now); void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp); char *cache_get_name(struct crec *crecp);
char *get_domain(struct in_addr addr);
/* rfc1035.c */ /* rfc1035.c */
unsigned short extract_request(HEADER *header, size_t qlen, unsigned short extract_request(HEADER *header, size_t qlen,
@@ -687,8 +734,8 @@ size_t resize_packet(HEADER *header, size_t plen,
/* util.c */ /* util.c */
void rand_init(void); void rand_init(void);
unsigned short rand16(void); unsigned short rand16(void);
int legal_char(char c); int legal_hostname(char *c);
int canonicalise(char *s); char *canonicalise(char *s, int *nomem);
unsigned char *do_rfc1035_name(unsigned char *p, char *sval); unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void *safe_malloc(size_t size); void *safe_malloc(size_t size);
void safe_pipe(int *fd, int read_noblock); void safe_pipe(int *fd, int read_noblock);
@@ -721,7 +768,7 @@ void flush_log(void);
/* option.c */ /* option.c */
void read_opts (int argc, char **argv, char *compile_opts); void read_opts (int argc, char **argv, char *compile_opts);
char *option_string(unsigned char opt); char *option_string(unsigned char opt, int *is_ip, int *is_name);
void reread_dhcp(void); void reread_dhcp(void);
/* forward.c */ /* forward.c */
@@ -733,6 +780,7 @@ 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);
/* network.c */ /* network.c */
int indextoname(int fd, int index, char *name);
int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp); int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp);
int random_sock(int family); int random_sock(int family);
void pre_allocate_sfds(void); void pre_allocate_sfds(void);
@@ -741,25 +789,24 @@ void check_servers(void);
int enumerate_interfaces(); int enumerate_interfaces();
struct listener *create_wildcard_listeners(void); struct listener *create_wildcard_listeners(void);
struct listener *create_bound_listeners(void); struct listener *create_bound_listeners(void);
int iface_check(int family, struct all_addr *addr, int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
struct ifreq *ifr, int *indexp);
int fix_fd(int fd); int fix_fd(int fd);
struct in_addr get_ifaddr(char *intr); struct in_addr get_ifaddr(char *intr);
/* dhcp.c */ /* dhcp.c */
#ifdef HAVE_DHCP
void dhcp_init(void); void dhcp_init(void);
void dhcp_packet(time_t now); void dhcp_packet(time_t now, int pxe_fd);
struct dhcp_context *address_available(struct dhcp_context *context, struct dhcp_context *address_available(struct dhcp_context *context,
struct in_addr addr, struct in_addr addr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
struct dhcp_context *narrow_context(struct dhcp_context *context, struct dhcp_context *narrow_context(struct dhcp_context *context,
struct in_addr taddr, struct in_addr taddr,
struct dhcp_netid *netids); struct dhcp_netid *netids);
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly); int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool, int negonly);int address_allocate(struct dhcp_context *context,
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len, struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now); struct dhcp_netid *netids, time_t now);
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
struct dhcp_config *find_config(struct dhcp_config *configs, struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context, struct dhcp_context *context,
unsigned char *clid, int clid_len, unsigned char *clid, int clid_len,
@@ -771,16 +818,18 @@ void check_dhcp_hosts(int fatal);
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr); struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr);
char *strip_hostname(char *hostname); char *strip_hostname(char *hostname);
char *host_from_dns(struct in_addr addr); char *host_from_dns(struct in_addr addr);
char *get_domain(struct in_addr addr);
#endif
/* lease.c */ /* lease.c */
#ifdef HAVE_DHCP
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_allocate(struct in_addr addr);
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, void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
char *suffix, int auth);
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now); void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease *lease, int interface); void lease_set_interface(struct dhcp_lease *lease, int interface);
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type, struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
@@ -790,22 +839,24 @@ void lease_prune(struct dhcp_lease *target, time_t now);
void lease_update_from_configs(void); void lease_update_from_configs(void);
int do_script_run(time_t now); int do_script_run(time_t now);
void rerun_scripts(void); void rerun_scripts(void);
#endif
/* rfc2131.c */ /* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index, size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
size_t sz, time_t now, int unicast_dest, int *is_inform); size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd);
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
int clid_len, unsigned char *clid, int *len_out);
#endif
/* dnsmasq.c */ /* dnsmasq.c */
#ifdef HAVE_DHCP
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
void send_event(int fd, int event, int data); void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now); void clear_cache_and_reload(time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
void load_dhcp(time_t now);
#endif
/* netlink.c */ /* netlink.c */
#ifdef HAVE_LINUX_NETWORK #ifdef HAVE_LINUX_NETWORK
void netlink_init(void); void netlink_init(void);
@@ -827,10 +878,13 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
char *dbus_init(void); char *dbus_init(void);
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset); void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset);
void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset); void set_dbus_listeners(int *maxfdp, fd_set *rset, fd_set *wset, fd_set *eset);
# ifdef HAVE_DHCP
void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname);
# endif
#endif #endif
/* helper.c */ /* helper.c */
#ifndef NO_FORK #if defined(HAVE_DHCP) && !defined(NO_FORK)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd); int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void); void helper_write(void);
void queue_script(int action, struct dhcp_lease *lease, void queue_script(int action, struct dhcp_lease *lease,
+27 -44
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -20,7 +20,7 @@ static struct frec *lookup_frec(unsigned short id, unsigned int crc);
static struct frec *lookup_frec_by_sender(unsigned short id, static struct frec *lookup_frec_by_sender(unsigned short id,
union mysockaddr *addr, union mysockaddr *addr,
unsigned int crc); unsigned int crc);
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc); static unsigned short get_id(unsigned int crc);
static void free_frec(struct frec *f); static void free_frec(struct frec *f);
static struct randfd *allocate_rfd(int family); static struct randfd *allocate_rfd(int family);
@@ -86,7 +86,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */ pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
pkt->ipi6_addr = source->addr.addr6; pkt->ipi6_addr = source->addr.addr6;
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 = IPV6_PKTINFO; cmptr->cmsg_type = daemon->v6pktinfo;
cmptr->cmsg_level = IPV6_LEVEL; cmptr->cmsg_level = IPV6_LEVEL;
} }
#else #else
@@ -242,15 +242,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (forward) if (forward)
{ {
/* force unchanging id for signed packets */
int is_sign;
find_pseudoheader(header, plen, NULL, NULL, &is_sign);
forward->source = *udpaddr; forward->source = *udpaddr;
forward->dest = *dst_addr; forward->dest = *dst_addr;
forward->iface = dst_iface; forward->iface = dst_iface;
forward->orig_id = ntohs(header->id); forward->orig_id = ntohs(header->id);
forward->new_id = get_id(is_sign, forward->orig_id, crc); forward->new_id = get_id(crc);
forward->fd = udpfd; forward->fd = udpfd;
forward->crc = crc; forward->crc = crc;
forward->forwardall = 0; forward->forwardall = 0;
@@ -262,10 +258,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (type != 0 || (daemon->options & OPT_ORDER)) if (type != 0 || (daemon->options & OPT_ORDER))
start = daemon->servers; start = daemon->servers;
else if (!(start = daemon->last_server)) else if (!(start = daemon->last_server) ||
daemon->forwardcount++ > FORWARD_TEST ||
difftime(now, daemon->forwardtime) > FORWARD_TIME)
{ {
start = daemon->servers; start = daemon->servers;
forward->forwardall = 1; forward->forwardall = 1;
daemon->forwardcount = 0;
daemon->forwardtime = now;
} }
} }
} }
@@ -381,8 +381,8 @@ static size_t process_reply(HEADER *header, time_t now,
size_t plen; size_t plen;
/* If upstream is advertising a larger UDP packet size /* If upstream is advertising a larger UDP packet size
than we allow, trim it so that we don't get overlarge than we allow, trim it so that we don't get overlarge
requests for the client. We can't do this for signed packets. */ requests for the client. We can't do this for signed packets. */
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign) if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)) && !is_sign)
{ {
@@ -657,7 +657,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 == IPV6_PKTINFO) if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
{ {
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr; dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex; if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
@@ -667,19 +667,8 @@ void receive_query(struct listener *listen, time_t now)
/* enforce available interface configuration */ /* enforce available interface configuration */
if (if_index == 0) if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
return; !iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
#ifdef SIOCGIFNAME
ifr.ifr_ifindex = if_index;
if (ioctl(listen->fd, SIOCGIFNAME, &ifr) == -1)
return;
#else
if (!if_indextoname(if_index, ifr.ifr_name))
return;
#endif
if (!iface_check(listen->family, &dst_addr, &ifr, &if_index))
return; return;
if (listen->family == AF_INET && if (listen->family == AF_INET &&
@@ -918,19 +907,23 @@ static struct randfd *allocate_rfd(int family)
(eg) TFTP. Once we have a reasonable number, randomness should be OK */ (eg) TFTP. Once we have a reasonable number, randomness should be OK */
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
if (daemon->randomsocks[i].refcount == 0 && if (daemon->randomsocks[i].refcount == 0)
(daemon->randomsocks[i].fd = random_sock(family)) != -1)
{ {
if ((daemon->randomsocks[i].fd = random_sock(family)) == -1)
break;
daemon->randomsocks[i].refcount = 1; daemon->randomsocks[i].refcount = 1;
daemon->randomsocks[i].family = family; daemon->randomsocks[i].family = family;
return &daemon->randomsocks[i]; return &daemon->randomsocks[i];
} }
/* No free ones, grab an existing one */ /* No free ones or cannot get new socket, grab an existing one */
for (i = 0; i < RANDOM_SOCKS; i++) for (i = 0; i < RANDOM_SOCKS; i++)
{ {
int j = (i+finger) % RANDOM_SOCKS; int j = (i+finger) % RANDOM_SOCKS;
if (daemon->randomsocks[j].family == family && daemon->randomsocks[j].refcount != 0xffff) if (daemon->randomsocks[j].refcount != 0 &&
daemon->randomsocks[j].family == family &&
daemon->randomsocks[j].refcount != 0xffff)
{ {
finger = j; finger = j;
daemon->randomsocks[j].refcount++; daemon->randomsocks[j].refcount++;
@@ -1069,22 +1062,12 @@ void server_gone(struct server *server)
daemon->srv_save = NULL; daemon->srv_save = NULL;
} }
/* return unique random ids. /* return unique random ids. */
For signed packets we can't change the ID without breaking the static unsigned short get_id(unsigned int crc)
signing, so we keep the same one. In this case force is set, and this
routine degenerates into killing any conflicting forward record. */
static unsigned short get_id(int force, unsigned short force_id, unsigned int crc)
{ {
unsigned short ret = 0; unsigned short ret = 0;
if (force) do
{
struct frec *f = lookup_frec(force_id, crc);
if (f)
free_frec(f); /* free */
ret = force_id;
}
else do
ret = rand16(); ret = rand16();
while (lookup_frec(ret, crc)); while (lookup_frec(ret, crc));
+99 -111
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -28,15 +28,16 @@
main process. main process.
*/ */
#ifndef NO_FORK #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);
struct script_data struct script_data
{ {
unsigned char action, hwaddr_len, hwaddr_type; unsigned char action, hwaddr_len, hwaddr_type;
unsigned char clid_len, hostname_len, uclass_len, vclass_len; unsigned char clid_len, hostname_len, ed_len;
struct in_addr addr; struct in_addr addr, giaddr;
unsigned int remaining_time; unsigned int remaining_time;
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
unsigned int length; unsigned int length;
@@ -93,7 +94,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* kill daemon */ /* kill daemon */
send_event(event_fd, EVENT_DIE, 0); send_event(event_fd, EVENT_DIE, 0);
/* return error */ /* return error */
send_event(err_fd, EVENT_HUSER_ERR, errno);; send_event(err_fd, EVENT_HUSER_ERR, errno);
} }
_exit(0); _exit(0);
} }
@@ -101,7 +102,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* 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. This closes err_fd, so that
main process can return. */ main process can return. */
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)
close(max_fd); close(max_fd);
@@ -112,6 +113,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
struct script_data data; struct script_data data;
char *p, *action_str, *hostname = NULL; char *p, *action_str, *hostname = NULL;
unsigned char *buf = (unsigned char *)daemon->namebuff; unsigned char *buf = (unsigned char *)daemon->namebuff;
unsigned char *end, *alloc_buff = NULL;
int err = 0; int err = 0;
/* 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 */
@@ -130,16 +132,16 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* stringify MAC into dhcp_buff */ /* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff; p = daemon->dhcp_buff;
if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0) if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
p += sprintf(p, "%.2x-", data.hwaddr_type); p += sprintf(p, "%.2x-", data.hwaddr_type);
for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++) for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
{ {
p += sprintf(p, "%.2x", data.hwaddr[i]); p += sprintf(p, "%.2x", data.hwaddr[i]);
if (i != data.hwaddr_len - 1) if (i != data.hwaddr_len - 1)
p += sprintf(p, ":"); p += sprintf(p, ":");
} }
/* and CLID into packet */ /* and CLID into packet, avoid overwrite from bad data */
if (!read_write(pipefd[0], buf, data.clid_len, 1)) if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
continue; continue;
for (p = daemon->packet, i = 0; i < data.clid_len; i++) for (p = daemon->packet, i = 0; i < data.clid_len; i++)
{ {
@@ -150,17 +152,25 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
/* and expiry or length into dhcp_buff2 */ /* and expiry or length into dhcp_buff2 */
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
sprintf(daemon->dhcp_buff2, "%u ", data.length); sprintf(daemon->dhcp_buff2, "%u", data.length);
#else #else
sprintf(daemon->dhcp_buff2, "%lu ", (unsigned long)data.expires); sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
#endif #endif
if (!read_write(pipefd[0], buf, data.hostname_len + data.uclass_len + data.vclass_len, 1)) /* supplied data may just exceed normal buffer (unlikely) */
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
continue;
if (!read_write(pipefd[0], buf,
data.hostname_len + data.ed_len, 1))
continue; 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;
@@ -203,45 +213,40 @@ 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.vclass_len != 0)
{
buf[data.vclass_len - 1] = 0; /* don't trust zero-term */
/* cannot have = chars in env - truncate if found . */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv("DNSMASQ_VENDOR_CLASS", (char *)buf, &err);
buf += data.vclass_len;
}
if (data.uclass_len != 0)
{
unsigned char *end = buf + data.uclass_len;
buf[data.uclass_len - 1] = 0; /* don't trust zero-term */
for (i = 0; buf < end;)
{
size_t len = strlen((char *)buf) + 1;
if ((p = strchr((char *)buf, '=')))
*p = 0;
if (strlen((char *)buf) != 0)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i++);
my_setenv(daemon->dhcp_buff2, (char *)buf, &err);
}
buf += len;
}
}
sprintf(daemon->dhcp_buff2, "%u ", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
if (data.hostname_len != 0) if (data.hostname_len != 0)
{ {
char *dot;
hostname = (char *)buf; hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0; hostname[data.hostname_len - 1] = 0;
if (!canonicalise(hostname)) if (!legal_hostname(hostname))
hostname = NULL; 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_SUPPLIED_HOSTNAME", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
for (i = 0; buf; i++)
{
sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
}
if (data.giaddr.s_addr != 0)
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
if (data.action == ACTION_OLD_HOSTNAME && hostname) if (data.action == ACTION_OLD_HOSTNAME && hostname)
{ {
@@ -270,57 +275,58 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
static void my_setenv(const char *name, const char *value, int *error) static void my_setenv(const char *name, const char *value, int *error)
{ {
if (*error == 0) if (*error == 0 && setenv(name, value, 1) != 0)
{ *error = errno;
#if defined(HAVE_SOLARIS_NETWORK) && !defined(HAVE_SOLARIS_PRIVS)
/* old Solaris is missing setenv..... */
char *p;
if (!(p = malloc(strlen(name) + strlen(value) + 2)))
*error = ENOMEM;
else
{
strcpy(p, name);
strcat(p, "=");
strcat(p, value);
if (putenv(p) != 0)
*error = errno;
}
#else
if (setenv(name, value, 1) != 0)
*error = errno;
#endif
}
} }
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
{
unsigned char *next;
if (!buf || (buf == end))
return NULL;
for (next = buf; *next != 0; next++)
if (next == end)
return NULL;
if (next != buf)
{
char *p;
/* No "=" in value */
if ((p = strchr((char *)buf, '=')))
*p = 0;
my_setenv(env, (char *)buf, err);
}
return next + 1;
}
/* 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)
{ {
unsigned char *p; unsigned char *p;
size_t size; size_t size;
unsigned int i, hostname_len = 0, clid_len = 0, vclass_len = 0, uclass_len = 0; unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
/* no script */ /* no script */
if (daemon->helperfd == -1) if (daemon->helperfd == -1)
return; return;
if (lease->vendorclass) if (lease->extradata)
vclass_len = lease->vendorclass_len; ed_len = lease->extradata_len;
if (lease->userclass)
uclass_len = lease->userclass_len;
if (lease->clid) if (lease->clid)
clid_len = lease->clid_len; clid_len = lease->clid_len;
if (hostname) if (hostname)
hostname_len = strlen(hostname) + 1; hostname_len = strlen(hostname) + 1;
size = sizeof(struct script_data) + clid_len + vclass_len + uclass_len + hostname_len; size = sizeof(struct script_data) + clid_len + ed_len + hostname_len;
if (size > buf_size) if (size > buf_size)
{ {
struct script_data *new; struct script_data *new;
/* start with resonable size, will almost never need extending. */ /* start with reasonable size, will almost never need extending. */
if (size < sizeof(struct script_data) + 200) if (size < sizeof(struct script_data) + 200)
size = sizeof(struct script_data) + 200; size = sizeof(struct script_data) + 200;
@@ -336,24 +342,13 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
buf->hwaddr_len = lease->hwaddr_len; buf->hwaddr_len = lease->hwaddr_len;
buf->hwaddr_type = lease->hwaddr_type; buf->hwaddr_type = lease->hwaddr_type;
buf->clid_len = clid_len; buf->clid_len = clid_len;
buf->vclass_len = vclass_len; buf->ed_len = ed_len;
buf->uclass_len = uclass_len;
buf->hostname_len = hostname_len; buf->hostname_len = hostname_len;
buf->addr = lease->addr; buf->addr = lease->addr;
buf->giaddr = lease->giaddr;
memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len); memcpy(buf->hwaddr, lease->hwaddr, lease->hwaddr_len);
buf->interface[0] = 0; if (!indextoname(daemon->dhcpfd, lease->last_interface, buf->interface))
#ifdef HAVE_LINUX_NETWORK buf->interface[0] = 0;
if (lease->last_interface != 0)
{
struct ifreq ifr;
ifr.ifr_ifindex = lease->last_interface;
if (ioctl(daemon->dhcpfd, SIOCGIFNAME, &ifr) != -1)
strncpy(buf->interface, ifr.ifr_name, IF_NAMESIZE);
}
#else
if (lease->last_interface != 0)
if_indextoname(lease->last_interface, buf->interface);
#endif
#ifdef HAVE_BROKEN_RTC #ifdef HAVE_BROKEN_RTC
buf->length = lease->length; buf->length = lease->length;
@@ -368,23 +363,16 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
memcpy(p, lease->clid, clid_len); memcpy(p, lease->clid, clid_len);
p += clid_len; p += clid_len;
} }
if (vclass_len != 0) if (hostname_len != 0)
{ {
memcpy(p, lease->vendorclass, vclass_len); memcpy(p, hostname, hostname_len);
p += vclass_len; p += hostname_len;
} }
if (uclass_len != 0) if (ed_len != 0)
{ {
memcpy(p, lease->userclass, uclass_len); memcpy(p, lease->extradata, ed_len);
p += uclass_len; p += ed_len;
} }
/* substitute * for space */
for (i = 0; i < hostname_len; i++)
if ((daemon->options & OPT_LEASE_RO) && hostname[i] == ' ')
*(p++) = '*';
else
*(p++) = hostname[i];
bytes_in_buf = p - (unsigned char *)buf; bytes_in_buf = p - (unsigned char *)buf;
} }
-252
View File
@@ -1,252 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2007 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/>.
*/
/* Code in this file is based on contributions by John Volpe. */
#include "dnsmasq.h"
#ifdef HAVE_ISC_READER
#define MAXTOK 50
struct isc_lease {
char *name, *fqdn;
time_t expires;
struct in_addr addr;
struct isc_lease *next;
};
static struct isc_lease *leases = NULL;
static off_t lease_file_size = (off_t)0;
static ino_t lease_file_inode = (ino_t)0;
static int logged_lease = 0;
static int next_token (char *token, int buffsize, FILE * fp)
{
int c, count = 0;
char *cp = token;
while((c = getc(fp)) != EOF)
{
if (c == '#')
do { c = getc(fp); } while (c != '\n' && c != EOF);
if (c == ' ' || c == '\t' || c == '\n' || c == ';')
{
if (count)
break;
}
else if ((c != '"') && (count<buffsize-1))
{
*cp++ = c;
count++;
}
}
*cp = 0;
return count ? 1 : 0;
}
void load_dhcp(time_t now)
{
char *hostname = daemon->namebuff;
char token[MAXTOK], *dot;
struct in_addr host_address;
time_t ttd, tts;
FILE *fp;
struct isc_lease *lease, *tmp, **up;
struct stat statbuf;
if (stat(daemon->lease_file, &statbuf) == -1)
{
if (!logged_lease)
my_syslog(LOG_WARNING, _("failed to access %s: %s"), daemon->lease_file, strerror(errno));
logged_lease = 1;
return;
}
logged_lease = 0;
if ((statbuf.st_size <= lease_file_size) &&
(statbuf.st_ino == lease_file_inode))
return;
lease_file_size = statbuf.st_size;
lease_file_inode = statbuf.st_ino;
if (!(fp = fopen (daemon->lease_file, "r")))
{
my_syslog (LOG_ERR, _("failed to load %s: %s"), daemon->lease_file, strerror(errno));
return;
}
my_syslog (LOG_INFO, _("reading %s"), daemon->lease_file);
while ((next_token(token, MAXTOK, fp)))
{
if (strcmp(token, "lease") == 0)
{
hostname[0] = '\0';
ttd = tts = (time_t)(-1);
if (next_token(token, MAXTOK, fp) &&
(host_address.s_addr = inet_addr(token)) != (in_addr_t) -1)
{
if (next_token(token, MAXTOK, fp) && *token == '{')
{
while (next_token(token, MAXTOK, fp) && *token != '}')
{
if ((strcmp(token, "client-hostname") == 0) ||
(strcmp(token, "hostname") == 0))
{
if (next_token(hostname, MAXDNAME, fp))
if (!canonicalise(hostname))
{
*hostname = 0;
my_syslog(LOG_ERR, _("bad name in %s"), daemon->lease_file);
}
}
else if ((strcmp(token, "ends") == 0) ||
(strcmp(token, "starts") == 0))
{
struct tm lease_time;
int is_ends = (strcmp(token, "ends") == 0);
if (next_token(token, MAXTOK, fp) && /* skip weekday */
next_token(token, MAXTOK, fp) && /* Get date from lease file */
sscanf (token, "%d/%d/%d",
&lease_time.tm_year,
&lease_time.tm_mon,
&lease_time.tm_mday) == 3 &&
next_token(token, MAXTOK, fp) &&
sscanf (token, "%d:%d:%d:",
&lease_time.tm_hour,
&lease_time.tm_min,
&lease_time.tm_sec) == 3)
{
/* There doesn't seem to be a universally available library function
which converts broken-down _GMT_ time to seconds-in-epoch.
The following was borrowed from ISC dhcpd sources, where
it is noted that it might not be entirely accurate for odd seconds.
Since we're trying to get the same answer as dhcpd, that's just
fine here. */
static const int months [11] = { 31, 59, 90, 120, 151, 181,
212, 243, 273, 304, 334 };
time_t time = ((((((365 * (lease_time.tm_year - 1970) + /* Days in years since '70 */
(lease_time.tm_year - 1969) / 4 + /* Leap days since '70 */
(lease_time.tm_mon > 1 /* Days in months this year */
? months [lease_time.tm_mon - 2]
: 0) +
(lease_time.tm_mon > 2 && /* Leap day this year */
!((lease_time.tm_year - 1972) & 3)) +
lease_time.tm_mday - 1) * 24) + /* Day of month */
lease_time.tm_hour) * 60) +
lease_time.tm_min) * 60) + lease_time.tm_sec;
if (is_ends)
ttd = time;
else
tts = time; }
}
}
/* missing info? */
if (!*hostname)
continue;
if (ttd == (time_t)(-1))
continue;
/* We use 0 as infinite in ttd */
if ((tts != -1) && (ttd == tts - 1))
ttd = (time_t)0;
else if (difftime(now, ttd) > 0)
continue;
if ((dot = strchr(hostname, '.')))
{
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
{
my_syslog(LOG_WARNING,
_("Ignoring DHCP lease for %s because it has an illegal domain part"),
hostname);
continue;
}
*dot = 0;
}
for (lease = leases; lease; lease = lease->next)
if (hostname_isequal(lease->name, hostname))
{
lease->expires = ttd;
lease->addr = host_address;
break;
}
if (!lease && (lease = whine_malloc(sizeof(struct isc_lease))))
{
lease->expires = ttd;
lease->addr = host_address;
lease->fqdn = NULL;
lease->next = leases;
if (!(lease->name = whine_malloc(strlen(hostname)+1)))
free(lease);
else
{
leases = lease;
strcpy(lease->name, hostname);
if (daemon->domain_suffix &&
(lease->fqdn = whine_malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
{
strcpy(lease->fqdn, hostname);
strcat(lease->fqdn, ".");
strcat(lease->fqdn, daemon->domain_suffix);
}
}
}
}
}
}
}
fclose(fp);
/* prune expired leases */
for (lease = leases, up = &leases; lease; lease = tmp)
{
tmp = lease->next;
if (lease->expires != (time_t)0 && difftime(now, lease->expires) > 0)
{
*up = lease->next; /* unlink */
free(lease->name);
if (lease->fqdn)
free(lease->fqdn);
free(lease);
}
else
up = &lease->next;
}
/* remove all existing DHCP cache entries */
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)
{
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
}
}
#endif
+119 -82
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,12 +10,14 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
#ifdef HAVE_DHCP
static struct dhcp_lease *leases = NULL, *old_leases = NULL; static struct dhcp_lease *leases = NULL, *old_leases = NULL;
static int dns_dirty, file_dirty, leases_left; static int dns_dirty, file_dirty, leases_left;
@@ -40,14 +42,20 @@ void lease_init(time_t now)
initial state of the database. If leasefile-ro is initial state of the database. If leasefile-ro is
set without a script, we just do without any set without a script, we just do without any
lease database. */ lease database. */
if (!daemon->lease_change_command) #ifdef HAVE_SCRIPT
if (daemon->lease_change_command)
{ {
file_dirty = dns_dirty = 0; strcpy(daemon->dhcp_buff, daemon->lease_change_command);
return; strcat(daemon->dhcp_buff, " init");
leasestream = popen(daemon->dhcp_buff, "r");
} }
strcpy(daemon->dhcp_buff, daemon->lease_change_command); else
strcat(daemon->dhcp_buff, " init"); #endif
leasestream = popen(daemon->dhcp_buff, "r"); {
file_dirty = dns_dirty = 0;
return;
}
} }
else else
{ {
@@ -57,7 +65,7 @@ void lease_init(time_t now)
if (!leasestream) if (!leasestream)
die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE); die(_("cannot open or create lease file %s: %s"), daemon->lease_file, EC_FILE);
/* a+ mode lease pointer at end. */ /* a+ mode leaves pointer at end. */
rewind(leasestream); rewind(leasestream);
} }
@@ -98,19 +106,14 @@ void lease_init(time_t now)
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len); 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);
char *p;
/* unprotect spaces */
for (p = strchr(daemon->dhcp_buff, '*'); p; p = strchr(p, '*'))
*p = ' ';
lease_set_hostname(lease, daemon->dhcp_buff, daemon->domain_suffix, 0);
}
/* set these correctly: the "old" events are generated later from /* set these correctly: the "old" events are generated later from
the startup synthesised SIGHUP. */ the startup synthesised SIGHUP. */
lease->new = lease->changed = 0; lease->new = lease->changed = 0;
} }
#ifdef HAVE_SCRIPT
if (!daemon->lease_stream) if (!daemon->lease_stream)
{ {
int rc = 0; int rc = 0;
@@ -131,6 +134,7 @@ void lease_init(time_t now)
die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET); die(_("lease-init script returned exit code %s"), daemon->dhcp_buff, WEXITSTATUS(rc) + EC_INIT_OFFSET);
} }
} }
#endif
/* Some leases may have expired */ /* Some leases may have expired */
file_dirty = 0; file_dirty = 0;
@@ -151,9 +155,9 @@ void lease_update_from_configs(void)
lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) && lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
(config->flags & CONFIG_NAME) && (config->flags & CONFIG_NAME) &&
(!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr)) (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
lease_set_hostname(lease, config->hostname, daemon->domain_suffix, 1); lease_set_hostname(lease, config->hostname, 1);
else if ((name = host_from_dns(lease->addr))) else if ((name = host_from_dns(lease->addr)))
lease_set_hostname(lease, name, daemon->domain_suffix, 1); /* updates auth flag only */ lease_set_hostname(lease, name, 1); /* updates auth flag only */
} }
static void ourprintf(int *errp, char *format, ...) static void ourprintf(int *errp, char *format, ...)
@@ -171,7 +175,6 @@ void lease_update_file(time_t now)
struct dhcp_lease *lease; struct dhcp_lease *lease;
time_t next_event; time_t next_event;
int i, err = 0; int i, err = 0;
char *p;
if (file_dirty != 0 && daemon->lease_stream) if (file_dirty != 0 && daemon->lease_stream)
{ {
@@ -197,15 +200,8 @@ void lease_update_file(time_t now)
} }
ourprintf(&err, " %s ", inet_ntoa(lease->addr)); ourprintf(&err, " %s ", inet_ntoa(lease->addr));
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
/* substitute * for space: "*" is an illegal name, as is " " */
if (lease->hostname)
for (p = lease->hostname; *p; p++)
ourprintf(&err, "%c", *p == ' ' ? '*' : *p);
else
ourprintf(&err, "*");
ourprintf(&err, " ");
if (lease->clid && lease->clid_len != 0) if (lease->clid && lease->clid_len != 0)
{ {
for (i = 0; i < lease->clid_len - 1; i++) for (i = 0; i < lease->clid_len - 1; i++)
@@ -235,7 +231,7 @@ void lease_update_file(time_t now)
if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0) if (next_event == 0 || difftime(next_event, LEASE_RETRY + now) > 0.0)
next_event = LEASE_RETRY + now; next_event = LEASE_RETRY + now;
my_syslog(LOG_ERR, _("failed to write %s: %s (retry in %us)"), my_syslog(MS_DHCP | LOG_ERR, _("failed to write %s: %s (retry in %us)"),
daemon->lease_file, strerror(err), daemon->lease_file, strerror(err),
(unsigned int)difftime(next_event, now)); (unsigned int)difftime(next_event, now));
} }
@@ -254,8 +250,11 @@ void lease_update_dns(void)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
{ {
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires); if (lease->fqdn)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires); cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
} }
dns_dirty = 0; dns_dirty = 0;
@@ -412,11 +411,33 @@ void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
} }
void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int auth) static void kill_name(struct dhcp_lease *lease)
{
/* run script to say we lost our old name */
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease->old_hostname);
/* If we know the fqdn, pass that. The helper will derive the
unqualified name from it, free the unqulaified name here. */
if (lease->fqdn)
{
lease->old_hostname = lease->fqdn;
free(lease->hostname);
}
else
lease->old_hostname = lease->hostname;
lease->hostname = lease->fqdn = NULL;
}
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
{ {
struct dhcp_lease *lease_tmp; struct dhcp_lease *lease_tmp;
char *new_name = NULL, *new_fqdn = NULL; char *new_name = NULL, *new_fqdn = NULL;
if (lease->hostname && name && hostname_isequal(lease->hostname, name)) if (lease->hostname && name && hostname_isequal(lease->hostname, name))
{ {
lease->auth_name = auth; lease->auth_name = auth;
@@ -433,44 +454,47 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, char *suffix, int
if (name) if (name)
{ {
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next) if ((new_name = whine_malloc(strlen(name) + 1)))
if (lease_tmp->hostname && hostname_isequal(lease_tmp->hostname, name))
{
if (lease_tmp->auth_name && !auth)
return;
/* this shouldn't happen unless updates are very quick and the
script very slow, we just avoid a memory leak if it does. */
free(lease_tmp->old_hostname);
lease_tmp->old_hostname = lease_tmp->hostname;
lease_tmp->hostname = NULL;
if (lease_tmp->fqdn)
{
new_fqdn = lease_tmp->fqdn;
lease_tmp->fqdn = NULL;
}
break;
}
if (!new_name && (new_name = whine_malloc(strlen(name) + 1)))
strcpy(new_name, name);
if (suffix && !new_fqdn && (new_fqdn = whine_malloc(strlen(name) + strlen(suffix) + 2)))
{ {
strcpy(new_fqdn, name); char *suffix = get_domain(lease->addr);
strcat(new_fqdn, "."); strcpy(new_name, name);
strcat(new_fqdn, suffix); if (suffix && (new_fqdn = whine_malloc(strlen(new_name) + strlen(suffix) + 2)))
{
strcpy(new_fqdn, name);
strcat(new_fqdn, ".");
strcat(new_fqdn, suffix);
}
}
/* Depending on mode, we check either unqualified name or FQDN. */
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
{
if (daemon->options & OPT_DHCP_FQDN)
{
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
continue;
}
else
{
if (!new_name || !lease_tmp->hostname || !hostname_isequal(lease_tmp->hostname, new_name) )
continue;
}
if (lease_tmp->auth_name && !auth)
{
free(new_name);
free(new_fqdn);
return;
}
kill_name(lease_tmp);
break;
} }
} }
if (lease->hostname) if (lease->hostname)
{ kill_name(lease);
/* run script to say we lost our old name */
free(lease->old_hostname);
lease->old_hostname = lease->hostname;
}
free(lease->fqdn);
lease->hostname = new_name; lease->hostname = new_name;
lease->fqdn = new_fqdn; lease->fqdn = new_fqdn;
lease->auth_name = auth; lease->auth_name = auth;
@@ -506,6 +530,13 @@ int do_script_run(time_t now)
{ {
struct dhcp_lease *lease; struct dhcp_lease *lease;
#ifdef HAVE_DBUS
/* If we're going to be sending DBus signals, but the connection is not yet up,
delay everything until it is. */
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
return 0;
#endif
if (old_leases) if (old_leases)
{ {
lease = old_leases; lease = old_leases;
@@ -513,7 +544,7 @@ int do_script_run(time_t now)
/* If the lease still has an old_hostname, do the "old" action on that first */ /* If the lease still has an old_hostname, do the "old" action on that first */
if (lease->old_hostname) if (lease->old_hostname)
{ {
#ifndef NO_FORK #ifdef HAVE_SCRIPT
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
#endif #endif
free(lease->old_hostname); free(lease->old_hostname);
@@ -522,16 +553,18 @@ int do_script_run(time_t now)
} }
else else
{ {
#ifndef NO_FORK kill_name(lease);
queue_script(ACTION_DEL, lease, lease->hostname, now); #ifdef HAVE_SCRIPT
queue_script(ACTION_DEL, lease, lease->old_hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(ACTION_DEL, lease, lease->old_hostname);
#endif #endif
old_leases = lease->next; old_leases = lease->next;
free(lease->hostname); free(lease->old_hostname);
free(lease->fqdn);
free(lease->clid); free(lease->clid);
free(lease->vendorclass); free(lease->extradata);
free(lease->userclass);
free(lease); free(lease);
return 1; return 1;
@@ -542,7 +575,7 @@ int do_script_run(time_t now)
for (lease = leases; lease; lease = lease->next) for (lease = leases; lease; lease = lease->next)
if (lease->old_hostname) if (lease->old_hostname)
{ {
#ifndef NO_FORK #ifdef HAVE_SCRIPT
queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now); queue_script(ACTION_OLD_HOSTNAME, lease, lease->old_hostname, now);
#endif #endif
free(lease->old_hostname); free(lease->old_hostname);
@@ -554,23 +587,27 @@ int do_script_run(time_t now)
if (lease->new || lease->changed || if (lease->new || lease->changed ||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO))) (lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
{ {
#ifndef NO_FORK #ifdef HAVE_SCRIPT
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease, lease->hostname, now); queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname, now);
#endif
#ifdef HAVE_DBUS
emit_dbus_signal(lease->new ? ACTION_ADD : ACTION_OLD, lease,
lease->fqdn ? lease->fqdn : lease->hostname);
#endif #endif
lease->new = lease->changed = lease->aux_changed = 0; lease->new = lease->changed = lease->aux_changed = 0;
/* these are used for the "add" call, then junked, since they're not in the database */ /* this is used for the "add" call, then junked, since they're not in the database */
free(lease->vendorclass); free(lease->extradata);
lease->vendorclass = NULL; lease->extradata = NULL;
free(lease->userclass);
lease->userclass = NULL;
return 1; return 1;
} }
return 0; /* nothing to do */ return 0; /* nothing to do */
} }
#endif
+24 -6
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -248,6 +248,10 @@ static void log_write(void)
} }
} }
/* priority is one of LOG_DEBUG, LOG_INFO, LOG_NOTICE, etc. See sys/syslog.h.
OR'd to priority can be MS_TFTP, MS_DHCP, ... to be able to do log separation between
DNS, DHCP and TFTP services.
*/
void my_syslog(int priority, const char *format, ...) void my_syslog(int priority, const char *format, ...)
{ {
va_list ap; va_list ap;
@@ -256,10 +260,23 @@ void my_syslog(int priority, const char *format, ...)
char *p; char *p;
size_t len; size_t len;
pid_t pid = getpid(); pid_t pid = getpid();
char *func = "";
if ((LOG_FACMASK & priority) == MS_TFTP)
func = "-tftp";
else if ((LOG_FACMASK & priority) == MS_DHCP)
func = "-dhcp";
#ifdef LOG_PRI
priority = LOG_PRI(priority);
#else
/* Solaris doesn't have LOG_PRI */
priority &= LOG_PRIMASK;
#endif
if (log_stderr) if (log_stderr)
{ {
fprintf(stderr, "dnsmasq: "); fprintf(stderr, "dnsmasq%s: ", func);
va_start(ap, format); va_start(ap, format);
vfprintf(stderr, format, ap); vfprintf(stderr, format, ap);
va_end(ap); va_end(ap);
@@ -305,8 +322,9 @@ void my_syslog(int priority, const char *format, ...)
p = entry->payload; p = entry->payload;
if (!log_to_file) if (!log_to_file)
p += sprintf(p, "<%d>", priority | log_fac); p += sprintf(p, "<%d>", priority | log_fac);
p += sprintf(p, "%.15s dnsmasq[%d]: ", ctime(&time_now) + 4, (int)pid); p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
len = p - entry->payload; len = p - entry->payload;
va_start(ap, format); va_start(ap, format);
len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */ len += vsnprintf(p, MAX_MESSAGE - len, format, ap) + 1; /* include zero-terminator */
+85 -43
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -31,6 +31,7 @@
#endif #endif
static struct iovec iov; static struct iovec iov;
static u32 netlink_pid;
static void nl_err(struct nlmsghdr *h); static void nl_err(struct nlmsghdr *h);
static void nl_routechange(struct nlmsghdr *h); static void nl_routechange(struct nlmsghdr *h);
@@ -38,6 +39,7 @@ static void nl_routechange(struct nlmsghdr *h);
void netlink_init(void) void netlink_init(void)
{ {
struct sockaddr_nl addr; struct sockaddr_nl addr;
socklen_t slen = sizeof(addr);
addr.nl_family = AF_NETLINK; addr.nl_family = AF_NETLINK;
addr.nl_pad = 0; addr.nl_pad = 0;
@@ -59,48 +61,63 @@ void netlink_init(void)
} }
} }
if (daemon->netlinkfd == -1) if (daemon->netlinkfd == -1 ||
getsockname(daemon->netlinkfd, (struct sockaddr *)&addr, &slen) == 1)
die(_("cannot create netlink socket: %s"), NULL, EC_MISC); die(_("cannot create netlink socket: %s"), NULL, EC_MISC);
/* save pid assigned by bind() and retrieved by getsockname() */
netlink_pid = addr.nl_pid;
iov.iov_len = 200; iov.iov_len = 100;
iov.iov_base = safe_malloc(iov.iov_len); iov.iov_base = safe_malloc(iov.iov_len);
} }
static ssize_t netlink_recv(void) static ssize_t netlink_recv(void)
{ {
struct msghdr msg; struct msghdr msg;
struct sockaddr_nl nladdr;
ssize_t rc; ssize_t rc;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
while (1) while (1)
{ {
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_name = &nladdr;
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_flags = 0; msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
/* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
big buffer and pray in that case. */
if (rc == -1 && errno == EOPNOTSUPP) /* make buffer big enough */
if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
{ {
if (!expand_buf(&iov, 2000)) /* Very new Linux kernels return the actual size needed, older ones always return truncated size */
return -1; if ((size_t)rc == iov.iov_len)
break; {
if (expand_buf(&iov, rc + 100))
continue;
}
else
expand_buf(&iov, rc);
} }
if (rc == -1 || !(msg.msg_flags & MSG_TRUNC))
break;
if (!expand_buf(&iov, iov.iov_len + 100))
return -1;
}
/* finally, read it for real */ /* read it for real */
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR); msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR);
/* Make sure this is from the kernel */
if (rc == -1 || nladdr.nl_pid == 0)
break;
}
/* discard stuff which is truncated at this point (expand_buf() may fail) */
if (msg.msg_flags & MSG_TRUNC)
{
rc = -1;
errno = ENOMEM;
}
return rc; return rc;
} }
@@ -141,13 +158,20 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
while (1) while (1)
{ {
if ((len = netlink_recv()) == -1) if ((len = netlink_recv()) == -1)
return 0; {
if (errno == ENOBUFS)
{
sleep(1);
goto again;
}
return 0;
}
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_ERROR) if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid)
nl_err(h);
else if (h->nlmsg_seq != seq)
nl_routechange(h); /* May be multicast arriving async */ nl_routechange(h); /* May be multicast arriving async */
else if (h->nlmsg_type == NLMSG_ERROR)
nl_err(h);
else if (h->nlmsg_type == NLMSG_DONE) else if (h->nlmsg_type == NLMSG_DONE)
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@@ -208,10 +232,17 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
} }
} }
void netlink_multicast(void) void netlink_multicast(void)
{ {
ssize_t len; ssize_t len;
struct nlmsghdr *h; struct nlmsghdr *h;
int flags;
/* don't risk blocking reading netlink messages here. */
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
return;
if ((len = netlink_recv()) != -1) if ((len = netlink_recv()) != -1)
{ {
@@ -221,11 +252,15 @@ void netlink_multicast(void)
else else
nl_routechange(h); nl_routechange(h);
} }
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
} }
static void nl_err(struct nlmsghdr *h) static void nl_err(struct nlmsghdr *h)
{ {
struct nlmsgerr *err = NLMSG_DATA(h); struct nlmsgerr *err = NLMSG_DATA(h);
if (err->error != 0) if (err->error != 0)
my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error))); my_syslog(LOG_ERR, _("netlink returns error: %s"), strerror(-(err->error)));
} }
@@ -234,10 +269,10 @@ static void nl_err(struct nlmsghdr *h)
If this happens and we still have a DNS packet in the buffer, we re-send it. If this happens and we still have a DNS packet in the buffer, we re-send it.
This helps on DoD links, where frequently the packet which triggers dialling is This helps on DoD links, where frequently the packet which triggers dialling is
a DNS query, which then gets lost. By re-sending, we can avoid the lookup a DNS query, which then gets lost. By re-sending, we can avoid the lookup
failing. */ failing. Note that we only accept these messages from the kernel (pid == 0) */
static void nl_routechange(struct nlmsghdr *h) static void nl_routechange(struct nlmsghdr *h)
{ {
if (h->nlmsg_type == RTM_NEWROUTE && daemon->srv_save) if (h->nlmsg_pid == 0 && h->nlmsg_type == RTM_NEWROUTE)
{ {
struct rtmsg *rtm = NLMSG_DATA(h); struct rtmsg *rtm = NLMSG_DATA(h);
int fd; int fd;
@@ -245,17 +280,24 @@ static void nl_routechange(struct nlmsghdr *h)
if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK) if (rtm->rtm_type != RTN_UNICAST || rtm->rtm_scope != RT_SCOPE_LINK)
return; return;
if (daemon->srv_save->sfd) /* Force re-reading resolv file right now, for luck. */
fd = daemon->srv_save->sfd->fd; daemon->last_resolv = 0;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0, if (daemon->srv_save)
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send()); {
if (daemon->srv_save->sfd)
fd = daemon->srv_save->sfd->fd;
else if (daemon->rfd_save && daemon->rfd_save->refcount != 0)
fd = daemon->rfd_save->fd;
else
return;
while(sendto(fd, daemon->packet, daemon->packet_len, 0,
&daemon->srv_save->addr.sa, sa_len(&daemon->srv_save->addr)) == -1 && retry_send());
}
} }
} }
#endif #endif
+116 -63
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,14 +10,43 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
int iface_check(int family, struct all_addr *addr, #ifdef HAVE_LINUX_NETWORK
struct ifreq *ifr, int *indexp)
int indextoname(int fd, int index, char *name)
{
struct ifreq ifr;
if (index == 0)
return 0;
ifr.ifr_ifindex = index;
if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
return 0;
strncpy(name, ifr.ifr_name, IF_NAMESIZE);
return 1;
}
#else
int indextoname(int fd, int index, char *name)
{
if (index == 0 || !if_indextoname(index, name))
return 0;
return 1;
}
#endif
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
{ {
struct iname *tmp; struct iname *tmp;
int ret = 1; int ret = 1;
@@ -27,7 +56,6 @@ int iface_check(int family, struct all_addr *addr,
if (indexp) if (indexp)
{ {
#ifdef HAVE_BSD_BRIDGE
/* One form of bridging on BSD has the property that packets /* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address. 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 We allow these to be treated as aliases of another interface which does have
@@ -36,26 +64,25 @@ int iface_check(int family, struct all_addr *addr,
for (bridge = daemon->bridges; bridge; bridge = bridge->next) for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{ {
for (alias = bridge->alias; alias; alias = alias->next) for (alias = bridge->alias; alias; alias = alias->next)
if (strncmp(ifr->ifr_name, alias->iface, IF_NAMESIZE) == 0) if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
{ {
int newindex; int newindex;
if (!(newindex = if_nametoindex(bridge->iface))) if (!(newindex = if_nametoindex(bridge->iface)))
{ {
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr->ifr_name); my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
return 0; return 0;
} }
else else
{ {
*indexp = newindex; *indexp = newindex;
strncpy(ifr->ifr_name, bridge->iface, IF_NAMESIZE); strncpy(name, bridge->iface, IF_NAMESIZE);
break; break;
} }
} }
if (alias) if (alias)
break; break;
} }
#endif
} }
if (daemon->if_names || (addr && daemon->if_addrs)) if (daemon->if_names || (addr && daemon->if_addrs))
@@ -63,7 +90,7 @@ int iface_check(int family, struct all_addr *addr,
ret = 0; ret = 0;
for (tmp = daemon->if_names; tmp; tmp = tmp->next) for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0)) if (tmp->name && (strcmp(tmp->name, name) == 0))
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)
@@ -82,7 +109,7 @@ int iface_check(int family, struct all_addr *addr,
} }
for (tmp = daemon->if_except; tmp; tmp = tmp->next) for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr->ifr_name) == 0)) if (tmp->name && (strcmp(tmp->name, name) == 0))
ret = 0; ret = 0;
return ret; return ret;
@@ -92,7 +119,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
union mysockaddr *addr, struct in_addr netmask) union mysockaddr *addr, struct in_addr netmask)
{ {
struct irec *iface; struct irec *iface;
int fd; int fd, mtu = 0, loopback;
struct ifreq ifr; struct ifreq ifr;
int dhcp_ok = 1; int dhcp_ok = 1;
struct iname *tmp; struct iname *tmp;
@@ -103,16 +130,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
if (sockaddr_isequal(&iface->addr, addr)) if (sockaddr_isequal(&iface->addr, addr))
return 1; return 1;
#ifdef HAVE_LINUX_NETWORK
ifr.ifr_ifindex = if_index;
#endif
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 || if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
#ifdef HAVE_LINUX_NETWORK !indextoname(fd, if_index, ifr.ifr_name) ||
ioctl(fd, SIOCGIFNAME, &ifr) == -1 ||
#else
!if_indextoname(if_index, ifr.ifr_name) ||
#endif
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
{ {
if (fd != -1) if (fd != -1)
@@ -123,12 +142,17 @@ static int iface_allowed(struct irec **irecp, int if_index,
} }
return 0; return 0;
} }
loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
close(fd); close(fd);
/* If we are restricting the set of interfaces to use, make /* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */ sure that loopback interfaces are in that set. */
if (daemon->if_names && (ifr.ifr_flags & IFF_LOOPBACK)) if (daemon->if_names && loopback)
{ {
struct iname *lo; struct iname *lo;
for (lo = daemon->if_names; lo; lo = lo->next) for (lo = daemon->if_names; lo; lo = lo->next)
@@ -150,7 +174,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
} }
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, NULL)) !iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
return 1; return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -159,7 +183,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, NULL)) !iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
return 1; return 1;
#endif #endif
@@ -169,6 +193,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->addr = *addr; iface->addr = *addr;
iface->netmask = netmask; iface->netmask = netmask;
iface->dhcp_ok = dhcp_ok; iface->dhcp_ok = dhcp_ok;
iface->mtu = mtu;
iface->next = *irecp; iface->next = *irecp;
*irecp = iface; *irecp = iface;
return 1; return 1;
@@ -217,7 +242,6 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask); return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
} }
int enumerate_interfaces(void) int enumerate_interfaces(void)
{ {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
@@ -270,16 +294,35 @@ static int create_ipv6_listener(struct listener **link, int port)
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 || setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
!fix_fd(fd) || !fix_fd(fd) ||
!fix_fd(tcpfd) || !fix_fd(tcpfd) ||
#ifdef IPV6_RECVPKTINFO
setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1 ||
#else
setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
#endif
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 || bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
listen(tcpfd, 5) == -1 || listen(tcpfd, 5) == -1 ||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1) bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
return 0; return 0;
/* 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
return 0;
}
# else
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
return 0;
# endif
#else
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
return 0;
#endif
l = safe_malloc(sizeof(struct listener)); l = safe_malloc(sizeof(struct listener));
l->fd = fd; l->fd = fd;
l->tcpfd = tcpfd; l->tcpfd = tcpfd;
@@ -366,8 +409,11 @@ struct listener *create_bound_listeners(void)
{ {
struct listener *listeners = NULL; struct listener *listeners = NULL;
struct irec *iface; struct irec *iface;
int opt = 1; int rc, opt = 1;
#ifdef HAVE_IPV6
static int dad_count = 0;
#endif
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
{ {
struct listener *new = safe_malloc(sizeof(struct listener)); struct listener *new = safe_malloc(sizeof(struct listener));
@@ -377,6 +423,7 @@ struct listener *create_bound_listeners(void)
new->tftpfd = -1; new->tftpfd = -1;
new->tcpfd = -1; new->tcpfd = -1;
new->fd = -1; new->fd = -1;
listeners = new;
if (daemon->port != 0) if (daemon->port != 0)
{ {
@@ -396,27 +443,34 @@ struct listener *create_bound_listeners(void)
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET); die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
} }
#endif #endif
if (bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 || while(1)
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
{ {
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->addr))) != -1)
break;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL)) /* 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 (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL) &&
dad_count++ < DAD_WAIT)
{ {
close(new->tcpfd); sleep(1);
close(new->fd); continue;
free(new);
new = NULL;
} }
else
#endif #endif
{ break;
prettyprint_addr(&iface->addr, daemon->namebuff);
die(_("failed to bind listening socket for %s: %s"),
daemon->namebuff, EC_BADNET);
}
} }
else if (listen(new->tcpfd, 5) == -1)
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
{
prettyprint_addr(&iface->addr, daemon->namebuff);
die(_("failed to bind listening socket for %s: %s"),
daemon->namebuff, EC_BADNET);
}
if (listen(new->tcpfd, 5) == -1)
die(_("failed to listen on socket: %s"), NULL, EC_BADNET); die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
} }
@@ -434,15 +488,13 @@ struct listener *create_bound_listeners(void)
} }
#endif #endif
if (new)
listeners = new;
} }
return listeners; return listeners;
} }
/* return a UDP socket bound to a random port, have to coper 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)
{ {
@@ -452,10 +504,7 @@ int random_sock(int family)
{ {
union mysockaddr addr; union mysockaddr addr;
unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port; unsigned int ports_avail = 65536u - (unsigned short)daemon->min_port;
int i, tries = 3 * ports_avail; int tries = ports_avail < 30 ? 3 * ports_avail : 100;
if (tries > 100)
tries = 100;
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
addr.sa.sa_family = family; addr.sa.sa_family = family;
@@ -463,7 +512,7 @@ int random_sock(int family)
/* don't loop forever if all ports in use. */ /* don't loop forever if all ports in use. */
if (fix_fd(fd)) if (fix_fd(fd))
for (i = tries; i != 0; i--) while(tries--)
{ {
unsigned short port = rand16(); unsigned short port = rand16();
@@ -522,8 +571,8 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp)
return 0; return 0;
#if defined(SO_BINDTODEVICE) #if defined(SO_BINDTODEVICE)
if (strlen(intname) != 0 && if (intname[0] != 0 &&
setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, sizeof(intname)) == -1) setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1)
return 0; return 0;
#endif #endif
@@ -537,7 +586,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
/* when using random ports, servers which would otherwise use /* when using random ports, servers which would otherwise use
the INADDR_ANY/port0 socket have sfd set to NULL */ the INADDR_ANY/port0 socket have sfd set to NULL */
if (!daemon->osport) if (!daemon->osport && intname[0] == 0)
{ {
errno = 0; errno = 0;
@@ -622,8 +671,8 @@ void pre_allocate_sfds(void)
errno != 0 && errno != 0 &&
(daemon->options & OPT_NOWILD)) (daemon->options & OPT_NOWILD))
{ {
prettyprint_addr(&srv->addr, daemon->namebuff); prettyprint_addr(&srv->source_addr, daemon->namebuff);
if (strlen(srv->interface) != 0) if (srv->interface[0] != 0)
{ {
strcat(daemon->namebuff, " "); strcat(daemon->namebuff, " ");
strcat(daemon->namebuff, srv->interface); strcat(daemon->namebuff, srv->interface);
@@ -640,6 +689,10 @@ void check_servers(void)
struct server *new, *tmp, *ret = NULL; struct server *new, *tmp, *ret = NULL;
int port = 0; int port = 0;
/* interface may be new since startup */
if (!(daemon->options & OPT_NOWILD))
enumerate_interfaces();
for (new = daemon->servers; new; new = tmp) for (new = daemon->servers; new; new = tmp)
{ {
tmp = new->next; tmp = new->next;
@@ -698,7 +751,7 @@ void check_servers(void)
else if (!(new->flags & SERV_LITERAL_ADDRESS)) else if (!(new->flags & SERV_LITERAL_ADDRESS))
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2); my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2);
} }
else if (strlen(new->interface) != 0) else if (new->interface[0] != 0)
my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface); my_syslog(LOG_INFO, _("using nameserver %s#%d(via %s)"), daemon->namebuff, port, new->interface);
else else
my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port); my_syslog(LOG_INFO, _("using nameserver %s#%d"), daemon->namebuff, port);
+661 -293
View File
File diff suppressed because it is too large. Load diff
+191 -134
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -21,8 +21,14 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...); unsigned short class, char *format, ...);
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
static int extract_name(HEADER *header, size_t plen, unsigned char **pp, static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
char *name, int isExtract) char *name, int isExtract, int extrabytes)
{ {
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL; unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0; unsigned int j, l, hops = 0;
@@ -31,19 +37,47 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
if (isExtract) if (isExtract)
*cp = 0; *cp = 0;
while ((l = *p++)) while (1)
{ {
unsigned int label_type = l & 0xc0; unsigned int label_type;
if (!CHECK_LEN(header, p, plen, 1))
return 0;
if ((l = *p++) == 0)
/* end marker */
{
/* check that there are the correct no of bytes after the name */
if (!CHECK_LEN(header, p, plen, extrabytes))
return 0;
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
}
label_type = l & 0xc0;
if (label_type == 0xc0) /* pointer */ if (label_type == 0xc0) /* pointer */
{ {
if ((size_t)(p - (unsigned char *)header) >= plen) if (!CHECK_LEN(header, p, plen, 1))
return 0; return 0;
/* get offset */ /* get offset */
l = (l&0x3f) << 8; l = (l&0x3f) << 8;
l |= *p++; l |= *p++;
if (l >= plen)
return 0;
if (!p1) /* first jump, save location to go back to */ if (!p1) /* first jump, save location to go back to */
p1 = p; p1 = p;
@@ -74,7 +108,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
/* output is \[x<hex>/siz]. which is digs+9 chars */ /* output is \[x<hex>/siz]. which is digs+9 chars */
if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME) if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0; return 0;
if ((size_t)(p - (unsigned char *)header + ((count-1)>>3)) >= plen) if (!CHECK_LEN(header, p, plen, (count-1)>>3))
return 0; return 0;
*cp++ = '\\'; *cp++ = '\\';
@@ -98,12 +132,14 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
{ /* label_type = 0 -> label. */ { /* label_type = 0 -> label. */
if (cp - (unsigned char *)name + l + 1 >= MAXDNAME) if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
return 0; return 0;
if ((size_t)(p - (unsigned char *)header) >= plen) if (!CHECK_LEN(header, p, plen, l))
return 0; return 0;
for(j=0; j<l; j++, p++) for(j=0; j<l; j++, p++)
if (isExtract) if (isExtract)
{ {
if (legal_char(*p)) unsigned char c = *p;
if (isascii(c) && !iscntrl(c) && c != '.')
*cp++ = *p; *cp++ = *p;
else else
return 0; return 0;
@@ -132,26 +168,7 @@ static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
else if (*cp != 0 && *cp++ != '.') else if (*cp != 0 && *cp++ != '.')
retvalue = 2; retvalue = 2;
} }
if ((unsigned int)(p - (unsigned char *)header) >= plen)
return 0;
} }
if (isExtract)
{
if (cp != (unsigned char *)name)
cp--;
*cp = 0; /* terminate: lose final period */
}
else if (*cp != 0)
retvalue = 2;
if (p1) /* we jumped via compression */
*pp = p1;
else
*pp = p;
return retvalue;
} }
/* Max size of input string (for IPv6) is 75 chars.) */ /* Max size of input string (for IPv6) is 75 chars.) */
@@ -261,15 +278,17 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
return 0; return 0;
} }
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen) static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
{ {
while(1) while(1)
{ {
unsigned int label_type = (*ansp) & 0xc0; unsigned int label_type;
if ((unsigned int)(ansp - (unsigned char *)header) >= plen) if (!CHECK_LEN(header, ansp, plen, 1))
return NULL; return NULL;
label_type = (*ansp) & 0xc0;
if (label_type == 0xc0) if (label_type == 0xc0)
{ {
/* pointer for compression. */ /* pointer for compression. */
@@ -283,6 +302,9 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
/* Extended label type */ /* Extended label type */
unsigned int count; unsigned int count;
if (!CHECK_LEN(header, ansp, plen, 2))
return NULL;
if (((*ansp++) & 0x3f) != 1) if (((*ansp++) & 0x3f) != 1)
return NULL; /* we only understand bitstrings */ return NULL; /* we only understand bitstrings */
@@ -296,12 +318,17 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
else else
{ /* label type == 0 Bottom six bits is length */ { /* label type == 0 Bottom six bits is length */
unsigned int len = (*ansp++) & 0x3f; unsigned int len = (*ansp++) & 0x3f;
if (!ADD_RDLEN(header, ansp, plen, len))
return NULL;
if (len == 0) if (len == 0)
break; /* zero length label marks the end. */ break; /* zero length label marks the end. */
ansp += len;
} }
} }
if (!CHECK_LEN(header, ansp, plen, extrabytes))
return NULL;
return ansp; return ansp;
} }
@@ -313,12 +340,10 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
for (q = ntohs(header->qdcount); q != 0; q--) for (q = ntohs(header->qdcount); q != 0; q--)
{ {
if (!(ansp = skip_name(ansp, header, plen))) if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL; return NULL;
ansp += 4; /* class and type */ ansp += 4; /* class and type */
} }
if ((unsigned int)(ansp - (unsigned char *)header) > plen)
return NULL;
return ansp; return ansp;
} }
@@ -329,13 +354,12 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
if (!(ansp = skip_name(ansp, header, plen))) if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL; return NULL;
ansp += 8; /* type, class, TTL */ ansp += 8; /* type, class, TTL */
GETSHORT(rdlen, ansp); GETSHORT(rdlen, ansp);
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen) if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL; return NULL;
ansp += rdlen;
} }
return ansp; return ansp;
@@ -355,7 +379,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
for (q = ntohs(header->qdcount); q != 0; q--) for (q = ntohs(header->qdcount); q != 0; q--)
{ {
if (!extract_name(header, plen, &p, name, 1)) if (!extract_name(header, plen, &p, name, 1, 4))
return crc; /* bad packet */ return crc; /* bad packet */
for (p1 = (unsigned char *)name; *p1; p1++) for (p1 = (unsigned char *)name; *p1; p1++)
@@ -381,7 +405,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
} }
p += 4; p += 4;
if ((unsigned int)(p - (unsigned char *)header) > plen) if (!CHECK_LEN(header, p, plen, 0))
return crc; /* bad packet */ return crc; /* bad packet */
} }
@@ -393,12 +417,13 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
{ {
unsigned char *ansp = skip_questions(header, plen); unsigned char *ansp = skip_questions(header, plen);
/* if packet is malformed, just return as-is. */
if (!ansp) if (!ansp)
return 0; return plen;
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount), if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen))) header, plen)))
return 0; return plen;
/* restore pseudoheader */ /* restore pseudoheader */
if (pheader && ntohs(header->arcount) == 0) if (pheader && ntohs(header->arcount) == 0)
@@ -432,7 +457,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
{ {
for (i = ntohs(header->qdcount); i != 0; i--) for (i = ntohs(header->qdcount); i != 0; i--)
{ {
if (!(ansp = skip_name(ansp, header, plen))) if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL; return NULL;
GETSHORT(type, ansp); GETSHORT(type, ansp);
@@ -458,7 +483,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
for (i = 0; i < arcount; i++) for (i = 0; i < arcount; i++)
{ {
unsigned char *save, *start = ansp; unsigned char *save, *start = ansp;
if (!(ansp = skip_name(ansp, header, plen))) if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL; return NULL;
GETSHORT(type, ansp); GETSHORT(type, ansp);
@@ -466,9 +491,8 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
GETSHORT(class, ansp); GETSHORT(class, ansp);
ansp += 4; /* TTL */ ansp += 4; /* TTL */
GETSHORT(rdlen, ansp); GETSHORT(rdlen, ansp);
if ((size_t)(ansp + rdlen - (unsigned char *)header) > plen) if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL; return NULL;
ansp += rdlen;
if (type == T_OPT) if (type == T_OPT)
{ {
if (len) if (len)
@@ -508,7 +532,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
for (i = count; i != 0; i--) for (i = count; i != 0; i--)
{ {
if (!(p = skip_name(p, header, qlen))) if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -521,25 +545,34 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
struct doctor *doctor; struct doctor *doctor;
struct in_addr addr; struct in_addr addr;
/* alignment */ if (!CHECK_LEN(header, p, qlen, INADDRSZ))
return 0;
/* alignment */
memcpy(&addr, p, INADDRSZ); memcpy(&addr, p, INADDRSZ);
for (doctor = daemon->doctors; doctor; doctor = doctor->next) for (doctor = daemon->doctors; doctor; doctor = doctor->next)
if (is_same_net(doctor->in, addr, doctor->mask)) {
{ if (doctor->end.s_addr == 0)
addr.s_addr &= ~doctor->mask.s_addr; {
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr); if (!is_same_net(doctor->in, addr, doctor->mask))
/* Since we munged the data, the server it came from is no longer authoritative */ continue;
header->aa = 0; }
memcpy(p, &addr, INADDRSZ); else if (ntohl(doctor->in.s_addr) > ntohl(addr.s_addr) ||
break; ntohl(doctor->end.s_addr) < ntohl(addr.s_addr))
} continue;
addr.s_addr &= ~doctor->mask.s_addr;
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
/* Since we munged the data, the server it came from is no longer authoritative */
header->aa = 0;
memcpy(p, &addr, INADDRSZ);
break;
}
} }
p += rdlen; if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0; /* bad packet */
if ((size_t)(p - (unsigned char *)header) > qlen)
return 0; /* bad packet */
} }
return p; return p;
@@ -559,7 +592,7 @@ static int find_soa(HEADER *header, size_t qlen)
for (i = ntohs(header->nscount); i != 0; i--) for (i = ntohs(header->nscount); i != 0; i--)
{ {
if (!(p = skip_name(p, header, qlen))) if (!(p = skip_name(p, header, qlen, 10)))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -574,10 +607,10 @@ static int find_soa(HEADER *header, size_t qlen)
minttl = ttl; minttl = ttl;
/* MNAME */ /* MNAME */
if (!(p = skip_name(p, header, qlen))) if (!(p = skip_name(p, header, qlen, 0)))
return 0; return 0;
/* RNAME */ /* RNAME */
if (!(p = skip_name(p, header, qlen))) if (!(p = skip_name(p, header, qlen, 20)))
return 0; return 0;
p += 16; /* SERIAL REFRESH RETRY EXPIRE */ p += 16; /* SERIAL REFRESH RETRY EXPIRE */
@@ -585,13 +618,10 @@ static int find_soa(HEADER *header, size_t qlen)
if (ttl < minttl) if (ttl < minttl)
minttl = ttl; minttl = ttl;
} }
else else if (!ADD_RDLEN(header, p, qlen, rdlen))
p += rdlen;
if ((size_t)(p - (unsigned char *)header) > qlen)
return 0; /* bad packet */ return 0; /* bad packet */
} }
/* rewrite addresses in additioal section too */ /* rewrite addresses in additioal section too */
if (!do_doctor(p, ntohs(header->arcount), header, qlen)) if (!do_doctor(p, ntohs(header->arcount), header, qlen))
return 0; return 0;
@@ -633,7 +663,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
unsigned long cttl = ULONG_MAX, attl; unsigned long cttl = ULONG_MAX, attl;
namep = p; namep = p;
if (!extract_name(header, qlen, &p, name, 1)) if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -661,8 +691,8 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
{ {
unsigned char *tmp = namep; unsigned char *tmp = namep;
/* the loop body overwrites the original name, so get it back here. */ /* the loop body overwrites the original name, so get it back here. */
if (!extract_name(header, qlen, &tmp, name, 1) || if (!extract_name(header, qlen, &tmp, name, 1, 0) ||
!(res = extract_name(header, qlen, &p1, name, 0))) !(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(aqtype, p1); GETSHORT(aqtype, p1);
@@ -677,7 +707,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR)) if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
{ {
if (!extract_name(header, qlen, &p1, name, 1)) if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0; return 0;
if (aqtype == T_CNAME) if (aqtype == T_CNAME)
@@ -692,7 +722,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
} }
p1 = endrr; p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen) if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */ return 0; /* bad packet */
} }
} }
@@ -737,7 +767,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
for (j = ntohs(header->ancount); j != 0; j--) for (j = ntohs(header->ancount); j != 0; j--)
{ {
if (!(res = extract_name(header, qlen, &p1, name, 0))) if (!(res = extract_name(header, qlen, &p1, name, 0, 10)))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(aqtype, p1); GETSHORT(aqtype, p1);
@@ -763,14 +793,17 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
if (attl < cttl) if (attl < cttl)
cttl = attl; cttl = attl;
if (!extract_name(header, qlen, &p1, name, 1)) if (!extract_name(header, qlen, &p1, name, 1, 0))
return 0; return 0;
goto cname_loop1; goto cname_loop1;
} }
else else
{ {
found = 1; found = 1;
/* copy address into aligned storage */ /* copy address into aligned storage */
if (!CHECK_LEN(header, p1, qlen, addrlen))
return 0; /* bad packet */
memcpy(&addr, p1, addrlen); memcpy(&addr, p1, addrlen);
/* check for returned address in private space */ /* check for returned address in private space */
@@ -790,7 +823,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now)
} }
p1 = endrr; p1 = endrr;
if ((size_t)(p1 - (unsigned char *)header) > qlen) if (!CHECK_LEN(header, p1, qlen, 0))
return 0; /* bad packet */ return 0; /* bad packet */
} }
} }
@@ -839,7 +872,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY) if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
return 0; /* must be exactly one query. */ return 0; /* must be exactly one query. */
if (!extract_name(header, qlen, &p, name, 1)) if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -953,7 +986,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
for (i = ntohs(header->ancount); i != 0; i--) for (i = ntohs(header->ancount); i != 0; i--)
{ {
if (!extract_name(header, qlen, &p, name, 1)) if (!extract_name(header, qlen, &p, name, 1, 10))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -962,19 +995,25 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
GETSHORT(rdlen, p); GETSHORT(rdlen, p);
if (qclass == C_IN && qtype == T_A) if (qclass == C_IN && qtype == T_A)
for (baddrp = baddr; baddrp; baddrp = baddrp->next) {
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0) if (!CHECK_LEN(header, p, qlen, INADDRSZ))
{ return 0;
/* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */ for (baddrp = baddr; baddrp; baddrp = baddrp->next)
cache_start_insert(); if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG); {
cache_end_insert(); /* Found a bogus address. Insert that info here, since there no SOA record
to get the ttl from in the normal processing */
return 1; cache_start_insert();
} cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
cache_end_insert();
return 1;
}
}
p += rdlen; if (!ADD_RDLEN(header, p, qlen, rdlen))
return 0;
} }
return 0; return 0;
@@ -1073,6 +1112,18 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigne
return 1; return 1;
} }
static unsigned long crec_ttl(struct crec *crecp, time_t now)
{
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
return daemon->local_ttl;
return crecp->ttd - now;
}
/* return zero if we can't answer from cache, or packet size if we can */ /* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(HEADER *header, char *limit, size_t qlen, size_t answer_request(HEADER *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, time_t now) struct in_addr local_addr, struct in_addr local_netmask, time_t now)
@@ -1137,7 +1188,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
nameoffset = p - (unsigned char *)header; nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */ /* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1)) if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */ return 0; /* bad packet */
GETSHORT(qtype, p); GETSHORT(qtype, p);
@@ -1239,18 +1290,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
auth = 0; auth = 0;
if (!dryrun) if (!dryrun)
{ {
unsigned long ttl;
/* Return 0 ttl for DHCP entries, which might change
before the lease expires. */
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
record_source(daemon->addn_hosts, crecp->uid)); record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL,
T_PTR, C_IN, "d", cache_get_name(crecp))) T_PTR, C_IN, "d", cache_get_name(crecp)))
anscount++; anscount++;
} }
@@ -1283,18 +1327,41 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (qtype != type && qtype != T_ANY) if (qtype != type && qtype != T_ANY)
continue; continue;
/* Check for "A for A" queries */ /* Check for "A for A" queries; be rather conservative
if (qtype == T_A && (addr.addr.addr4.s_addr = inet_addr(name)) != (in_addr_t) -1) about what looks like dotted-quad. */
if (qtype == T_A)
{ {
ans = 1; char *cp;
if (!dryrun) unsigned int i, a;
int x;
for (cp = name, i = 0, a = 0; *cp; i++)
{ {
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL); if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, {
daemon->local_ttl, NULL, type, C_IN, "4", &addr)) i = 5;
anscount++; break;
}
a = (a << 8) + x;
if (*cp == '.')
cp++;
}
if (i == 4)
{
ans = 1;
if (!dryrun)
{
addr.addr.addr4.s_addr = htonl(a);
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
}
continue;
} }
continue;
} }
/* interface name stuff */ /* interface name stuff */
@@ -1357,8 +1424,9 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
{ {
if (!dryrun) if (!dryrun)
{ {
log_query(crecp->flags, name, NULL, record_source(daemon->addn_hosts, crecp->uid)); log_query(crecp->flags, name, NULL, record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, crecp->ttd - now, &nameoffset, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), &nameoffset,
T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache))) T_CNAME, C_IN, "d", cache_get_name(crecp->addr.cname.cache)))
anscount++; anscount++;
} }
@@ -1391,17 +1459,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
ans = 1; ans = 1;
if (!dryrun) if (!dryrun)
{ {
unsigned long ttl;
if (crecp->flags & (F_IMMORTAL | F_DHCP))
ttl = daemon->local_ttl;
else
ttl = crecp->ttd - now;
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr, log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
record_source(daemon->addn_hosts, crecp->uid)); record_source(crecp->uid));
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, ttl, NULL, type, C_IN, if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
crec_ttl(crecp, now), NULL, type, C_IN,
type == T_A ? "4" : "6", &crecp->addr)) type == T_A ? "4" : "6", &crecp->addr))
anscount++; anscount++;
} }
@@ -1529,7 +1591,6 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
crecp = NULL; crecp = NULL;
while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6))) while ((crecp = cache_find_by_name(crecp, rec->target, now, F_IPV4 | F_IPV6)))
{ {
unsigned long ttl;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
int type = crecp->flags & F_IPV4 ? T_A : T_AAAA; int type = crecp->flags & F_IPV4 ? T_A : T_AAAA;
#else #else
@@ -1538,12 +1599,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
if (crecp->flags & F_NEG) if (crecp->flags & F_NEG)
continue; continue;
if (crecp->flags & (F_IMMORTAL | F_DHCP)) if (add_resource_record(header, limit, NULL, rec->offset, &ansp,
ttl = daemon->local_ttl; crec_ttl(crecp, now), NULL, type, C_IN,
else
ttl = crecp->ttd - now;
if (add_resource_record(header, limit, NULL, rec->offset, &ansp, ttl, NULL, type, C_IN,
crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr)) crecp->flags & F_IPV4 ? "4" : "6", &crecp->addr))
addncount++; addncount++;
} }
+995 -374
View File
File diff suppressed because it is too large. Load diff
+62 -52
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -10,8 +10,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -45,15 +45,14 @@ void tftp_request(struct listener *listen, time_t now)
char *filename, *mode, *p, *end, *opt; char *filename, *mode, *p, *end, *opt;
struct sockaddr_in addr, peer; struct sockaddr_in addr, peer;
struct msghdr msg; struct msghdr msg;
struct cmsghdr *cmptr;
struct iovec iov; struct iovec iov;
struct ifreq ifr; struct ifreq ifr;
int is_err = 1, if_index = 0; int is_err = 1, if_index = 0, mtu = 0;
struct iname *tmp; struct iname *tmp;
struct tftp_transfer *transfer; struct tftp_transfer *transfer;
int port = daemon->start_tftp_port; /* may be zero to use ephemeral port */ int port = daemon->start_tftp_port; /* may be zero to use ephemeral 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 mtuflag = IP_PMTUDISC_DONT;
#endif #endif
union { union {
@@ -62,7 +61,7 @@ void tftp_request(struct listener *listen, time_t now)
char control[CMSG_SPACE(sizeof(struct in_pktinfo))]; char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
#elif defined(HAVE_SOLARIS_NETWORK) #elif defined(HAVE_SOLARIS_NETWORK)
char control[CMSG_SPACE(sizeof(unsigned int))]; char control[CMSG_SPACE(sizeof(unsigned int))];
#else #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))]; char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#endif #endif
} control_u; } control_u;
@@ -85,9 +84,15 @@ void tftp_request(struct listener *listen, time_t now)
return; return;
if (daemon->options & OPT_NOWILD) if (daemon->options & OPT_NOWILD)
addr = listen->iface->addr.in; {
addr = listen->iface->addr.in;
mtu = listen->iface->mtu;
}
else else
{ {
char name[IF_NAMESIZE];
struct cmsghdr *cmptr;
addr.sin_addr.s_addr = 0; addr.sin_addr.s_addr = 0;
#if defined(HAVE_LINUX_NETWORK) #if defined(HAVE_LINUX_NETWORK)
@@ -97,38 +102,37 @@ void tftp_request(struct listener *listen, time_t now)
addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst; addr.sin_addr = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex; if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
} }
if (!(ifr.ifr_ifindex = if_index) ||
ioctl(listen->tftpfd, SIOCGIFNAME, &ifr) == -1)
return;
#elif defined(HAVE_SOLARIS_NETWORK)
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
if_index = *((unsigned int *)CMSG_DATA(cmptr));
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF) #elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
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 == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr)); addr.sin_addr = *((struct in_addr *)CMSG_DATA(cmptr));
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF) else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
#ifdef HAVE_SOLARIS_NETWORK if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
if_index = *((unsigned int *)CMSG_DATA(cmptr));
#else
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
#endif #endif
if (if_index == 0 || !if_indextoname(if_index, ifr.ifr_name)) if (!indextoname(listen->tftpfd, if_index, name) ||
return; addr.sin_addr.s_addr == 0 ||
!iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index))
#endif
if (addr.sin_addr.s_addr == 0)
return;
if (!iface_check(AF_INET, (struct all_addr *)&addr.sin_addr,
&ifr, &if_index))
return; return;
/* allowed interfaces are the same as for DHCP */ /* allowed interfaces are the same as for DHCP */
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, name) == 0))
return; return;
strncpy(ifr.ifr_name, name, IF_NAMESIZE);
if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
} }
addr.sin_port = htons(port); addr.sin_port = htons(port);
@@ -161,7 +165,7 @@ void tftp_request(struct listener *listen, time_t now)
{ {
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 || if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(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, &mtu, sizeof(mtu)) == -1 || setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
#endif #endif
!fix_fd(transfer->sockfd)) !fix_fd(transfer->sockfd))
{ {
@@ -172,7 +176,7 @@ void tftp_request(struct listener *listen, time_t now)
addr.sin_port = htons(port); addr.sin_port = htons(port);
continue; continue;
} }
my_syslog(LOG_ERR, _("unable to get free port for TFTP")); my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
} }
free_transfer(transfer); free_transfer(transfer);
return; return;
@@ -195,42 +199,50 @@ void tftp_request(struct listener *listen, time_t now)
while ((opt = next(&p, end))) while ((opt = next(&p, end)))
{ {
if (strcasecmp(opt, "blksize") == 0 && if (strcasecmp(opt, "blksize") == 0)
(opt = next(&p, end)) &&
!(daemon->options & OPT_TFTP_NOBLOCK))
{ {
transfer->blocksize = atoi(opt); if ((opt = next(&p, end)) &&
if (transfer->blocksize < 1) !(daemon->options & OPT_TFTP_NOBLOCK))
transfer->blocksize = 1; {
if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4) transfer->blocksize = atoi(opt);
transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4; if (transfer->blocksize < 1)
transfer->opt_blocksize = 1; transfer->blocksize = 1;
transfer->block = 0; if (transfer->blocksize > (unsigned)daemon->packet_buff_sz - 4)
transfer->blocksize = (unsigned)daemon->packet_buff_sz - 4;
/* 32 bytes for IP, UDP and TFTP headers */
if (mtu != 0 && transfer->blocksize > (unsigned)mtu - 32)
transfer->blocksize = (unsigned)mtu - 32;
transfer->opt_blocksize = 1;
transfer->block = 0;
}
} }
else if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
if (strcasecmp(opt, "tsize") == 0 && next(&p, end) && !transfer->netascii)
{ {
transfer->opt_transize = 1; transfer->opt_transize = 1;
transfer->block = 0; transfer->block = 0;
} }
} }
/* cope with backslashes from windows boxen. */
while ((p = strchr(filename, '\\')))
*p = '/';
strcpy(daemon->namebuff, "/"); strcpy(daemon->namebuff, "/");
if (daemon->tftp_prefix) if (daemon->tftp_prefix)
{ {
if (daemon->tftp_prefix[0] == '/') if (daemon->tftp_prefix[0] == '/')
daemon->namebuff[0] = 0; daemon->namebuff[0] = 0;
strncat(daemon->namebuff, daemon->tftp_prefix, MAXDNAME); strncat(daemon->namebuff, daemon->tftp_prefix, (MAXDNAME-1) - strlen(daemon->namebuff));
if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/') if (daemon->tftp_prefix[strlen(daemon->tftp_prefix)-1] != '/')
strncat(daemon->namebuff, "/", MAXDNAME); strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
if (daemon->options & OPT_TFTP_APREF) if (daemon->options & OPT_TFTP_APREF)
{ {
size_t oldlen = strlen(daemon->namebuff); size_t oldlen = strlen(daemon->namebuff);
struct stat statbuf; struct stat statbuf;
strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), MAXDNAME); strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff));
strncat(daemon->namebuff, "/", MAXDNAME); strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
/* remove unique-directory if it doesn't exist */ /* remove unique-directory if it doesn't exist */
if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode)) if (stat(daemon->namebuff, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode))
@@ -248,8 +260,7 @@ void tftp_request(struct listener *listen, time_t now)
} }
else if (filename[0] == '/') else if (filename[0] == '/')
daemon->namebuff[0] = 0; daemon->namebuff[0] = 0;
strncat(daemon->namebuff, filename, MAXDNAME); strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
daemon->namebuff[MAXDNAME-1] = 0;
/* check permissions and open file */ /* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len))) if ((transfer->file = check_tftp_fileperm(&len)))
@@ -268,7 +279,7 @@ void tftp_request(struct listener *listen, time_t now)
free_transfer(transfer); free_transfer(transfer);
else else
{ {
my_syslog(LOG_INFO, _("TFTP sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr)); my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
transfer->next = daemon->tftp_trans; transfer->next = daemon->tftp_trans;
daemon->tftp_trans = transfer; daemon->tftp_trans = transfer;
} }
@@ -402,7 +413,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
*(q++) = *r; *(q++) = *r;
*q = 0; *q = 0;
} }
my_syslog(LOG_ERR, _("TFTP 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,
inet_ntoa(transfer->peer.sin_addr)); inet_ntoa(transfer->peer.sin_addr));
@@ -433,7 +444,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
/* don't complain about timeout when we're awaiting the last /* don't complain about timeout when we're awaiting the last
ACK, some clients never send it */ ACK, some clients never send it */
if (len != 0) if (len != 0)
my_syslog(LOG_ERR, _("TFTP failed sending %s to %s"), my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr)); transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
len = 0; len = 0;
} }
@@ -492,8 +503,7 @@ static ssize_t tftp_err(int err, char *packet, char *message, char *file)
mess->op = htons(OP_ERR); mess->op = htons(OP_ERR);
mess->err = htons(err); mess->err = htons(err);
ret += (snprintf(mess->message, 500, message, file, errstr) + 1); ret += (snprintf(mess->message, 500, message, file, errstr) + 1);
if (err != ERR_FNF) my_syslog(MS_TFTP | LOG_ERR, "%s", mess->message);
my_syslog(LOG_ERR, "TFTP %s", mess->message);
return ret; return ret;
} }
+107 -39
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2007 Simon Kelley /* dnsmasq is Copyright (c) 2000-2010 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
@@ -9,15 +9,13 @@
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
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/>.
*/ */
/* Some code in this file contributed by Rob Funk. */
/* The SURF random number generator was taken from djbdns-1.05, by /* The SURF random number generator was taken from djbdns-1.05, by
Daniel J Berstein, which is public domain. */ Daniel J Bernstein, which is public domain. */
#include "dnsmasq.h" #include "dnsmasq.h"
@@ -26,6 +24,9 @@
#include <sys/times.h> #include <sys/times.h>
#endif #endif
#ifdef LOCALEDIR
#include <idna.h>
#endif
#ifdef HAVE_ARC4RANDOM #ifdef HAVE_ARC4RANDOM
void rand_init(void) void rand_init(void)
@@ -97,48 +98,110 @@ unsigned short rand16(void)
#endif #endif
static int check_name(char *in)
int legal_char(char c)
{ {
/* check for legal char a-z A-Z 0-9 - /* remove trailing .
(also / , used for RFC2317 and _ used in windows queries
and space, for DNS-SD stuff) */
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '/' || c == '_' || c == ' ')
return 1;
return 0;
}
int canonicalise(char *s)
{
/* check for legal chars and remove trailing .
also fail empty string and label > 63 chars */ also fail empty string and label > 63 chars */
size_t dotgap = 0, l = strlen(s); size_t dotgap = 0, l = strlen(in);
char c; char c;
int nowhite = 0; int nowhite = 0;
if (l == 0 || l > MAXDNAME) return 0; if (l == 0 || l > MAXDNAME) return 0;
if (s[l-1] == '.') if (in[l-1] == '.')
{ {
if (l == 1) return 0; if (l == 1) return 0;
s[l-1] = 0; in[l-1] = 0;
} }
while ((c = *s)) for (; (c = *in); in++)
{ {
if (c == '.') if (c == '.')
dotgap = 0; dotgap = 0;
else if (!legal_char(c) || (++dotgap > MAXLABEL)) else if (++dotgap > MAXLABEL)
return 0; return 0;
else if (isascii(c) && iscntrl(c))
/* iscntrl only gives expected results for ascii */
return 0;
#ifndef LOCALEDIR
else if (!isascii(c))
return 0;
#endif
else if (c != ' ') else if (c != ' ')
nowhite = 1; nowhite = 1;
s++;
} }
return nowhite;
if (!nowhite)
return 0;
return 1;
}
/* Hostnames have a more limited valid charset than domain names
so check for legal char a-z A-Z 0-9 - _
Note that this may receive a FQDN, so only check the first label
for the tighter criteria. */
int legal_hostname(char *name)
{
char c;
if (!check_name(name))
return 0;
for (; (c = *name); name++)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_')
continue;
/* end of hostname part */
if (c == '.')
return 1;
return 0;
}
return 1;
}
char *canonicalise(char *in, int *nomem)
{
char *ret = NULL;
#ifdef LOCALEDIR
int rc;
#endif
if (nomem)
*nomem = 0;
if (!check_name(in))
return NULL;
#ifdef LOCALEDIR
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
{
if (ret)
free(ret);
if (nomem && (rc == IDNA_MALLOC_ERROR || rc == IDNA_DLOPEN_ERROR))
{
my_syslog(LOG_ERR, _("failed to allocate memory"));
*nomem = 1;
}
return NULL;
}
#else
if ((ret = whine_malloc(strlen(in)+1)))
strcpy(ret, in);
else if (nomem)
*nomem = 1;
#endif
return ret;
} }
unsigned char *do_rfc1035_name(unsigned char *p, char *sval) unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
@@ -346,14 +409,19 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
return i; return i;
} }
/* return 0 for no match, or (no matched octets) + 1 */
int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask) int memcmp_masked(unsigned char *a, unsigned char *b, int len, unsigned int mask)
{ {
int i; int i, count;
for (i = len - 1; i >= 0; i--, mask = mask >> 1) for (count = 1, i = len - 1; i >= 0; i--, mask = mask >> 1)
if (!(mask & 1) && a[i] != b[i]) if (!(mask & 1))
return 0; {
if (a[i] == b[i])
return 1; count++;
else
return 0;
}
return count;
} }
/* _note_ may copy buffer */ /* _note_ may copy buffer */