import of dnsmasq-2.23.tar.gz
diff --git a/CHANGELOG b/CHANGELOG
index dbeb5f0..335b854 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1444,3 +1444,103 @@
regression. Rob Holland and Roy Marples chased this one
down.
+version 2.23
+ Added a check to ensure that there cannot be more than one
+ dhcp-host option for any one IP address, even if the
+ addresses are assigned indirectly via a hostname and
+ /etc/hosts.
+
+ Include a "server identifier" in DHCPNAK replies, as
+ required by RFC2131.
+
+ Added method support for DBus
+ (http://www.freedesktop.org/Software/dbus)
+ This is a superior way to re-configure dnsmasq on-the-fly
+ with different upstream nameservers, as the host moves
+ between networks. DBus support must be enabled in
+ src/config.h and should be considered experimental at this
+ point. See DBus-interface for the specification of the
+ DBus method calls supported.
+
+ Added information to the FAQ about setting the DNS domain
+ in windows XP and Mac OS X, thanks to Rick Hull.
+
+ Added sanity check to resolv.conf polling code to cope
+ with backwards-moving clocks. Thanks to Leonardo Canducci
+ for help with this.
+
+ Handle so-called "A-for-A" queries, which are queries for
+ the address associated with a name which is already a
+ dotted-quad address. These should be handled by the
+ resolver code, but sometimes aren't and there's no point
+ in forwarding them.
+
+ Added "no-dhcp-interface" option to disable DHCP service
+ on an interface, whilst still providing DNS.
+
+ Fix format-string problem - config file names get passed
+ to fprintf as a format string, so % characters could cause
+ crashes. Thanks to Rob Holland for sleuthing that one.
+
+ Fixed multiple compiler warnings from gcc 4. Thanks to
+ Tim Cutts for the report.
+
+ Send the hostname option on DHCP offer messages as well as
+ DHCP ack messages. This is required by the Rio Digital
+ Audio Receiver. Thanks to Ron Frederick for the patch.
+
+ Add 'd' (for day) as a possible time multiplier in lease
+ time specifications. Thanks to Michael Deegan.
+
+ Make quoting suppress recognition of IP addresses, so
+ dhcp-option=66,1.2.3.4 now means something different to
+ dhcp-option=66,"1.2.3.4", which sets the option to a
+ string value. Thanks to Brian Macauley for the bug report.
+
+ Fixed the option parsing code to avoid segfaults from some
+ invalid configurations. Thanks to Wookey for spotting that one.
+
+ Provide information about which compile-time options were
+ selected, both in the log at startup and as part of the output
+ from dnsmasq --version. Thanks to Dirk Schenkewitz for
+ the suggestion.
+
+ Fix pathalogical behaviour when a broken client keeps sending
+ DHCPDISCOVER messages repeatedly and fast. Because dealing with
+ each of these takes a few seconds, (because of the ping) then a
+ queue of DHCP packets could build up. Now, the results of a ping
+ test are assumed to be valid for 30 seconds, so repeated waits are
+ not required. Thanks to Luca Landi for finding this.
+
+ Allow DHCPINFORM requests without hardware address
+ information. These are generated by some browsers, looking
+ for proxy information. Thanks to Stanley Jaddoe for the
+ bug report on that.
+
+ Add support of the "client FQDN" DHCP option. If present,
+ this is used to allow the client to tell dnsmasq its name,
+ in preference to (mis)using the hostname option. See
+ http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/\
+ draft-ietf-dhc-fqdn-option-10.txt
+ for details of the draft spec.
+
+ Added startup scripts for MacOS X Tiger/Panther to the
+ contrib collection. Thanks to Tim Cutts.
+
+ Tweak DHCP network selection so that clients which turn up
+ on our network in REBINDING state and with a lease for a
+ foreign network will get a NAK response. Thanks to Dan
+ Shechter for work on this and an initial patch and thanks
+ to Gyorgy Farkas for further testing.
+
+ Fix DNS query forwarding for empty queries and forward
+ queries even when the recursion-desired bit is clear. This
+ allows "dig +trace" to work. Problem report from Uwe
+ Gansert.
+
+ Added "const" declarations where appropriate, thanks to
+ Andreas Mohr for the patch.
+
+ Added --bootp-dynamic option and associated
+ functionality. Thanks to Josef Wolf for the suggestion.
+
diff --git a/DBus-interface b/DBus-interface
new file mode 100644
index 0000000..07bffd4
--- /dev/null
+++ b/DBus-interface
@@ -0,0 +1,94 @@
+DBus support must be enabled at compile-time and run-time. Ensure
+that src/config.h contains the line
+
+#define HAVE_DBUS.
+
+and that /etc/dnsmasq.conf contains the line
+
+enable-dbus
+
+Because dnsmasq can operate stand-alone from the DBus, and may need to provide
+service before the dbus daemon is available, it will continue to run
+if the DBus connection is not available at startup. The DBus will be polled
+every 250ms until a connection is established. Start of polling and final
+connection establishment are both logged. When dnsmasq establishes a
+connection to the dbus, it sends the signal "Up". Anything controlling
+the server settings in dnsmasq should re-invoke the SetServers method
+(q.v.) when it sees this signal. This allows dnsmasq to be restarted
+and avoids startup races with the provider of nameserver information.
+
+
+Dnsmasq provides one service on the DBus: uk.org.thekelleys.dnsmasq
+and a single object: /uk/org/thekelleys/dnsmasq
+
+Methods are of the form
+
+uk.org.thekelleys.<method>
+
+Available methods are:
+
+GetVersion
+----------
+Returns a string containing the version of dnsmasq running.
+
+ClearCache
+----------
+Returns nothing. Clears the domain name cache and re-reads
+/etc/hosts. The same as sending dnsmasq a HUP signal.
+
+SetServers
+----------
+Returns nothing. Takes a set of arguments representing the new
+upstream DNS servers to be used by dnsmasq. IPv4 addresses are
+represented as a UINT32 (in network byte order) and IPv6 addresses
+are represented as sixteen BYTEs (since there is no UINT128 type).
+Each server address may be followed by one or more STRINGS, which are
+the domains for which the preceding server should be used.
+
+Examples.
+
+UINT32: <address1>
+UNIT32: <address2>
+
+is equivalent to
+
+--server=<address1> --server=<address2>
+
+
+UINT32 <address1>
+UINT32 <address2>
+STRING "somedomain.com"
+
+is equivalent to
+
+--server=<address1> --server=/somedomain.com/<address2>
+
+UINT32 <address1>
+UINT32 <address2>
+STRING "somedomain.com"
+UINT32 <address3>
+STRING "anotherdomain.com"
+STRING "thirddomain.com"
+
+is equivalent to
+
+--server=<address1>
+--server=/somedomain.com/<address2>
+--server=/anotherdomain.com/thirddomain.com/<address3>
+
+Am IPv4 address of 0.0.0.0 is interpreted as "no address, local only",
+so
+
+UINT32: <0.0.0.0>
+STRING "local.domain"
+
+is equivalent to
+
+--local=/local.domain/
+
+
+Each call to SetServers completely replaces the set of servers
+specified by via the DBus, but it leaves any servers specified via the
+command line or /etc/dnsmasq.conf or /etc/resolv.conf alone.
+
+
diff --git a/FAQ b/FAQ
index c468de6..7383abb 100644
--- a/FAQ
+++ b/FAQ
@@ -39,18 +39,15 @@
Q: Will dnsmasq compile/run on non-Linux systems?
-A: Yes, there is explicit support for *BSD and Solaris.
+A: Yes, there is explicit support for *BSD and MacOS X. There are
+ start-up scripts for MacOS X Tiger and Panther in /contrib. Earlier
+ dnsmasq releases ran under Solaris, but that capability has
+ probably rotted. Dnsmasq will link with uclibc to provide small
+ binaries suitable for use in embedded systems such as
+ routers. (There's special code to support machines with flash
+ filesystems and no battery-backed RTC.)
For other systems, try altering the settings in config.h.
-
-A: Update for V2. Doing DHCP is rather non-portable, so there may be
- a few teething troubles. The initial 2.0 release is known to work
- on Linux 2.2.x, Linux 2.4.x and Linux 2.6.x with uclibc and glibc
- 2.3. It also works on FreeBSD 4.8. The crucial problem is sending
- raw packets, bypassing the IP stack. Dnsmasq contains code to do
- using PF_PACKET sockets (which is for Linux) and the Berkeley packet
- filter (which works with BSD). If you are trying to port to another
- Un*x, bpf is the most likeley candidate. See config.h
-
+
Q: My companies' nameserver knows about some names which aren't in the
public DNS. Even though I put it first in /etc/resolv.conf, it
dosen't work: dnsmasq seems not to use the nameservers in the order
@@ -88,7 +85,7 @@
Q: I'm running on BSD and dnsmasq won't accept long options on the
command line.
-A: Dnsmasq when built on BSD systems doesn't use GNU getopt by
+A: Dnsmasq when built on some BSD systems doesn't use GNU getopt by
default. You can either just use the single-letter options or
change config.h and the Makefile to use getopt-long. Note that
options in /etc/dnsmasq.conf must always be the long form,
@@ -105,13 +102,23 @@
"ping" will get a lookup failure, appending a dot to the end of the
hostname will fix things. (ie "ping myhost" fails, but "ping
myhost." works. The solution is to make sure that all your hosts
- have a domain set ("domain" in resolv.conf, the network applet in
- windows, or set a domain in your DHCP server). Any domain will do,
- but "localnet" is traditional. Now when you resolve "myhost" the
- resolver will attempt to look up "myhost.localnet" so you need to
- have dnsmasq reply to that name. The way to do that is to include
- the domain in each name on /etc/hosts and/or to use the
- --expand-hosts and --domain options.
+ have a domain set ("domain" in resolv.conf, or set a domain in
+ your DHCP server, see below fr Windows XP and Mac OS X).
+ Any domain will do, but "localnet" is traditional. Now when you
+ resolve "myhost" the resolver will attempt to look up
+ "myhost.localnet" so you need to have dnsmasq reply to that name.
+ The way to do that is to include the domain in each name on
+ /etc/hosts and/or to use the --expand-hosts and --domain options.
+
+Q: How do I set the DNS domain in Windows XP or MacOS X (ref: previous
+ question)?
+
+A: for XP, Control Panel > Network Connections > { Connection to gateway /
+ DNS } > Properties > { Highlight TCP/IP } > Properties > Advanced >
+ DNS Tab > DNS suffix for this connection:
+
+A: for OS X, System Preferences > Network > {Connection to gateway / DNS } >
+ Search domains:
Q: Can I get dnsmasq to save the contents of its cache to disk when
I shut my machine down and re-load when it starts again?
@@ -281,7 +288,9 @@
A: Yes, new releases of dnsmasq are always announced through
freshmeat.net, and they allow you to subcribe to email alerts when
- new versions of particular projects are released.
+ new versions of particular projects are released. New releases are
+ also announced in the dnsmasq-discuss mailing list, subscribe at
+ http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
Q: What does the dhcp-authoritative option do?
@@ -301,7 +310,7 @@
Q: My laptop has two network interfaces, a wired one and a wireless
one. I never use both interfaces at the same time, and I'd like the
same IP and configuration to be used irrespcetive of which
- interface is in use. How can I do that.
+ interface is in use. How can I do that?
A: By default, the identity of a machine is determined by using the
MAC address, which is associated with interface hardware. Once an
@@ -320,12 +329,11 @@
A: Yes, from version-2.21. The support is only available running under
Linux, on a kernel which provides the RT-netlink facility. All 2.4
and 2.6 kernels provide RT-netlink and it's an option in 2.2
- kernels. If dnsmasq is built under uclibc, even on Linux, then
- the support is not included.
+ kernels.
If a physical interface has more than one IP address or aliases
with extra IP addresses, then any dhcp-ranges corresponding to
- these addresses can be used for address allocation. So is and
+ these addresses can be used for address allocation. So if an
interface has addresses 192.168.1.0/24 and 192.68.2.0/24 and there
are DHCP ranges 192.168.1.100-192.168.1.200 and
192.168.2.100-192.168.2.200 then both ranges would be used for host
@@ -334,6 +342,21 @@
hosts allocated addresses on that subnet using dhcp-host options,
while anonymous hosts go on the other.
+
+Q: Dnsmasq sometimes logs "nameserver xxx.xxx.xxx.xxx refused
+ to do a recursive query" and DNS stops working. What's going on?
+
+A: Probably the nameserver is an authoritative nameserver for a
+ particular domain, but is not configured to answer general DNS
+ queries for an arbitrary domain. It is not suitable for use by
+ dnsmasq as an upstream server and should be removed from the
+ configuration. Note that if you have more than one upstream
+ nameserver configured dnsmasq will load-balance across them and
+ it may be some time before dnsmasq gets around to using a
+ particular nameserver. This means that a particular configuration
+ may work for sometime with a broken upstream nameserver
+ configuration.
+
diff --git a/Makefile b/Makefile
index 9dab602..46a531d 100644
--- a/Makefile
+++ b/Makefile
@@ -7,10 +7,10 @@
CFLAGS?= -O2
all :
- @cd $(SRC); $(MAKE) dnsmasq
+ $(MAKE) -f ../bld/Makefile -C $(SRC) dnsmasq
clean :
- rm -f *~ contrib/*/*~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
+ rm -f *~ bld/*~ contrib/*/*~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
install : all
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
diff --git a/bld/Makefile b/bld/Makefile
new file mode 100644
index 0000000..a394506
--- /dev/null
+++ b/bld/Makefile
@@ -0,0 +1,17 @@
+# Uncomment this on Solaris.
+#LIBS = -lsocket -lnsl
+
+CFLAGS ?= -O2
+PKG_CONFIG ?= pkg-config
+
+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
+
+.c.o: dnsmasq.h config.h
+ $(CC) $(CFLAGS) `../bld/pkg-wrapper $(PKG_CONFIG) --cflags dbus-1` $(RPM_OPT_FLAGS) -Wall -W -c $*.c
+
+dnsmasq : $(OBJS) dnsmasq.h config.h
+ $(CC) -o $@ $(OBJS) `../bld/pkg-wrapper $(PKG_CONFIG) --libs dbus-1` $(LIBS)
+
+
+
diff --git a/bld/pkg-wrapper b/bld/pkg-wrapper
new file mode 100755
index 0000000..694de19
--- /dev/null
+++ b/bld/pkg-wrapper
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+if grep -q "^\#.*define.*HAVE_DBUS" config.h ; then
+ exec $*
+fi
+
+
diff --git a/contrib/dnsmasq_MacOSX/DNSmasq b/contrib/dnsmasq_MacOSX/DNSmasq
new file mode 100755
index 0000000..6b62118
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/DNSmasq
@@ -0,0 +1,22 @@
+#!/bin/sh
+. /etc/rc.common
+
+StartService() {
+ if [ "${DNSMASQ:=-NO-}" = "-YES-" ] ; then
+ /usr/local/sbin/dnsmasq -q -n
+ fi
+}
+
+StopService() {
+ pid=`GetPID dnsmasq`
+ if [ $? -eq 0 ]; then
+ kill $pid
+ fi
+}
+
+RestartService() {
+ StopService "$@"
+ StartService "$@"
+}
+
+RunService "$1"
diff --git a/contrib/dnsmasq_MacOSX/README.rtf b/contrib/dnsmasq_MacOSX/README.rtf
new file mode 100644
index 0000000..da48411
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/README.rtf
@@ -0,0 +1,42 @@
+{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf100
+{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fnil\fcharset77 Monaco;}
+{\colortbl;\red255\green255\blue255;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww11120\viewh10100\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 1. If you've used DNSenabler, or if you're using Mac OS X Server, or if you have in any other way activated Mac OS X's built-in DHCP and/or DNS servers, disable them. This would usually involve checking that they are either set to -NO- or absent altogether in
+\f1 /etc/hostconfig
+\f0 . If you've never done anything to do with DNS or DHCP servers on a client version of MacOS X, you won't need to worry about this; it will already be configured for you.\
+\
+2. Add a configuration item to
+\f1 /etc/hostconfig
+\f0 as follows:\
+\
+
+\f1 DNSMASQ=-YES-
+\f0 \
+\
+3. Create a system-wide StartupItems directory for dnsmasq:\
+\
+
+\f1 sudo mkdir -p /Library/StartupItems/DNSmasq\
+
+\f0 \
+4. Copy the files
+\f1 DNSmasq
+\f0 and
+\f1 StartupParameters.plist
+\f0 into this directory, and make sure the former is executable:\
+\
+
+\f1 sudo cp DNSmasq StartupParameters.plist /Library/StartupItems/DNSmasq\
+sudo chmod 755 /Library/StartupItems/DNSmasq/DNSmasq\
+
+\f0 \
+5. Start the service:\
+\
+
+\f1 sudo /Library/StartupItems/DNSmasq/DNSmasq start\
+
+\f0 \cf0 \
+That should be all...}
\ No newline at end of file
diff --git a/contrib/dnsmasq_MacOSX/StartupParameters.plist b/contrib/dnsmasq_MacOSX/StartupParameters.plist
new file mode 100644
index 0000000..454bda0
--- /dev/null
+++ b/contrib/dnsmasq_MacOSX/StartupParameters.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Description</key>
+ <string>DNSmasq</string>
+ <key>OrderPreference</key>
+ <string>None</string>
+ <key>Provides</key>
+ <array>
+ <string>DNSmasq</string>
+ </array>
+ <key>Uses</key>
+ <array>
+ <string>Network</string>
+ </array>
+ </dict>
+</plist>
diff --git a/contrib/openvpn/README b/contrib/openvpn/README
new file mode 100644
index 0000000..dd99600
--- /dev/null
+++ b/contrib/openvpn/README
@@ -0,0 +1,44 @@
+The patch I have attached lets me get the behavior I wish out of
+dnsmasq. I also include my version of dhclient-enter-hooks as
+required for the switchover from pre-dnsmasq and dhclient.
+
+On 8/16/05, Joseph Tate <dragonstrider@gmail.com> wrote:
+> I'm trying to use dnsmasq on a laptop in order to facilitate openvpn
+> connections. As such, the only configuration option I'm concerned
+> about is a single server=3D/example.com/192.168.0.1 line.
+>
+> The way I currently have it set up is I modified dhclient to write its
+> resolv.conf data to /etc/resolv.conf.dhclient and configured
+> /etc/dnsmasq.conf to look there for its upstream dns servers.
+> /etc/resolv.conf is set to nameserver 127.0.0.1
+>
+> All of this works great. When I start the openvpn service, it the
+> routes, and queries to the domain in the server=3D line work just fine.
+>
+> The only problem is that the hostname for my system doesn't get set
+> correctly. With the resolv.conf data written to something other than
+> /etc/resolv.conf, the ifup scripts don't have a valid dns server to do
+> the ipcalc call to set the laptop's hostname. If I start dnsmasq
+> before the network comes up, something gets fubar'd. I'm not sure how
+> to describe it exactly, but network services are slow to load, and
+> restarting networking and dnsmasq doesn't solve the problem. Perhaps
+> dnsmasq is answering the dhcp request when the network starts?
+> Certainly not desired behavior.
+>
+> Anyway, my question: is there a way to have the best of both worlds?
+> DHCP requests to another server, and DNS lookups that work at all
+> times?
+>
+> My current best idea on how to solve this problem is modifying the
+> dnsmasq initscript to tweak /etc/dhclient-enter-hooks to change where
+> dhclient writes resolv.conf data, and fixing up /etc/resolv.conf on
+> the fly to set 127.0.0.1 to the nameserver (and somehow keep the
+> search domains intact), but I'm hoping that I'm just missing some key
+> piece of the puzzle and that this problem has been solved before. Any
+> insights?
+>
+> --
+> Joseph Tate
+> Personal e-mail: jtate AT dragonstrider DOT com
+> Web: http://www.dragonstrider.com
+>
diff --git a/contrib/openvpn/dhclient-enter-hooks b/contrib/openvpn/dhclient-enter-hooks
new file mode 100644
index 0000000..cb78e2a
--- /dev/null
+++ b/contrib/openvpn/dhclient-enter-hooks
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+function save_previous() {
+ if [ -e $1 -a ! -e $1.predhclient ]; then
+ mv $1 $1.predhclient
+ fi
+}
+
+function write_resolv_conf() {
+ RESOLVCONF=$1
+ if [ -n "$new_domain_name" ] || [ -n "$new_domain_name_servers" ]; then
+ save_previous $RESOLVCONF
+ echo '; generated by /etc/dhclient-enter-hooks' > $RESOLVCONF
+ if [ -n "$SEARCH" ]; then
+ echo search $SEARCH >> $RESOLVCONF
+ else
+ if [ -n "$new_domain_name" ]; then
+ echo search $new_domain_name >> $RESOLVCONF
+ fi
+ fi
+ chmod 644 $RESOLVCONF
+ for nameserver in $new_domain_name_servers; do
+ echo nameserver $nameserver >>$RESOLVCONF
+ done
+ fi
+}
+
+make_resolv_conf() {
+ write_resolv_conf /etc/resolv.conf
+}
diff --git a/contrib/openvpn/dnsmasq.patch b/contrib/openvpn/dnsmasq.patch
new file mode 100644
index 0000000..683507e
--- /dev/null
+++ b/contrib/openvpn/dnsmasq.patch
@@ -0,0 +1,61 @@
+--- dnsmasq-2.22/rpm/dnsmasq.rh 2005-03-24 09:51:18.000000000 -0500
++++ dnsmasq-2.22/rpm/dnsmasq.rh.new 2005-08-25 10:52:04.310568784 -0400
+@@ -2,7 +2,7 @@
+ #
+ # Startup script for the DNS caching server
+ #
+-# chkconfig: 2345 99 01
++# chkconfig: 2345 07 89
+ # description: This script starts your DNS caching server
+ # processname: dnsmasq
+ # pidfile: /var/run/dnsmasq.pid
+@@ -10,6 +10,25 @@
+ # Source function library.
+ . /etc/rc.d/init.d/functions
+
++function setup_dhclient_enter_hooks() {
++ if [ -f /etc/dhclient-enter-hooks ]; then
++ . /etc/dhclient-enter-hooks
++ cp /etc/resolv.conf /etc/resolv.conf.dnsmasq
++ cp /etc/dhclient-enter-hooks /etc/dhclient-enter-hooks.dnsmasq
++ sed -e 's/resolv\.conf$/resolv.conf.dhclient/' /etc/dhclient-enter-hooks.dnsmasq > /etc/dhclient-enter-hooks
++ sed -e 's/\(nameserver[ tab]\+\)[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/\1127.0.0.1/' /etc/resolv.conf.dnsmasq > /etc/resolv.conf
++ fi
++}
++
++function teardown_dhclient_enter_hooks() {
++ if [ -f /etc/dhclient-enter-hooks -a -f /etc/dhclient-enter-hooks.dnsmasq ]; then
++ if [ -f /etc/resolv.conf.dnsmasq ]; then
++ mv /etc/resolv.conf.dnsmasq /etc/resolv.conf
++ fi
++ mv /etc/dhclient-enter-hooks.dnsmasq /etc/dhclient-enter-hooks
++ fi
++}
++
+ # Source networking configuration.
+ . /etc/sysconfig/network
+
+@@ -24,7 +43,7 @@
+ MAILHOSTNAME=""
+ # change this line if you want dns to get its upstream servers from
+ # somewhere other that /etc/resolv.conf
+-RESOLV_CONF=""
++RESOLV_CONF="/etc/resolv.conf.dnsmasq"
+ # change this if you want dnsmasq to cache any "hostname" or "client-hostname" from
+ # a dhcpd's lease file
+@@ -54,6 +73,7 @@
+ case "$1" in
+ start)
+ echo -n "Starting dnsmasq: "
++ setup_dhclient_enter_hooks
+ daemon $dnsmasq $OPTIONS
+ RETVAL=$?
+ echo
+@@ -62,6 +82,7 @@
+ stop)
+ if test "x`pidof dnsmasq`" != x; then
+ echo -n "Shutting down dnsmasq: "
++ teardown_dhclient_enter_hooks
+ killproc dnsmasq
+ fi
+ RETVAL=$?
diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec
index a866afb..c9d7c9a 100644
--- a/dnsmasq-rh.spec
+++ b/dnsmasq-rh.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.22
+Version: 2.23
Release: 1
Copyright: GPL
Group: System Environment/Daemons
diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec
index a6d6602..f669a7e 100644
--- a/dnsmasq-suse.spec
+++ b/dnsmasq-suse.spec
@@ -5,7 +5,7 @@
###############################################################################
Name: dnsmasq
-Version: 2.22
+Version: 2.23
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
diff --git a/dnsmasq.8 b/dnsmasq.8
index 0f05f5a..f3d6dcf 100644
--- a/dnsmasq.8
+++ b/dnsmasq.8
@@ -48,7 +48,8 @@
.TP
.B \-k, --keep-in-foreground
Do not go into the background at startup but otherwise run as
-normal. This is intended for use when dnsmasq is run under daemontools.
+normal. This is intended for use when dnsmasq is run under daemontools
+or launchd.
.TP
.B \-d, --no-daemon
Debug mode: don't fork to the background, don't write a pid file,
@@ -120,6 +121,9 @@
.B --except-interface
options always override the others.
.TP
+.B \-2, --no-dhcp-interface=<interface name>
+Do not provide DHCP on the specified interface, but do provide DNS service.
+.TP
.B \-a, --listen-address=<ipaddr>
Listen on the given IP address(es). Both
.B \--interface
@@ -201,6 +205,12 @@
Don't read /etc/resolv.conf. Get upstream servers only from the command
line or the dnsmasq configuration file.
.TP
+.B \-1, --enable-dbus
+Allow dnsmasq configuration to be updated via DBus method calls. The
+configuration which can be changed is upstream DNS servers (and
+corressponding domains) and cache clear. Requires that dnsmasq has
+been built with DBus support.
+.TP
.B \-o, --strict-order
By default, dnsmasq will send queries to any of the upstream servers
it knows about and tries to favour servers to are known to
@@ -212,11 +222,11 @@
.TP
.B \-D, --domain-needed
Tells dnsmasq to never forward queries for plain names, without dots
-or domain parts, to upstream nameservers. If the name is not knowm
+or domain parts, to upstream nameservers. If the name is not known
from /etc/hosts or DHCP then a "not found" answer is returned.
.TP
.B \-S, --server=[/[<domain>]/[domain/]][<ipaddr>[#<port>][@<source>[#<port>]]]
-Specify IP address of upsream severs directly. Setting this flag does
+Specify IP address of upstream severs directly. Setting this flag does
not suppress reading of /etc/resolv.conf, use -R to do that. If one or
more
optional domains are given, that server is used only for those domains
@@ -302,13 +312,7 @@
weight and priority are zero. Be careful if transposing data from BIND
zone files: the port, weight and priority numbers are in a different
order. More than one SRV record for a given service/domain is allowed,
-all that match are returned. Specifying at least one
-.B --srv-host
-option also turns on replies to SOA queries for the
-domain given by the
-.B --domain
-option. The data in these is stereotyped, but is enough for resolvers
-to deduce that the domain is a valid one for resolving SRV records.
+all that match are returned.
.TP
.B \-Y, --txt-record=<name>[[,<text>],<text>]
Return a TXT DNS record. The value of TXT record is a set of strings,
@@ -390,9 +394,10 @@
.B --dhcp-host=00:20:e0:3b:13:af,ignore
This is
useful when there is another DHCP server on the network which should
-be used by some machines. The net:<network-id> parameter enables DHCP options just
-for this host in the same way as the the network-id in
-.B dhcp-range.
+be used by some machines. 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.
Ethernet addresses (but not client-ids) may have
wildcard bytes, so for example
.B --dhcp-host=00:20:e0:3b:13:*,ignore
@@ -434,7 +439,13 @@
large the data item is. It does this by examining the option number and/or the
value, but can be overriden by appending a single letter flag as follows:
b = one byte, s = two bytes, i = four bytes. This is mainly useful with
-encapsulated vendor class options (see below) where dnsmasq cannot determine data size from the option number.
+encapsulated vendor class options (see below) where dnsmasq cannot
+determine data size from the option number. Option data which
+consists solely of periods and digits will be interpreted by dnsmasq
+as an IP address, and inserted into an option as such. To force a
+literal string, use quotes. For instance when using option 66 to send
+a literal IP address as TFTP server name, it is necessary to do
+.B --dhcp-option=66,"1.2.3.4"
Encapsulated Vendor-class options may also be specified using
--dhcp-option: for instance
@@ -489,6 +500,12 @@
unknown leases from unknown hosts are not ignored. This allows new hosts
to get a lease without a tedious timeout under all circumstances.
.TP
+.B \-3, --bootp-dynamic
+Enable dynamic allocation of IP addresses to BOOTP clients. Use this
+with care, since each address allocated to a BOOTP client is leased
+forever, and therefore becomes permanently unavailable for re-use by
+other hosts.
+.TP
.B \-l, --dhcp-leasefile=<path>
Use the specified file to store DHCP lease information. If this option
is given but no dhcp-range option is given then dnsmasq version 1
@@ -502,7 +519,7 @@
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
for DHCP-configured hosts to claim. The intention is to constrain hostnames so that an untrusted host on the LAN cannot advertise it's name via dhcp as e.g. "microsoft.com" and capture traffic not meant for it. If no domain suffix is specified, then any DHCP hostname with a domain part (ie with a period) will be disallowed and logged. If suffix is specified, then hostnames with a domain part are allowed, provided the domain part matches the suffix. In addition, when a suffix is set then hostnames without a domain part have the suffix added as an optional domain part. Eg on my network I can set
-.B --domain-suffix=thekelleys.org.uk
+.B --domain=thekelleys.org.uk
and have a machine whose DHCP hostname is "laptop". The IP address for that machine is available from
.B dnsmasq
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
@@ -510,7 +527,7 @@
in /etc/resolv.conf (or equivalent).
.TP
.B \-E, --expand-hosts
-Add the domain-suffix 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.
.SH CONFIG FILE
At startup, dnsmasq reads
@@ -522,13 +539,13 @@
file consists of one option per line, exactly as the long options detailed
in the OPTIONS section but without the leading "--". Lines starting with # are comments and ignored. For
options which may only be specified once, the configuration file overrides
-the command line. Use the --conf-file option to specify a different
+the command line. Use the --conf-file (or -C) option to specify a different
configuration file. The conf-file option is also allowed in
configuration files, to include multiple configuration files. Only one
level of nesting is allowed. Quoting is allowed in a config file:
-between " quotes the special meaning of , and # is removed and the
-following escapes are allowed: \\\\ \\" \\t and \\n. The later two
-corresponding to newline and tab.
+between " quotes the special meanings of ,:. and # are removed and the
+following escapes are allowed: \\\\ \\" \\t \\a \\b \\r and \\n. The later
+corresponding to tab, bell, backspace, return and newline.
.SH NOTES
When it receives a SIGHUP,
.B dnsmasq
diff --git a/dnsmasq.conf.example b/dnsmasq.conf.example
index 9ac76e8..eafe7cb 100644
--- a/dnsmasq.conf.example
+++ b/dnsmasq.conf.example
@@ -10,7 +10,7 @@
# uneccessarily. If you have a dial-on-demand link they also stop
# these requests from bringing up the link uneccessarily.
-# Never forward plain names (with a dot or domain part)
+# Never forward plain names (without a dot or domain part)
domain-needed
# Never forward addresses in the non-routed address spaces.
bogus-priv
@@ -62,8 +62,9 @@
#user=
#group=
-# If you want dnsmasq to listen for requests only on specified interfaces
-# (and the loopback) give the name of the interface (eg eth0) here.
+# If you want dnsmasq to listen for DHCP and DNS requests only on
+# specified interfaces (and the loopback) give the name of the
+# interface (eg eth0) here.
# Repeat the line for more than one interface.
#interface=
# Or you can specify which interface _not_ to listen on
@@ -71,6 +72,10 @@
# Or which to listen on by address (remember to include 127.0.0.1 if
# you use this.)
#listen-address=
+# If you want dnsmasq to provide only DNS service on an interface,
+# configure it as shown above, and then use the following line to
+# disable DHCP on it.
+#no-dhcp-interface=
# On systems which support it, dnsmasq binds the wildcard address,
# even when it is listening on only some interfaces. It then discards
diff --git a/doc.html b/doc.html
index 735cae8..9fe979c 100644
--- a/doc.html
+++ b/doc.html
@@ -4,7 +4,7 @@
</HEAD>
<BODY BGCOLOR="WHITE">
<H1 ALIGN=center>Dnsmasq</H1>
-Dnsmasq is lightweight, easy to configure DNS forwarder and DHCP
+Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
server. It is designed to provide DNS and, optionally, DHCP, to a
small network. It can serve the names of local machines which are
not in the global DNS. The DHCP server integrates with the DNS
@@ -22,7 +22,7 @@
Mac OS X.
Dnsmasq is included in at least the following Linux distributions:
Gentoo, Debian, Slackware, Suse,
-Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, CoyoteLinux and
+Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l, CoyoteLinux and
Clarkconnect. It is also available as a FreeBSD port and is used in
Linksys wireless routers and the m0n0wall project.
<P>
@@ -103,8 +103,8 @@
</PRE>
<H2>Links.</H2>
-Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
-HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
+There is an article in German on dnsmasq at <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
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index fe87c0d..0000000
--- a/src/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# Uncomment this on Solaris.
-#LIBS = -lsocket -lnsl
-
-CFLAGS?= -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
-
-.c.o: dnsmasq.h config.h
- $(CC) $(CFLAGS) $(RPM_OPT_FLAGS) -Wall -W -c $*.c
-
-dnsmasq : $(OBJS) dnsmasq.h config.h
- $(CC) -o $@ $(OBJS) $(LIBS)
-
-
-
diff --git a/src/cache.c b/src/cache.c
index efd6aaf..79d7161 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -59,12 +59,12 @@
hash_table[i] = NULL;
}
-static struct crec **hash_bucket(unsigned char *name)
+static struct crec **hash_bucket(char *name)
{
unsigned int c, val = 0;
/* don't use tolower and friends here - they may be messed up by LOCALE */
- while((c = *name++))
+ while((c = (unsigned char) *name++))
if (c >= 'A' && c <= 'Z')
val += c + 'a' - 'A';
else
@@ -579,12 +579,12 @@
continue;
#ifdef HAVE_IPV6
- if (inet_pton(AF_INET, token, &addr) == 1)
+ if (inet_pton(AF_INET, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV4;
addrlen = INADDRSZ;
}
- else if (inet_pton(AF_INET6, token, &addr) == 1)
+ else if (inet_pton(AF_INET6, token, &addr) > 0)
{
flags = F_HOSTS | F_IMMORTAL | F_FORWARD | F_REVERSE | F_IPV6;
addrlen = IN6ADDRSZ;
@@ -902,9 +902,9 @@
else if (flags & F_QUERY)
{
unsigned int i;
- static struct {
+ static const struct {
unsigned int type;
- char *name;
+ const char * const name;
} typestr[] = {
{ 1, "A" },
{ 2, "NS" },
@@ -948,6 +948,9 @@
else
source = "cached";
+ if (strlen(name) == 0)
+ name = ".";
+
if ((flags & F_FORWARD) | (flags & F_NEG))
syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, addrbuff);
else if (flags & F_REVERSE)
diff --git a/src/config.h b/src/config.h
index 1797944..d491503 100644
--- a/src/config.h
+++ b/src/config.h
@@ -12,7 +12,7 @@
/* Author's email: simon@thekelleys.org.uk */
-#define VERSION "2.22"
+#define VERSION "2.23"
#define FTABSIZ 150 /* max number of outstanding requests */
#define MAX_PROCS 20 /* max no children for TCP requests */
@@ -50,6 +50,10 @@
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
+/* DBUS interface specifics */
+#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
+#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
+
/* Logfile stuff - change this to change the options and facility */
/* debug is true if the --no-daemon flag is given */
#ifdef LOG_PERROR
@@ -164,6 +168,11 @@
back to the Berkley API at runtime if netlink support is not
configured into the kernel.
+HAVE_DBUS
+ Define this if you want to link against libdbus, and have dnsmasq
+ define some methods to allow (re)configuration of the upstream DNS
+ servers via DBus.
+
NOTES:
For Linux you should define
HAVE_LINUX_IPV6_PROC
@@ -201,6 +210,8 @@
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
#endif
+#undef HAVE_DBUS
+
/* platform dependent options. */
/* Must preceed __linux__ since uClinux defines __linux__ too. */
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644
index 0000000..c1a9ac0
--- /dev/null
+++ b/src/dbus.c
@@ -0,0 +1,342 @@
+/* dnsmasq is Copyright (c) 2000-2005 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.
+
+ 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.
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_DBUS
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus.h>
+
+struct watch {
+ DBusWatch *watch;
+ struct watch *next;
+};
+
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+ struct daemon *daemon = data;
+ struct watch *w;
+
+ for (w = daemon->watches; w; w = w->next)
+ if (w->watch == watch)
+ return TRUE;
+
+ if (!(w = malloc(sizeof(struct watch))))
+ return FALSE;
+
+ w->watch = watch;
+ w->next = daemon->watches;
+ daemon->watches = w;
+
+ dbus_watch_set_data (watch, (void *)daemon, NULL);
+
+ return TRUE;
+}
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+ struct daemon *daemon = data;
+ struct watch **up, *w;
+
+ for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
+ if (w->watch == watch)
+ {
+ *up = w->next;
+ free(w);
+ }
+ else
+ up = &(w->next);
+}
+
+static void dbus_read_servers(struct daemon *daemon, DBusMessage *message)
+{
+ struct server *serv, *tmp, **up;
+ DBusMessageIter iter;
+ union mysockaddr addr, source_addr;
+ char *domain;
+
+ dbus_message_iter_init(message, &iter);
+
+ /* mark everything from DBUS */
+ for (serv = daemon->servers; serv; serv = serv->next)
+ if (serv->flags & SERV_FROM_DBUS)
+ serv->flags |= SERV_MARK;
+
+ while (1)
+ {
+ int skip = 0;
+
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32)
+ {
+ u32 a;
+
+ dbus_message_iter_get_basic(&iter, &a);
+ dbus_message_iter_next (&iter);
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+ source_addr.in.sin_len = addr.in.sin_len = sizeof(struct sockaddr_in);
+#endif
+ addr.in.sin_addr.s_addr = ntohl(a);
+ source_addr.in.sin_family = addr.in.sin_family = AF_INET;
+ addr.in.sin_port = htons(NAMESERVER_PORT);
+ source_addr.in.sin_addr.s_addr = INADDR_ANY;
+ source_addr.in.sin_port = htons(daemon->query_port);
+ }
+ else if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BYTE)
+ {
+ unsigned char p[sizeof(struct in6_addr)];
+ unsigned int i;
+
+ skip = 1;
+
+ for(i = 0; i < sizeof(struct in6_addr); i++)
+ {
+ dbus_message_iter_get_basic(&iter, &p[i]);
+ dbus_message_iter_next (&iter);
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
+ break;
+ }
+
+#ifndef HAVE_IPV6
+ syslog(LOG_WARNING, "attempt to set an IPv6 server address via DBus - no IPv6 support");
+#else
+ if (i == sizeof(struct in6_addr)-1)
+ {
+ memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
+#ifdef HAVE_SOCKADDR_SA_LEN
+ source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
+ addr.in6.sin6_port = htons(NAMESERVER_PORT);
+ source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = htonl(0);
+ source_addr.in6.sin6_addr = in6addr_any;
+ source_addr.in6.sin6_port = htons(daemon->query_port);
+ skip = 0;
+ }
+#endif
+ }
+ else
+ /* At the end */
+ break;
+
+ do {
+ if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING)
+ {
+ dbus_message_iter_get_basic(&iter, &domain);
+ dbus_message_iter_next (&iter);
+ }
+ else
+ domain = NULL;
+
+ if (!skip)
+ {
+ /* See if this is already there, and unmark */
+ for (serv = daemon->servers; serv; serv = serv->next)
+ if ((serv->flags & SERV_FROM_DBUS) &&
+ (serv->flags & SERV_MARK))
+ {
+ if (!(serv->flags & SERV_HAS_DOMAIN) && !domain)
+ {
+ serv->flags &= ~SERV_MARK;
+ break;
+ }
+ if ((serv->flags & SERV_HAS_DOMAIN) &&
+ domain &&
+ hostname_isequal(domain, serv->domain))
+ {
+ serv->flags &= ~SERV_MARK;
+ break;
+ }
+ }
+
+ if (!serv && (serv = malloc(sizeof (struct server))))
+ {
+ /* Not found, create a new one. */
+ if (domain)
+ serv->domain = malloc(strlen(domain)+1);
+ if (domain && !serv->domain)
+ {
+ free(serv);
+ serv = NULL;
+ }
+ else
+ {
+ serv->next = daemon->servers;
+ daemon->servers = serv;
+ serv->flags = SERV_FROM_DBUS;
+ serv->sfd = NULL;
+ if (domain)
+ {
+ strcpy(serv->domain, domain);
+ serv->flags |= SERV_HAS_DOMAIN;
+ }
+ }
+ }
+
+ if (serv)
+ {
+ if (source_addr.in.sin_family == AF_INET &&
+ addr.in.sin_addr.s_addr == 0 &&
+ serv->domain)
+ serv->flags |= SERV_NO_ADDR;
+ else
+ {
+ serv->flags &= ~SERV_NO_ADDR;
+ serv->addr = addr;
+ serv->source_addr = source_addr;
+ }
+ }
+ }
+ } while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+ }
+
+ /* unlink and free anything still marked. */
+ for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
+ {
+ tmp = serv->next;
+ if (serv->flags & SERV_MARK)
+ {
+ *up = serv->next;
+ free(serv);
+ }
+ else
+ up = &serv->next;
+ }
+
+}
+
+DBusHandlerResult message_handler (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ char *method = (char *)dbus_message_get_member(message);
+ struct daemon *daemon = (struct daemon *)user_data;
+
+ if (strcmp(method, "GetVersion") == 0)
+ {
+ char *v = VERSION;
+ DBusMessage *reply = dbus_message_new_method_return(message);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
+ dbus_connection_send (connection, reply, NULL);
+ dbus_message_unref (reply);
+ }
+ else if (strcmp(method, "SetServers") == 0)
+ {
+ syslog(LOG_INFO, "setting upstream servers from DBus");
+ dbus_read_servers(daemon, message);
+ check_servers(daemon);
+ }
+ else if (strcmp(method, "ClearCache") == 0)
+ clear_cache_and_reload(daemon, dnsmasq_time(daemon->uptime_fd));
+ else
+ return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+
+ return (DBUS_HANDLER_RESULT_HANDLED);
+
+}
+
+
+/* returns NULL or error message, may fail silently if dbus daemon not yet up. */
+char *dbus_init(struct daemon *daemon)
+{
+ DBusConnection *connection = NULL;
+ DBusObjectPathVTable dnsmasq_vtable = {NULL, &message_handler, NULL, NULL, NULL, NULL };
+ DBusError dbus_error;
+ DBusMessage *message;
+
+ dbus_error_init (&dbus_error);
+ if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
+ return NULL;
+
+ dbus_connection_set_exit_on_disconnect(connection, FALSE);
+ dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
+ NULL, (void *)daemon, NULL);
+ dbus_error_init (&dbus_error);
+ dbus_bus_request_name (connection, DNSMASQ_SERVICE, 0, &dbus_error);
+ if (dbus_error_is_set (&dbus_error))
+ return (char *)dbus_error.message;
+
+ if (!dbus_connection_register_object_path(connection, DNSMASQ_PATH,
+ &dnsmasq_vtable, daemon))
+ return "could not register a DBus message handler";
+
+ daemon->dbus = connection;
+
+ if ((message = dbus_message_new_signal(DNSMASQ_PATH, DNSMASQ_SERVICE, "Up")))
+ dbus_connection_send(connection, message, NULL);
+
+ return NULL;
+}
+
+
+int set_dbus_listeners(struct daemon *daemon, int maxfd,
+ fd_set *rset, fd_set *wset, fd_set *eset)
+{
+ struct watch *w;
+
+ for (w = daemon->watches; w; w = w->next)
+ if (dbus_watch_get_enabled(w->watch))
+ {
+ unsigned int flags = dbus_watch_get_flags(w->watch);
+ int fd = dbus_watch_get_fd(w->watch);
+
+ if (fd > maxfd)
+ maxfd = fd;
+
+ if (flags & DBUS_WATCH_READABLE)
+ FD_SET(fd, rset);
+
+ if (flags & DBUS_WATCH_WRITABLE)
+ FD_SET(fd, wset);
+
+ FD_SET(fd, eset);
+ }
+ return maxfd;
+}
+
+void check_dbus_listeners(struct daemon *daemon,
+ fd_set *rset, fd_set *wset, fd_set *eset)
+{
+ DBusConnection *connection = (DBusConnection *)daemon->dbus;
+ struct watch *w;
+
+ for (w = daemon->watches; w; w = w->next)
+ if (dbus_watch_get_enabled(w->watch))
+ {
+ unsigned int flags = 0;
+ int fd = dbus_watch_get_fd(w->watch);
+
+ if (FD_ISSET(fd, rset))
+ flags |= DBUS_WATCH_READABLE;
+
+ if (FD_ISSET(fd, wset))
+ flags |= DBUS_WATCH_WRITABLE;
+
+ if (FD_ISSET(fd, eset))
+ flags |= DBUS_WATCH_ERROR;
+
+ if (flags != 0)
+ dbus_watch_handle(w->watch, flags);
+ }
+
+ if (connection)
+ {
+ dbus_connection_ref (connection);
+ while (dbus_connection_dispatch (connection) == DBUS_DISPATCH_DATA_REMAINS);
+ dbus_connection_unref (connection);
+ }
+}
+
+#endif
diff --git a/src/dhcp.c b/src/dhcp.c
index 63392cb..ea013dc 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -56,7 +56,7 @@
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
- setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
+ setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 ||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
die("cannot create ICMP raw socket: %s.", NULL);
@@ -102,7 +102,7 @@
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
-
+ daemon->ping_results = NULL;
}
void dhcp_packet(struct daemon *daemon, time_t now)
@@ -191,6 +191,10 @@
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
+
+ for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
+ if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
+ return;
if (daemon->if_names || daemon->if_addrs)
{
@@ -333,6 +337,7 @@
#else
struct sockaddr_ll dest;
+ memset(&dest, 0, sizeof(dest));
dest.sll_family = AF_PACKET;
dest.sll_halen = ETHER_ADDR_LEN;
dest.sll_ifindex = iface_index;
@@ -495,7 +500,8 @@
}
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
- struct in_addr *addrp, unsigned char *hwaddr, struct dhcp_netid *netids)
+ struct in_addr *addrp, unsigned char *hwaddr,
+ struct dhcp_netid *netids, time_t now)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -528,12 +534,47 @@
if (!lease_find_by_addr(addr) &&
!config_find_by_address(daemon->dhcp_conf, addr))
{
+ struct ping_result *r, *victim = NULL;
+ int count;
+
+ /* check if we failed to ping addr sometime in the last
+ 30s. If so, assume the same situation still exists.
+ This avoids problems when a stupid client bangs
+ on us repeatedly. As a final check, is we did more
+ than six ping checks in the last 30s, we are in
+ high-load mode, so don't do any more. */
+ for (count = 0, r = daemon->ping_results; r; r = r->next)
+ if (difftime(now, r->time) > 30.0)
+ victim = r; /* old record */
+ else if (++count == 6 || r->addr.s_addr == addr.s_addr)
+ {
+ *addrp = addr;
+ return 1;
+ }
+
if (icmp_ping(daemon, addr))
- /* perturb address selection so that we are
+ /* address in use: perturb address selection so that we are
less likely to try this address again. */
c->addr_epoch++;
else
{
+ /* at this point victim may hold an expired record */
+ if (!victim)
+ {
+ if ((victim = malloc(sizeof(struct ping_result))))
+ {
+ victim->next = daemon->ping_results;
+ daemon->ping_results = victim;
+ }
+ }
+
+ /* record that this address is OK for 30s
+ without more ping checks */
+ if (victim)
+ {
+ victim->addr = addr;
+ victim->time = now;
+ }
*addrp = addr;
return 1;
}
@@ -548,7 +589,7 @@
}
if (netids)
- return address_allocate(context, daemon, addrp, hwaddr, NULL);
+ return address_allocate(context, daemon, addrp, hwaddr, NULL, now);
return 0;
}
@@ -590,14 +631,16 @@
return config;
}
- for (config = configs; config; config = config->next)
- if ((config->flags & CONFIG_HWADDR) &&
- config->wildcard_mask == 0 &&
- memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
- is_addr_in_context(context, config))
- return config;
-
+ if (hwaddr)
+ for (config = configs; config; config = config->next)
+ if ((config->flags & CONFIG_HWADDR) &&
+ config->wildcard_mask == 0 &&
+ memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0 &&
+ is_addr_in_context(context, config))
+ return config;
+
+
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
@@ -605,20 +648,21 @@
is_addr_in_context(context, config))
return config;
- for (config = configs; config; config = config->next)
- if ((config->flags & CONFIG_HWADDR) &&
- config->wildcard_mask != 0 &&
- is_addr_in_context(context, config))
- {
- int i;
- unsigned int mask = config->wildcard_mask;
- for (i = ETHER_ADDR_LEN - 1; i >= 0; i--, mask = mask >> 1)
- if (mask & 1)
- config->hwaddr[i] = hwaddr[i];
- if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
- return config;
- }
-
+ if (hwaddr)
+ for (config = configs; config; config = config->next)
+ if ((config->flags & CONFIG_HWADDR) &&
+ config->wildcard_mask != 0 &&
+ is_addr_in_context(context, config))
+ {
+ int i;
+ unsigned int mask = config->wildcard_mask;
+ for (i = ETHER_ADDR_LEN - 1; i >= 0; i--, mask = mask >> 1)
+ if (mask & 1)
+ config->hwaddr[i] = hwaddr[i];
+ if (memcmp(config->hwaddr, hwaddr, ETHER_ADDR_LEN) == 0)
+ return config;
+ }
+
return NULL;
}
@@ -632,6 +676,8 @@
unsigned char hwaddr[ETHER_ADDR_LEN];
struct dhcp_config *config, *configs = daemon->dhcp_conf;
int count = 0;
+
+ addr.s_addr = 0; /* eliminate warning */
if (!f)
{
@@ -731,7 +777,9 @@
{
/* Some people like to keep all static IP addresses in /etc/hosts.
This goes through /etc/hosts and sets static addresses for any DHCP config
- records which don't have an address and whose name matches. */
+ records which don't have an address and whose name matches.
+ We take care to maintain the invariant that any IP address can appear
+ in at most one dhcp-host. */
struct dhcp_config *config;
struct crec *crec;
@@ -742,8 +790,14 @@
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
(crec->flags & F_HOSTS))
{
- config->addr = crec->addr.addr.addr.addr4;
- config->flags |= CONFIG_ADDR;
+ if (config_find_by_address(configs, crec->addr.addr.addr.addr4))
+ syslog(LOG_WARNING, "duplicate IP address %s (%s) in dhcp-config directive",
+ inet_ntoa(crec->addr.addr.addr.addr4), config->hostname);
+ else
+ {
+ config->addr = crec->addr.addr.addr.addr4;
+ config->flags |= CONFIG_ADDR;
+ }
}
}
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 9cfbf8e..d545ba7 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -14,6 +14,27 @@
#include "dnsmasq.h"
+static char *compile_opts =
+#ifndef HAVE_IPV6
+"no-"
+#endif
+"IPv6 "
+#ifndef HAVE_GETOPT_LONG
+"no-"
+#endif
+"GNU-getopt "
+#ifdef HAVE_BROKEN_RTC
+"no-RTC "
+#endif
+#ifndef HAVE_ISC_READER
+"no-"
+#endif
+"ISC-leasefile "
+#ifndef HAVE_DBUS
+"no-"
+#endif
+"DBus";
+
static volatile int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd);
@@ -25,9 +46,7 @@
struct daemon *daemon;
int first_loop = 1;
int bind_fallback = 0;
- time_t resolv_changed = 0;
time_t now, last = 0;
- struct irec *interfaces;
struct sigaction sigact;
sigset_t sigmask;
struct iname *if_tmp;
@@ -65,7 +84,7 @@
sigaddset(&sigact.sa_mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
- daemon = read_opts(argc, argv);
+ daemon = read_opts(argc, argv, compile_opts);
if (daemon->edns_pktsz < PACKETSZ)
daemon->edns_pktsz = PACKETSZ;
@@ -83,7 +102,7 @@
die("ISC dhcpd integration not available: set HAVE_ISC_READER in src/config.h", NULL);
#endif
- if (!enumerate_interfaces(daemon, &interfaces, NULL, NULL))
+ if (!enumerate_interfaces(daemon, &daemon->interfaces, NULL, NULL))
die("failed to find list of interfaces: %s", NULL);
if (!(daemon->options & OPT_NOWILD) &&
@@ -95,7 +114,7 @@
if (daemon->options & OPT_NOWILD)
{
- daemon->listeners = create_bound_listeners(interfaces, daemon->port);
+ daemon->listeners = create_bound_listeners(daemon->interfaces, daemon->port);
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
@@ -104,18 +123,8 @@
for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
if (!if_tmp->used)
{
- char *addrbuff = daemon->namebuff;
-#ifdef HAVE_IPV6
- if (if_tmp->addr.sa.sa_family == AF_INET)
- inet_ntop(AF_INET, &if_tmp->addr.in.sin_addr,
- addrbuff, ADDRSTRLEN);
- else
- inet_ntop(AF_INET6, &if_tmp->addr.in6.sin6_addr,
- addrbuff, ADDRSTRLEN);
-#else
- strcpy(addrbuff, inet_ntoa(if_tmp->addr.in.sin_addr));
-#endif
- die("no interface with address %s", addrbuff);
+ prettyprint_addr(&if_tmp->addr, daemon->namebuff);
+ die("no interface with address %s", daemon->namebuff);
}
}
@@ -144,6 +153,20 @@
lease_init(daemon, now);
}
+ if (daemon->options & OPT_DBUS)
+#ifdef HAVE_DBUS
+ {
+ char *err;
+ daemon->dbus = NULL;
+ daemon->watches = NULL;
+ if ((err = dbus_init(daemon)))
+ die("DBus error: %s", err);
+ }
+#else
+ if (daemon->options & OPT_DBUS)
+ die("DBus not available: set HAVE_DBUS in src/config.h", NULL);
+#endif
+
/* If query_port is set then create a socket now, before dumping root
for use to access nameservers without more specific source addresses.
This allows query_port to be a low port */
@@ -174,14 +197,19 @@
if (!(daemon->options & OPT_DEBUG))
{
FILE *pidfile;
- struct serverfd *serverfdp;
- struct listener *listener;
struct passwd *ent_pw;
- int i;
-
+ fd_set test_set;
+ int maxfd, i;
+
+ FD_ZERO(&test_set);
+ maxfd = set_dns_listeners(daemon, &test_set, -1);
+#ifdef HAVE_DBUS
+ maxfd = set_dbus_listeners(daemon, maxfd, &test_set, &test_set, &test_set);
+#endif
+
/* The following code "daemonizes" the process.
See Stevens section 12.4 */
-
+
#ifndef NO_FORK
if (!(daemon->options & OPT_NO_FORK))
{
@@ -209,28 +237,19 @@
for (i=0; i<64; i++)
{
- for (listener = daemon->listeners; listener; listener = listener->next)
- if (listener->fd == i || listener->tcpfd == i)
- break;
- if (listener)
- continue;
-
#ifdef HAVE_BROKEN_RTC
if (i == daemon->uptime_fd)
continue;
#endif
-
+
if (daemon->dhcp &&
(i == daemon->lease_fd ||
i == daemon->dhcpfd ||
i == daemon->dhcp_raw_fd ||
i == daemon->dhcp_icmp_fd))
continue;
-
- for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
- if (serverfdp->fd == i)
- break;
- if (serverfdp)
+
+ if (i <= maxfd && FD_ISSET(i, &test_set))
continue;
close(i);
@@ -261,7 +280,19 @@
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, daemon->cachesize);
else
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
-
+
+ syslog(LOG_INFO, "compile time options: %s", compile_opts);
+
+#ifdef HAVE_DBUS
+ if (daemon->options & OPT_DBUS)
+ {
+ if (daemon->dbus)
+ syslog(LOG_INFO, "DBus support enabled: connected to system bus");
+ else
+ syslog(LOG_INFO, "DBus support enabled: bus connection pending");
+ }
+#endif
+
if (bind_fallback)
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
@@ -304,28 +335,19 @@
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
syslog(LOG_WARNING, "running as root");
- check_servers(daemon, interfaces);
+ check_servers(daemon);
while (sigterm == 0)
{
- fd_set rset;
+ fd_set rset, wset, eset;
if (sighup)
{
- cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
- if (daemon->dhcp)
- {
- if (daemon->options & OPT_ETHERS)
- dhcp_read_ethers(daemon);
- dhcp_update_configs(daemon->dhcp_conf);
- lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
- lease_update_file(0, now);
- lease_update_dns(daemon);
- }
+ clear_cache_and_reload(daemon, now);
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
{
reload_servers(daemon->resolv_files->name, daemon);
- check_servers(daemon, interfaces);
+ check_servers(daemon);
}
sighup = 0;
}
@@ -349,11 +371,15 @@
}
FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_ZERO(&eset);
if (!first_loop)
{
- int maxfd = set_dns_listeners(daemon, &rset, 0);
-
+ int maxfd = set_dns_listeners(daemon, &rset, -1);
+#ifdef HAVE_DBUS
+ maxfd = set_dbus_listeners(daemon, maxfd, &rset, &wset, &eset);
+#endif
if (daemon->dhcp)
{
FD_SET(daemon->dhcpfd, &rset);
@@ -361,25 +387,56 @@
maxfd = daemon->dhcpfd;
}
+ /* Whilst polling for the dbus, wake every quarter second */
#ifdef HAVE_PSELECT
- if (pselect(maxfd+1, &rset, NULL, NULL, NULL, &sigmask) < 0)
- FD_ZERO(&rset); /* rset otherwise undefined after error */
+ {
+ struct timespec *tp = NULL;
+#ifdef HAVE_DBUS
+ struct timespec t;
+ if ((daemon->options & OPT_DBUS) && !daemon->dbus)
+ {
+ tp = &t;
+ tp->tv_sec = 0;
+ tp->tv_nsec = 250000000;
+ }
+#endif
+ if (pselect(maxfd+1, &rset, &wset, &eset, tp, &sigmask) < 0)
+ {
+ /* otherwise undefined after error */
+ FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
+ }
+ }
#else
{
sigset_t save_mask;
+ struct timeval *tp = NULL;
+#ifdef HAVE_DBUS
+ struct timeval t;
+ if ((daemon->options & OPT_DBUS) && !daemon->dbus)
+ {
+ tp = &t;
+ tp->tv_sec = 0;
+ tp->tv_usec = 250000;
+ }
+#endif
sigprocmask(SIG_SETMASK, &sigmask, &save_mask);
- if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0)
- FD_ZERO(&rset); /* rset otherwise undefined after error */
+ if (select(maxfd+1, &rset, &wset, &eset, tp) < 0)
+ {
+ /* otherwise undefined after error */
+ FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&eset);
+ }
sigprocmask(SIG_SETMASK, &save_mask, NULL);
+
}
#endif
}
-
+
first_loop = 0;
now = dnsmasq_time(daemon->uptime_fd);
/* Check for changes to resolv files once per second max. */
- if (last == 0 || difftime(now, last) > 1.0)
+ /* 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)
{
last = now;
@@ -407,24 +464,40 @@
else
{
res->logged = 0;
- if (difftime(statbuf.st_mtime, last_change) > 0.0)
+ if (statbuf.st_mtime != res->mtime)
{
- last_change = statbuf.st_mtime;
- latest = res;
+ res->mtime = statbuf.st_mtime;
+ if (difftime(res->mtime, last_change) > 0.0)
+ {
+ last_change = res->mtime;
+ latest = res;
+ }
}
}
res = res->next;
}
- if (latest && difftime(last_change, resolv_changed) > 0.0)
+ if (latest)
{
- resolv_changed = last_change;
reload_servers(latest->name, daemon);
- check_servers(daemon, interfaces);
+ check_servers(daemon);
}
}
}
-
+
+#ifdef HAVE_DBUS
+ /* if we didn't create a DBus connection, retry now. */
+ if ((daemon->options & OPT_DBUS) && !daemon->dbus)
+ {
+ char *err;
+ if ((err = dbus_init(daemon)))
+ syslog(LOG_WARNING, "DBus error: %s", err);
+ if (daemon->dbus)
+ syslog(LOG_INFO, "connected to system DBus");
+ }
+ check_dbus_listeners(daemon, &rset, &wset, &eset);
+#endif
+
check_dns_listeners(daemon, &rset, now);
if (daemon->dhcp && FD_ISSET(daemon->dhcpfd, &rset))
@@ -432,7 +505,7 @@
}
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
-
+
if (daemon->dhcp)
{
#ifdef HAVE_BROKEN_RTC
@@ -469,6 +542,21 @@
}
}
+
+void clear_cache_and_reload(struct daemon *daemon, time_t now)
+{
+ cache_reload(daemon->options, daemon->namebuff, daemon->domain_suffix, daemon->addn_hosts);
+ if (daemon->dhcp)
+ {
+ if (daemon->options & OPT_ETHERS)
+ dhcp_read_ethers(daemon);
+ dhcp_update_configs(daemon->dhcp_conf);
+ lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
+ lease_update_file(0, now);
+ lease_update_dns(daemon);
+ }
+}
+
static int set_dns_listeners(struct daemon *daemon, fd_set *set, int maxfd)
{
struct serverfd *serverfdp;
@@ -540,7 +628,7 @@
#endif
else
{
- char *buff;
+ unsigned char *buff;
struct server *s;
int flags;
@@ -649,7 +737,8 @@
struct timeval tv;
fd_set rset;
struct sockaddr_in faddr;
- int maxfd, len = sizeof(faddr);
+ int maxfd;
+ socklen_t len = sizeof(faddr);
tv.tv_usec = 250000;
tv.tv_sec = 0;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 982928d..94ab217 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -110,6 +110,8 @@
#define OPT_NO_FORK 65536
#define OPT_AUTHORITATIVE 131072
#define OPT_LOCALISE 262144
+#define OPT_DBUS 524288
+#define OPT_BOOTP_DYNAMIC 1048576
struct all_addr {
union {
@@ -133,7 +135,8 @@
struct mx_srv_record {
char *name, *target;
- int issrv, srvport, priority, weight, offset;
+ int issrv, srvport, priority, weight;
+ unsigned int offset;
struct mx_srv_record *next;
};
@@ -214,6 +217,8 @@
#define SERV_HAS_DOMAIN 16 /* server for one domain only */
#define SERV_FOR_NODOTS 32 /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
+#define SERV_FROM_DBUS 128 /* 1 if source is DBus */
+#define SERV_MARK 256 /* for mark-and-delete */
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
@@ -255,8 +260,8 @@
/* resolv-file parms from command-line */
struct resolvc {
struct resolvc *next;
- int is_default;
- int logged;
+ int is_default, logged;
+ time_t mtime;
char *name;
};
@@ -379,6 +384,11 @@
} data;
};
+struct ping_result {
+ struct in_addr addr;
+ time_t time;
+ struct ping_result *next;
+};
struct daemon {
/* datastuctures representing the command-line and
@@ -394,7 +404,7 @@
char *username, *groupname;
char *domain_suffix;
char *runfile;
- struct iname *if_names, *if_addrs, *if_except;
+ struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
struct bogus_addr *bogus_addr;
struct server *servers;
int cachesize;
@@ -417,6 +427,7 @@
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
struct serverfd *sfds;
+ struct irec *interfaces;
struct listener *listeners;
struct server *last_server;
int uptime_fd;
@@ -428,6 +439,15 @@
#endif
struct udp_dhcp_packet *dhcp_packet;
char *dhcp_buff, *dhcp_buff2;
+ struct ping_result *ping_results;
+
+ /* DBus stuff */
+#ifdef HAVE_DBUS
+ /* void * here to avoid depending on dbus headers outside dbus.c */
+ void *dbus;
+ struct watch *watches;
+#endif
+
};
/* cache.c */
@@ -472,35 +492,35 @@
unsigned short rand16(void);
int legal_char(char c);
int canonicalise(char *s);
-int atoi_check(char *a, int *res);
+unsigned char *do_rfc1035_name(unsigned char *p, char *sval);
void die(char *message, char *arg1);
void complain(char *message, int lineno, char *file);
void *safe_malloc(size_t size);
-char *safe_string_alloc(char *cp);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
-int hostname_isequal(unsigned char *a, unsigned char *b);
+int hostname_isequal(char *a, char *b);
time_t dnsmasq_time(int fd);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
int retry_send(void);
void prettyprint_time(char *buf, unsigned int t);
+int prettyprint_addr(union mysockaddr *addr, char *buf);
int parse_hex(char *in, unsigned char *out, int maxlen,
unsigned int *wildcard_mask);
/* option.c */
-struct daemon *read_opts (int argc, char **argv);
+struct daemon *read_opts (int argc, char **argv, char *compile_opts);
/* forward.c */
void forward_init(int first);
void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now);
void receive_query(struct listener *listen, struct daemon *daemon, time_t now);
-char *tcp_request(struct daemon *daemon, int confd, time_t now,
- struct in_addr local_addr, struct in_addr netmask);
+unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
+ struct in_addr local_addr, struct in_addr netmask);
/* network.c */
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
void reload_servers(char *fname, struct daemon *daemon);
-void check_servers(struct daemon *daemon, struct irec *interfaces);
+void check_servers(struct daemon *daemon);
int enumerate_interfaces(struct daemon *daemon, struct irec **chainp,
union mysockaddr *test_addrp, struct in_addr *netmaskp);
struct listener *create_wildcard_listeners(int port);
@@ -515,7 +535,7 @@
int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
int address_allocate(struct dhcp_context *context, struct daemon *daemon,
struct in_addr *addrp, unsigned char *hwaddr,
- struct dhcp_netid *netids);
+ struct dhcp_netid *netids, time_t now);
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
@@ -551,6 +571,7 @@
/* dnsmasq.c */
int icmp_ping(struct daemon *daemon, struct in_addr addr);
+void clear_cache_and_reload(struct daemon *daemon, time_t now);
/* isc.c */
#ifdef HAVE_ISC_READER
@@ -564,3 +585,12 @@
struct in_addr relay, struct in_addr primary,
struct dhcp_context **retp);
#endif
+
+/* dbus.c */
+#ifdef HAVE_DBUS
+char *dbus_init(struct daemon *daemon);
+void check_dbus_listeners(struct daemon *daemon,
+ fd_set *rset, fd_set *wset, fd_set *eset);
+int set_dbus_listeners(struct daemon *daemon, int maxfd,
+ fd_set *rset, fd_set *wset, fd_set *eset);
+#endif
diff --git a/src/forward.c b/src/forward.c
index 065202f..082ee74 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -89,9 +89,8 @@
cmptr->cmsg_type = IP_SENDSRCADDR;
#endif
}
-
-#ifdef HAVE_IPV6
else
+#ifdef HAVE_IPV
{
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
@@ -100,6 +99,8 @@
cmptr->cmsg_type = IPV6_PKTINFO;
cmptr->cmsg_level = IPV6_LEVEL;
}
+#else
+ iface = 0; /* eliminate warning */
#endif
}
@@ -134,7 +135,7 @@
for (serv = daemon->servers; serv; serv=serv->next)
/* domain matches take priority over NODOTS matches */
- if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
+ if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
{
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
*type = SERV_FOR_NODOTS;
@@ -194,7 +195,7 @@
else
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
}
- else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
+ else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
flags = F_NXDOMAIN;
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon))
@@ -215,13 +216,13 @@
char *domain = NULL;
int type = 0;
struct all_addr *addrp = NULL;
+ unsigned int crc = questions_crc(header, (unsigned int)plen, daemon->namebuff);
unsigned short flags = 0;
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
struct server *start = NULL;
- unsigned int crc = questions_crc(header,(unsigned int)plen, daemon->namebuff);
-
- /* may be recursion not speced or no servers available. */
- if (!header->rd || !daemon->servers)
+
+ /* may be no servers available. */
+ if (!daemon->servers)
forward = NULL;
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
{
@@ -369,16 +370,8 @@
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
server && !(server->flags & SERV_WARNED_RECURSIVE))
{
- char addrbuff[ADDRSTRLEN];
-#ifdef HAVE_IPV6
- if (server->addr.sa.sa_family == AF_INET)
- inet_ntop(AF_INET, &server->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
- else if (server->addr.sa.sa_family == AF_INET6)
- inet_ntop(AF_INET6, &server->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
-#else
- strcpy(addrbuff, inet_ntoa(server->addr.in.sin_addr));
-#endif
- syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
+ prettyprint_addr(&server->addr, daemon->namebuff);
+ syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", daemon->namebuff);
if (!(daemon->options & OPT_LOG))
server->flags |= SERV_WARNED_RECURSIVE;
}
@@ -520,7 +513,10 @@
netmask = listen->iface->netmask;
}
else
- dst_addr_4.s_addr = 0;
+ {
+ dst_addr_4.s_addr = 0;
+ netmask.s_addr = 0;
+ }
iov[0].iov_base = daemon->packet;
iov[0].iov_len = daemon->edns_pktsz;
@@ -657,7 +653,7 @@
header, n, now);
}
-static int read_write(int fd, char *packet, int size, int rw)
+static int read_write(int fd, unsigned char *packet, int size, int rw)
{
int n, done;
@@ -686,14 +682,14 @@
blocking as neccessary, and then return. Note, need to be a bit careful
about resources for debug mode, when the fork is suppressed: that's
done by the caller. */
-char *tcp_request(struct daemon *daemon, int confd, time_t now,
- struct in_addr local_addr, struct in_addr netmask)
+unsigned char *tcp_request(struct daemon *daemon, int confd, time_t now,
+ struct in_addr local_addr, struct in_addr netmask)
{
int size = 0, m;
unsigned short qtype, gotname;
unsigned char c1, c2;
/* Max TCP packet + slop */
- char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
+ unsigned char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
HEADER *header;
struct server *last_server;
diff --git a/src/isc.c b/src/isc.c
index 82016da..6c092b6 100644
--- a/src/isc.c
+++ b/src/isc.c
@@ -136,8 +136,8 @@
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 int months [11] = { 31, 59, 90, 120, 151, 181,
- 212, 243, 273, 304, 334 };
+ 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 */
diff --git a/src/lease.c b/src/lease.c
index 96a8209..69fcc82 100644
--- a/src/lease.c
+++ b/src/lease.c
@@ -71,9 +71,9 @@
if (strcmp(daemon->packet, "*") == 0)
clid_len = 0;
else
- clid_len = parse_hex(daemon->packet, daemon->packet, 255, NULL);
+ clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL);
- if (!(lease = lease_allocate(hwaddr, daemon->packet, clid_len, addr)))
+ if (!(lease = lease_allocate(hwaddr, (unsigned char *)daemon->packet, clid_len, addr)))
die ("too many stored leases", NULL);
lease->expires = expires;
diff --git a/src/network.c b/src/network.c
index dc22312..e821f8f 100644
--- a/src/network.c
+++ b/src/network.c
@@ -33,7 +33,8 @@
if (!lo)
{
lo = safe_malloc(sizeof(struct iname));
- lo->name = safe_string_alloc(name);
+ lo->name = safe_malloc(strlen(name)+1);
+ strcpy(lo->name, name);
lo->isloop = lo->used = 1;
lo->next = daemon->if_names;
daemon->if_names = lo;
@@ -100,6 +101,8 @@
int fd = socket(PF_INET, SOCK_DGRAM, 0);
struct in_addr netmask;
int ret = 0;
+
+ netmask.s_addr = 0; /* eliminate warning */
if (fd == -1)
return 0;
@@ -262,7 +265,7 @@
return ret;
}
-#ifdef HAVE_IPV6
+#if defined(HAVE_IPV6) && (defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
static int create_ipv6_listener(struct listener **link, int port)
{
union mysockaddr addr;
@@ -330,6 +333,7 @@
struct listener *create_wildcard_listeners(int port)
{
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
+ port = 0; /* eliminate warning */
return NULL;
#else
union mysockaddr addr;
@@ -434,7 +438,11 @@
}
else
#endif
- die("failed to bind listening socket: %s", NULL);
+ {
+ char addrbuff[ADDRSTRLEN];
+ prettyprint_addr(&iface->addr, addrbuff);
+ die("failed to bind listening socket for %s: %s", addrbuff);
+ }
}
else
{
@@ -486,9 +494,8 @@
return sfd;
}
-void check_servers(struct daemon *daemon, struct irec *interfaces)
+void check_servers(struct daemon *daemon)
{
- char addrbuff[ADDRSTRLEN];
struct irec *iface;
struct server *new, *tmp, *ret = NULL;
int port = 0;
@@ -504,27 +511,14 @@
if (!(new->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR)))
{
-#ifdef HAVE_IPV6
- if (new->addr.sa.sa_family == AF_INET)
- {
- inet_ntop(AF_INET, &new->addr.in.sin_addr, addrbuff, ADDRSTRLEN);
- port = ntohs(new->addr.in.sin_port);
- }
- else if (new->addr.sa.sa_family == AF_INET6)
- {
- inet_ntop(AF_INET6, &new->addr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
- port = ntohs(new->addr.in6.sin6_port);
- }
-#else
- strcpy(addrbuff, inet_ntoa(new->addr.in.sin_addr));
- port = ntohs(new->addr.in.sin_port);
-#endif
- for (iface = interfaces; iface; iface = iface->next)
+ port = prettyprint_addr(&new->addr, daemon->namebuff);
+
+ for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&new->addr, &iface->addr))
break;
if (iface)
{
- syslog(LOG_WARNING, "ignoring nameserver %s - local interface", addrbuff);
+ syslog(LOG_WARNING, "ignoring nameserver %s - local interface", daemon->namebuff);
free(new);
continue;
}
@@ -533,7 +527,7 @@
if (!new->sfd && !(new->sfd = allocate_sfd(&new->source_addr, &daemon->sfds)))
{
syslog(LOG_WARNING,
- "ignoring nameserver %s - cannot make/bind socket: %m", addrbuff);
+ "ignoring nameserver %s - cannot make/bind socket: %m", daemon->namebuff);
free(new);
continue;
}
@@ -554,10 +548,10 @@
if (new->flags & SERV_NO_ADDR)
syslog(LOG_INFO, "using local addresses only for %s %s", s1, s2);
else if (!(new->flags & SERV_LITERAL_ADDRESS))
- syslog(LOG_INFO, "using nameserver %s#%d for %s %s", addrbuff, port, s1, s2);
+ syslog(LOG_INFO, "using nameserver %s#%d for %s %s", daemon->namebuff, port, s1, s2);
}
else
- syslog(LOG_INFO, "using nameserver %s#%d", addrbuff, port);
+ syslog(LOG_INFO, "using nameserver %s#%d", daemon->namebuff, port);
}
daemon->servers = ret;
@@ -611,7 +605,7 @@
continue;
#ifdef HAVE_IPV6
- if (inet_pton(AF_INET, token, &addr.in.sin_addr))
+ if (inet_pton(AF_INET, token, &addr.in.sin_addr) > 0)
#else
if ((addr.in.sin_addr.s_addr = inet_addr(token)) != (in_addr_t) -1)
#endif
@@ -625,7 +619,7 @@
source_addr.in.sin_port = htons(daemon->query_port);
}
#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr))
+ else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
{
#ifdef HAVE_SOCKADDR_SA_LEN
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(struct sockaddr_in6);
diff --git a/src/option.c b/src/option.c
index 11a416f..d0ac22b 100644
--- a/src/option.c
+++ b/src/option.c
@@ -21,9 +21,9 @@
int val;
};
-#define OPTSTRING "yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:"
+#define OPTSTRING "31yZDNLERKzowefnbvhdkqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:J:W:Y:2:"
-static struct myoption opts[] = {
+static const struct myoption opts[] = {
{"version", 0, 0, 'v'},
{"no-hosts", 0, 0, 'h'},
{"no-poll", 0, 0, 'n'},
@@ -65,6 +65,7 @@
{"addn-hosts", 1, 0, 'H'},
{"query-port", 1, 0, 'Q'},
{"except-interface", 1, 0, 'I'},
+ {"no-dhcp-interface", 1, 0, '2'},
{"domain-needed", 0, 0, 'D'},
{"dhcp-lease-max", 1, 0, 'X' },
{"bind-interfaces", 0, 0, 'z'},
@@ -79,6 +80,8 @@
{"srv-host", 1, 0, 'W'},
{"localise-queries", 0, 0, 'y'},
{"txt-record", 1, 0, 'Y'},
+ {"enable-dbus", 0, 0, '1'},
+ {"bootp-dynamic", 0, 0, '3'},
{0, 0, 0, 0}
};
@@ -87,7 +90,7 @@
unsigned int flag;
};
-static struct optflags optmap[] = {
+static const struct optflags optmap[] = {
{ 'b', OPT_BOGUSPRIV },
{ 'f', OPT_FILTER },
{ 'q', OPT_LOG },
@@ -106,12 +109,14 @@
{ 'z', OPT_NOWILD },
{ 'Z', OPT_ETHERS },
{ 'y', OPT_LOCALISE },
+ { '1', OPT_DBUS },
+ { '3', OPT_BOOTP_DYNAMIC },
{ 'v', 0},
{ 'w', 0},
{ 0, 0 }
};
-static char *usage =
+static const char * const usage =
"Usage: dnsmasq [options]\n\n"
#ifndef HAVE_GETOPT_LONG
"Use short options only on the command line.\n"
@@ -170,8 +175,98 @@
"-Y --txt-record=name,txt.... Specify TXT DNS record.\n"
"-z, --bind-interfaces Bind only to interfaces in use.\n"
"-Z, --read-ethers Read DHCP static host information from " ETHERSFILE ".\n"
+"-1, --enable-dbus Enable the DBus interface for setting upstream servers, etc.\n"
+"-2, --no-dhcp-interface=interface Do not provide DHCP on this interface, only provide DNS.\n"
+"-3, --bootp-dynamic Enable dynamic address allocation for bootp.\n"
"\n";
+/* We hide metacharaters in quoted strings by mapping them into the ASCII control
+ character space. Note that the \0, \t \a \b \r and \n characters are carefully placed in the
+ following sequence so that they map to themselves: it is therefore possible to call
+ unhide_metas repeatedly on string without breaking things.
+ The transformation gets undone by opt_canonicalise, atoi_check and safe_string_alloc, and a
+ couple of other places. */
+
+static char meta[] = "\000123456\a\b\t\n78\r90abcdefABCDEF:,.";
+
+static char hide_meta(char c)
+{
+ unsigned int i;
+
+ for (i = 0; i < (sizeof(meta) - 1); i++)
+ if (c == meta[i])
+ return (char)i;
+
+ return c;
+}
+
+static char unhide_meta(char cr)
+{
+ unsigned int c = cr;
+
+ if (c < (sizeof(meta) - 1))
+ cr = meta[c];
+
+ return cr;
+}
+
+static void unhide_metas(char *cp)
+{
+ if (cp)
+ for(; *cp; cp++)
+ *cp = unhide_meta(*cp);
+}
+
+static char *safe_string_alloc(char *cp)
+{
+ char *ret = NULL;
+
+ if (cp && strlen(cp) != 0)
+ {
+ ret = safe_malloc(strlen(cp)+1);
+ strcpy(ret, cp);
+
+ /* restore hidden metachars */
+ unhide_metas(ret);
+ }
+
+ return ret;
+}
+
+static char *safe_strchr(char *s, int c)
+{
+ if (!s)
+ return NULL;
+
+ return strchr(s, c);
+}
+
+static int canonicalise_opt(char *s)
+{
+ if (!s)
+ return 0;
+
+ unhide_metas(s);
+ return canonicalise(s);
+}
+
+static int atoi_check(char *a, int *res)
+{
+ char *p;
+
+ if (!a)
+ return 0;
+
+ unhide_metas(a);
+
+ for (p = a; *p; p++)
+ if (*p < '0' || *p > '9')
+ return 0;
+
+ *res = atoi(a);
+ return 1;
+}
+
static void add_txt(struct daemon *daemon, char *name, char *txt)
{
size_t len = strlen(txt);
@@ -187,20 +282,7 @@
memcpy((r->txt)+1, txt, len);
}
-/* filenames are OK with unquoted commas, restore them here. */
-static char *safe_filename_alloc(char *filename)
-{
- char *p, *ret = safe_string_alloc(filename);
-
- if (ret)
- for (p = ret; *p; p++)
- if (*p == '\001')
- *p = ',';
-
- return ret;
-}
-
-struct daemon *read_opts (int argc, char **argv)
+struct daemon *read_opts (int argc, char **argv, char *compile_opts)
{
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
char *problem = NULL, *buff = safe_malloc(MAXDNAME);
@@ -248,9 +330,6 @@
strncpy(buff, optarg, MAXDNAME);
buff[MAXDNAME-1] = 0;
arg = buff;
- for (p = arg; *p; p++)
- if (*p == ',')
- *p = '\001';
}
else
arg = NULL;
@@ -276,28 +355,40 @@
else
{
int white;
+ unsigned int lastquote;
lineno++;
/* Implement quotes, inside quotes we allow \\ \" \n and \t
- unquoted commas get changed to \001 also strip comments */
+ metacharacters get hidden also strip comments */
- for (white = 1, p = buff; *p; p++)
+ for (white = 1, lastquote = 0, p = buff; *p; p++)
{
if (*p == '"')
{
memmove(p, p+1, strlen(p+1)+1);
for(; *p && *p != '"'; p++)
- if (*p == '\\' &&
- (p[1] == '\\' || p[1] == '"' || p[1] == 'n' || p[1] == 't'))
- {
- if (p[1] == 't')
- p[1] = '\t';
- else if (p[1] == 'n')
- p[1] = '\n';
- memmove(p, p+1, strlen(p+1)+1);
- }
+ {
+ if (*p == '\\' && strchr("\"tnabr\\", p[1]))
+ {
+ if (p[1] == 't')
+ p[1] = '\t';
+ else if (p[1] == 'n')
+ p[1] = '\n';
+ else if (p[1] == 'a')
+ p[1] = '\a';
+ else if (p[1] == 'b')
+ p[1] = '\b';
+ else if (p[1] == 'r')
+ p[1] = '\r';
+ memmove(p, p+1, strlen(p+1)+1);
+ }
+ *p = hide_meta(*p);
+ }
if (*p == '"')
- memmove(p, p+1, strlen(p+1)+1);
+ {
+ memmove(p, p+1, strlen(p+1)+1);
+ lastquote = p - buff;
+ }
else
complain("missing \"", lineno, conffile);
}
@@ -307,13 +398,10 @@
*p = 0;
break;
}
- white = isspace(*p);
- if (*p == ',')
- *p = '\001';
-
+ white = isspace(unhide_meta(*p));
}
/* fgets gets end of line char too. */
- while (strlen(buff) > 0 && isspace(buff[strlen(buff)-1]))
+ while (strlen(buff) > lastquote && isspace(unhide_meta(buff[strlen(buff)-1])))
buff[strlen(buff)-1] = 0;
if (*buff == 0)
continue;
@@ -360,7 +448,8 @@
if (!f && option == 'v')
{
- printf("Dnsmasq version %s %s\n\n", VERSION, COPYRIGHT);
+ printf("Dnsmasq version %s %s\n", VERSION, COPYRIGHT);
+ printf("Compile time options %s\n\n", compile_opts);
printf("This software comes with ABSOLUTELY NO WARRANTY.\n");
printf("Dnsmasq is free software, and you are welcome to redistribute it\n");
printf("under the terms of the GNU General Public License, version 2.\n");
@@ -390,7 +479,7 @@
case 'C':
if (!f)
{
- conffile = safe_filename_alloc(arg);
+ conffile = safe_string_alloc(arg);
conffile_set = 1;
break;
}
@@ -404,18 +493,18 @@
file_name_save = conffile;
file_save = f;
line_save = lineno;
- conffile = safe_filename_alloc(arg);
+ conffile = safe_string_alloc(arg);
conffile_set = 1;
lineno = 0;
goto fileopen;
case 'x':
- daemon->runfile = safe_filename_alloc(arg);
+ daemon->runfile = safe_string_alloc(arg);
break;
case 'r':
{
- char *name = safe_filename_alloc(arg);
+ char *name = safe_string_alloc(arg);
struct resolvc *new, *list = daemon->resolv_files;
if (list && list->is_default)
@@ -435,6 +524,7 @@
new->next = list;
new->name = name;
new->is_default = 0;
+ new->mtime = 0;
new->logged = 0;
list = new;
}
@@ -447,11 +537,11 @@
int pref = 1;
struct mx_srv_record *new;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
{
char *prefstr;
*(comma++) = 0;
- if ((prefstr=strchr(comma, '\001')))
+ if ((prefstr=strchr(comma, ',')))
{
*(prefstr++) = 0;
if (!atoi_check(prefstr, &pref))
@@ -463,7 +553,7 @@
}
}
- if (!canonicalise(arg) || (comma && !canonicalise(comma)))
+ if (!canonicalise_opt(arg) || (comma && !canonicalise_opt(comma)))
{
option = '?';
problem = "bad MX name";
@@ -481,7 +571,7 @@
}
case 't':
- if (!canonicalise(arg))
+ if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad MX target";
@@ -491,13 +581,13 @@
break;
case 'l':
- daemon->lease_file = safe_filename_alloc(arg);
+ daemon->lease_file = safe_string_alloc(arg);
break;
case 'H':
{
struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
- new->fname = safe_filename_alloc(arg);
+ new->fname = safe_string_alloc(arg);
new->index = hosts_index++;
new->next = daemon->addn_hosts;
daemon->addn_hosts = new;
@@ -507,7 +597,7 @@
case 's':
if (strcmp (arg, "#") == 0)
daemon->options |= OPT_RESOLV_DOMAIN;
- else if (!canonicalise(arg))
+ else if (!canonicalise_opt(arg))
option = '?';
else
daemon->domain_suffix = safe_string_alloc(arg);
@@ -524,7 +614,7 @@
case 'i':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
new->next = daemon->if_names;
daemon->if_names = new;
@@ -532,30 +622,40 @@
"interface=" to disable all interfaces except loop. */
new->name = safe_string_alloc(arg);
new->isloop = new->used = 0;
- if (strchr(arg, ':'))
+ if (safe_strchr(new->name, ':'))
daemon->options |= OPT_NOWILD;
arg = comma;
} while (arg);
break;
case 'I':
+ case '2':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
- new->next = daemon->if_except;
- daemon->if_except = new;
new->name = safe_string_alloc(arg);
- if (strchr(arg, ':'))
- daemon->options |= OPT_NOWILD;
+ if (option == 'I')
+ {
+ new->next = daemon->if_except;
+ daemon->if_except = new;
+ if (safe_strchr(new->name, ':'))
+ daemon->options |= OPT_NOWILD;
+ }
+ else
+ {
+ new->next = daemon->dhcp_except;
+ daemon->dhcp_except = new;
+ }
arg = comma;
} while (arg);
break;
-
+
case 'B':
{
struct in_addr addr;
- if ((addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
+ unhide_metas(arg);
+ if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
struct bogus_addr *baddr = safe_malloc(sizeof(struct bogus_addr));
baddr->next = daemon->bogus_addr;
@@ -570,18 +670,19 @@
case 'a':
do {
struct iname *new = safe_malloc(sizeof(struct iname));
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
+ unhide_metas(arg);
new->next = daemon->if_addrs;
-#ifdef HAVE_IPV6
- if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr))
+ if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
new->addr.sa.sa_family = AF_INET;
#ifdef HAVE_SOCKADDR_SA_LEN
new->addr.in.sin_len = sizeof(struct sockaddr_in);
#endif
}
- else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr))
+#ifdef HAVE_IPV6
+ else if (arg && inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
{
new->addr.sa.sa_family = AF_INET6;
new->addr.in6.sin6_flowinfo = htonl(0);
@@ -589,14 +690,6 @@
new->addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
}
-#else
- if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
- {
- new->addr.sa.sa_family = AF_INET;
-#ifdef HAVE_SOCKADDR_SA_LEN
- new->addr.in.sin_len = sizeof(struct sockaddr_in);
-#endif
- }
#endif
else
{
@@ -615,7 +708,9 @@
{
struct server *serv, *newlist = NULL;
- if (*arg == '/')
+ unhide_metas(arg);
+
+ if (arg && *arg == '/')
{
char *end;
arg++;
@@ -626,7 +721,7 @@
/* # matches everything and becomes a zero length domain string */
if (strcmp(arg, "#") == 0)
domain = "";
- else if (!canonicalise(arg) && strlen(arg) != 0)
+ else if (!canonicalise_opt(arg) && strlen(arg) != 0)
option = '?';
else
domain = safe_string_alloc(arg); /* NULL if strlen is zero */
@@ -661,7 +756,7 @@
option = '?';
}
- if (!*arg)
+ if (!arg || !*arg)
{
newlist->flags |= SERV_NO_ADDR; /* no server */
if (newlist->flags & SERV_LITERAL_ADDRESS)
@@ -696,11 +791,7 @@
}
}
-#ifdef HAVE_IPV6
- if (inet_pton(AF_INET, arg, &newlist->addr.in.sin_addr))
-#else
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
-#endif
{
newlist->addr.in.sin_port = htons(serv_port);
newlist->source_addr.in.sin_port = htons(source_port);
@@ -710,11 +801,7 @@
#endif
if (source)
{
-#ifdef HAVE_IPV6
- if (inet_pton(AF_INET, source+1, &newlist->source_addr.in.sin_addr))
-#else
if ((newlist->source_addr.in.sin_addr.s_addr = inet_addr(source+1)) != (in_addr_t) -1)
-#endif
newlist->flags |= SERV_HAS_SOURCE;
else
option = '?'; /* error */
@@ -723,7 +810,7 @@
newlist->source_addr.in.sin_addr.s_addr = INADDR_ANY;
}
#ifdef HAVE_IPV6
- else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr))
+ else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
{
newlist->addr.in6.sin6_port = htons(serv_port);
newlist->source_addr.in6.sin6_port = htons(source_port);
@@ -734,7 +821,7 @@
#endif
if (source)
{
- if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr))
+ if (inet_pton(AF_INET6, source+1, &newlist->source_addr.in6.sin6_addr) > 0)
newlist->flags |= SERV_HAS_SOURCE;
else
option = '?'; /* error */
@@ -774,6 +861,7 @@
case 'c':
{
int size;
+
if (!atoi_check(arg, &size))
option = '?';
else
@@ -841,11 +929,17 @@
problem = "bad dhcp-range";
+ if (!arg)
+ {
+ option = '?';
+ break;
+ }
+
for (cp = arg; *cp; cp++)
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
break;
- if (*cp != '\001' && (comma = strchr(arg, '\001')))
+ if (*cp != ',' && (comma = strchr(arg, ',')))
{
*comma = 0;
if (strstr(arg, "net:") == arg)
@@ -864,7 +958,7 @@
for (k = 1; k < 5; k++)
{
- if (!(a[k] = strchr(a[k-1], '\001')))
+ if (!(a[k] = strchr(a[k-1], ',')))
break;
*(a[k]++) = 0;
}
@@ -924,6 +1018,10 @@
{
switch (a[leasepos][strlen(a[leasepos]) - 1])
{
+ case 'd':
+ case 'D':
+ fac *= 24;
+ /* fall though */
case 'h':
case 'H':
fac *= 60;
@@ -962,15 +1060,17 @@
new->flags = 0;
- a[0] = arg;
- for (k = 1; k < 6; k++)
- {
- if (!(a[k] = strchr(a[k-1], '\001')))
- break;
- *(a[k]++) = 0;
- }
+ if ((a[0] = arg))
+ for (k = 1; k < 6; k++)
+ {
+ if (!(a[k] = strchr(a[k-1], ',')))
+ break;
+ *(a[k]++) = 0;
+ }
+ else
+ k = 0;
- for(j = 0; j < k; j++)
+ for (j = 0; j < k; j++)
if (strchr(a[j], ':')) /* ethernet address, netid or binary CLID */
{
char *arg = a[j];
@@ -986,7 +1086,7 @@
int len;
arg += 3; /* dump id: */
if (strchr(arg, ':'))
- len = parse_hex(arg, arg, -1, NULL);
+ len = parse_hex(arg, (unsigned char *)arg, -1, NULL);
else
len = (int) strlen(arg);
@@ -1022,6 +1122,10 @@
last = *lastp;
switch (last)
{
+ case 'd':
+ case 'D':
+ fac *= 24;
+ /* fall through */
case 'h':
case 'H':
fac *= 60;
@@ -1100,7 +1204,7 @@
new->val = NULL;
new->vendor_class = NULL;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
{
struct dhcp_netid *np = NULL;
*comma++ = 0;
@@ -1113,7 +1217,7 @@
break;
if (strstr(arg, "vendor:") == arg)
- new->vendor_class = safe_string_alloc(arg+7);
+ new->vendor_class = (unsigned char *)safe_string_alloc(arg+7);
else
{
new->netid = safe_malloc(sizeof (struct dhcp_netid));
@@ -1122,7 +1226,7 @@
np = new->netid;
}
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
} while (arg);
}
@@ -1140,12 +1244,12 @@
size_t newlen, len = 0;
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
while (arg && *arg)
{
- if (!canonicalise(arg))
+ if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad domain in dhcp-option";
@@ -1159,7 +1263,7 @@
/* add string on the end in RFC1035 format */
while (*arg)
{
- char *cp = q++;
+ unsigned char *cp = q++;
int j;
for (j = 0; *arg && (*arg != '.'); arg++, j++)
*q++ = *arg;
@@ -1173,7 +1277,7 @@
newlen = q - p;
for (tail = p + len; *tail; tail += (*tail) + 1)
for (r = p; r - p < (int)len; r += (*r) + 1)
- if (strcmp(r, tail) == 0)
+ if (strcmp((char *)r, (char *)tail) == 0)
{
PUTSHORT((r - p) | 0xc000, tail);
newlen = tail - p;
@@ -1183,7 +1287,7 @@
len = newlen;
arg = comma;
- if (arg && (comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
}
@@ -1197,7 +1301,7 @@
is_addr = is_hex = is_dec = 1;
addrs = digs = 1;
for (cp = comma; *cp; cp++)
- if (*cp == '\001')
+ if (*cp == ',')
{
addrs++;
is_dec = is_hex = 0;
@@ -1275,7 +1379,7 @@
while (addrs--)
{
cp = comma;
- if ((comma = strchr(cp, '\001')))
+ if ((comma = strchr(cp, ',')))
*comma++ = 0;
in.s_addr = inet_addr(cp);
memcpy(op, &in, INADDRSZ);
@@ -1287,7 +1391,7 @@
/* text arg */
new->len = strlen(comma);
/* keep terminating zero on string */
- new->val = safe_string_alloc(comma);
+ new->val = (unsigned char *)safe_string_alloc(comma);
}
}
@@ -1328,7 +1432,7 @@
struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
newid->next = id;
id = newid;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*comma++ = 0;
newid->net = safe_string_alloc(arg+4);
arg = comma;
@@ -1340,18 +1444,22 @@
{
char *dhcp_file, *dhcp_sname = NULL;
struct in_addr dhcp_next_server;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*comma++ = 0;
dhcp_file = safe_string_alloc(arg);
dhcp_next_server.s_addr = 0;
if (comma)
{
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*comma++ = 0;
dhcp_sname = safe_string_alloc(arg);
- if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
- option = '?';
+ if (comma)
+ {
+ unhide_metas(comma);
+ if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
+ option = '?';
+ }
}
if (option != '?')
{
@@ -1380,13 +1488,14 @@
case 'U':
case 'j':
{
- if (!(comma = strchr(arg, '\001')))
+ if (!(comma = safe_strchr(arg, ',')))
option = '?';
else
{
struct dhcp_vendor *new = safe_malloc(sizeof(struct dhcp_vendor));
*comma = 0;
new->netid.net = safe_string_alloc(arg);
+ unhide_metas(comma+1);
new->len = strlen(comma+1);
new->data = safe_malloc(new->len);
memcpy(new->data, comma+1, new->len);
@@ -1405,7 +1514,7 @@
daemon->dhcp_ignore = new;
do {
struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*comma++ = 0;
member->next = list;
list = member;
@@ -1426,15 +1535,18 @@
mask.s_addr = 0xffffffff;
- a[0] = arg;
- for (k = 1; k < 4; k++)
- {
- if (!(a[k] = strchr(a[k-1], '\001')))
- break;
- *(a[k]++) = 0;
- }
+ if ((a[0] = arg))
+ for (k = 1; k < 3; k++)
+ {
+ if (!(a[k] = strchr(a[k-1], ',')))
+ break;
+ *(a[k]++) = 0;
+ unhide_metas(a[k]);
+ }
+ else
+ k = 0;
- if ((k < 2) ||
+ if ((k < 2) ||
((in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
{
@@ -1460,21 +1572,21 @@
struct txt_record *new;
unsigned char *p, *q;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*(comma) = 0;
- if (!canonicalise(arg))
+ if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad TXT record";
break;
}
- if ((q = comma))
+ if ((q = (unsigned char *)comma))
while (1)
{
size_t len;
- if ((p = strchr(q+1, '\001')))
+ if ((p = (unsigned char *)strchr((char*)q+1, ',')))
{
if ((len = p - q - 1) > 255)
{
@@ -1482,13 +1594,16 @@
break;
}
*q = len;
- q = p;
+ for (q = q+1; q < p; q++)
+ *q = unhide_meta(*q);
}
else
{
- if ((len = strlen(q+1)) > 255)
+ if ((len = strlen((char *)q+1)) > 255)
option = '?';
*q = len;
+ for (q = q+1; *q; q++)
+ *q = unhide_meta(*q);
break;
}
}
@@ -1505,7 +1620,7 @@
new->class = C_IN;
if (comma)
{
- new->len = q - ((unsigned char *)comma) + *q + 1;
+ new->len = q - ((unsigned char *)comma);
new->txt = safe_malloc(new->len);
memcpy(new->txt, comma, new->len);
}
@@ -1528,10 +1643,10 @@
char *name, *target = NULL;
struct mx_srv_record *new;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = safe_strchr(arg, ',')))
*(comma++) = 0;
- if (!canonicalise(arg))
+ if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad SRV record";
@@ -1542,9 +1657,9 @@
if (comma)
{
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*(comma++) = 0;
- if (!canonicalise(arg))
+ if (!canonicalise_opt(arg))
{
option = '?';
problem = "bad SRV target";
@@ -1554,7 +1669,7 @@
if (comma)
{
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &port))
{
@@ -1565,7 +1680,7 @@
if (comma)
{
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &priority))
{
@@ -1576,7 +1691,7 @@
if (comma)
{
arg = comma;
- if ((comma = strchr(arg, '\001')))
+ if ((comma = strchr(arg, ',')))
*(comma++) = 0;
if (!atoi_check(arg, &weight))
{
@@ -1674,27 +1789,11 @@
mx->target = daemon->mxtarget;
}
- if (daemon->domain_suffix)
- {
- /* add domain for any srv record without one. */
- struct mx_srv_record *srv;
-
- for (srv = daemon->mxnames; srv; srv = srv->next)
- if (srv->issrv &&
- strchr(srv->name, '.') &&
- strchr(srv->name, '.') == strrchr(srv->name, '.'))
- {
- strcpy(buff, srv->name);
- strcat(buff, ".");
- strcat(buff, daemon->domain_suffix);
- free(srv->name);
- srv->name = safe_string_alloc(buff);
- }
- }
-
if (daemon->options & OPT_NO_RESOLV)
daemon->resolv_files = 0;
- else if (daemon->resolv_files && (daemon->resolv_files)->next && (daemon->options & OPT_NO_POLL))
+ else if (daemon->resolv_files &&
+ (daemon->resolv_files)->next &&
+ (daemon->options & OPT_NO_POLL))
die("only one resolv.conf file allowed in no-poll mode.", NULL);
if (daemon->options & OPT_RESOLV_DOMAIN)
@@ -1715,7 +1814,7 @@
continue;
if ((token = strtok(NULL, " \t\n\r")) &&
- canonicalise(token) &&
+ canonicalise_opt(token) &&
(daemon->domain_suffix = safe_string_alloc(token)))
break;
}
@@ -1725,7 +1824,25 @@
if (!daemon->domain_suffix)
die("no search directive found in %s", (daemon->resolv_files)->name);
}
+
+ if (daemon->domain_suffix)
+ {
+ /* add domain for any srv record without one. */
+ struct mx_srv_record *srv;
+ for (srv = daemon->mxnames; srv; srv = srv->next)
+ if (srv->issrv &&
+ strchr(srv->name, '.') &&
+ strchr(srv->name, '.') == strrchr(srv->name, '.'))
+ {
+ strcpy(buff, srv->name);
+ strcat(buff, ".");
+ strcat(buff, daemon->domain_suffix);
+ free(srv->name);
+ srv->name = safe_string_alloc(buff);
+ }
+ }
+
return daemon;
}
diff --git a/src/rfc1035.c b/src/rfc1035.c
index 0b79a75..f9fc5cb 100644
--- a/src/rfc1035.c
+++ b/src/rfc1035.c
@@ -14,13 +14,13 @@
static int add_resource_record(HEADER *header, char *limit, int *truncp,
unsigned int nameoffset, unsigned char **pp,
- unsigned long ttl, int *offset, unsigned short type,
+ unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...);
static int extract_name(HEADER *header, unsigned int plen, unsigned char **pp,
- unsigned char *name, int isExtract)
+ char *name, int isExtract)
{
- unsigned char *cp = name, *p = *pp, *p1 = NULL;
+ unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0;
int retvalue = 1;
@@ -68,7 +68,7 @@
digs = ((count-1)>>2)+1;
/* output is \[x<hex>/siz]. which is digs+9 chars */
- if (cp - name + digs + 9 >= MAXDNAME)
+ if (cp - (unsigned char *)name + digs + 9 >= MAXDNAME)
return 0;
if (p - (unsigned char *)header + ((count-1)>>3) + 1u >= plen)
return 0;
@@ -86,13 +86,13 @@
*cp++ = dig < 10 ? dig + '0' : dig + 'A' - 10;
}
- cp += sprintf(cp, "/%d]", count);
+ cp += sprintf((char *)cp, "/%d]", count);
/* do this here to overwrite the zero char from sprintf */
*cp++ = '.';
}
else
{ /* label_type = 0 -> label. */
- if (cp - name + l + 1 >= MAXDNAME)
+ if (cp - (unsigned char *)name + l + 1 >= MAXDNAME)
return 0;
if (p - (unsigned char *)header + 1u >= plen)
return 0;
@@ -349,7 +349,7 @@
if (!extract_name(header, plen, &p, name, 1))
return crc; /* bad packet */
- for (p1 = name; *p1; p1++)
+ for (p1 = (unsigned char *)name; *p1; p1++)
{
int i = 8;
char c = *p1;
@@ -883,7 +883,7 @@
}
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
- unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
+ unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
{
va_list ap;
unsigned char *sav, *p = *pp;
@@ -936,19 +936,10 @@
/* get domain-name answer arg and store it in RDATA field */
if (offset)
*offset = p - (unsigned char *)header;
- sval = va_arg(ap, char *);
- while (sval && *sval)
- {
- unsigned char *cp = p++;
- for (j = 0; *sval && (*sval != '.'); sval++, j++)
- *p++ = *sval;
- *cp = j;
- if (*sval)
- sval++;
- }
+ p = do_rfc1035_name(p, va_arg(ap, char *));
*p++ = 0;
break;
-
+
case 't':
usval = va_arg(ap, int);
sval = va_arg(ap, char *);
@@ -1126,17 +1117,31 @@
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
{
unsigned short type = T_A;
-
+
if (flag == F_IPV6)
#ifdef HAVE_IPV6
- type = T_AAAA;
+ type = T_AAAA;
#else
- break;
+ break;
#endif
if (qtype != type && qtype != T_ANY)
continue;
+ /* Check for "A for A" queries. */
+ if (qtype == T_A && (addr.addr.addr4.s_addr = inet_addr(name)) != (in_addr_t) -1)
+ {
+ ans = 1;
+ if (!dryrun)
+ {
+ log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, 0, NULL, 0);
+ if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
+ daemon->local_ttl, NULL, type, C_IN, "4", &addr))
+ anscount++;
+ }
+ continue;
+ }
+
cname_restart:
if ((crecp = cache_find_by_name(NULL, name, now, flag | F_CNAME)))
{
@@ -1231,7 +1236,7 @@
ans = found = 1;
if (!dryrun)
{
- int offset;
+ unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV4, name, NULL, 0, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
@@ -1268,7 +1273,7 @@
found = ans = 1;
if (!dryrun)
{
- int offset;
+ unsigned int offset;
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_IPV6, name, NULL, 0, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd",
diff --git a/src/rfc2131.c b/src/rfc2131.c
index 8f546c1..eaf492e 100644
--- a/src/rfc2131.c
+++ b/src/rfc2131.c
@@ -43,6 +43,7 @@
#define OPTION_VENDOR_ID 60
#define OPTION_CLIENT_ID 61
#define OPTION_USER_CLASS 77
+#define OPTION_CLIENT_FQDN 81
#define OPTION_SUBNET_SELECT 118
#define OPTION_END 255
@@ -74,11 +75,11 @@
struct daemon *daemon,
char *hostname,
struct dhcp_netid *netid,
- struct in_addr subnet_addr);
+ struct in_addr subnet_addr,
+ unsigned char fqdn_flags);
int dhcp_reply(struct daemon *daemon, struct dhcp_context *context, char *iface_name, unsigned int sz, time_t now)
{
- struct dhcp_context *context_tmp;
unsigned char *opt, *clid = NULL;
struct dhcp_lease *ltmp, *lease = NULL;
struct dhcp_vendor *vendor;
@@ -87,40 +88,22 @@
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
- char *hostname = NULL;
- char *req_options = NULL;
+ char *hostname = NULL, *offer_hostname = NULL, *client_hostname = NULL;
+ unsigned char *req_options = NULL;
char *message = NULL;
unsigned int time;
struct dhcp_config *config;
struct dhcp_netid *netid = NULL;
- struct in_addr addr, subnet_addr;
+ struct in_addr subnet_addr;
unsigned short fuzz = 0;
unsigned int mess_type = 0;
-
+ u8 *chaddr;
+ unsigned char fqdn_flags = 0;
subnet_addr.s_addr = 0;
if (mess->op != BOOTREQUEST)
return 0;
- /* Token ring is supported when we have packet sockets
- to make the HW headers for us. We don't have the code to build
- token ring headers when using BPF. We rely on the fact that
- token ring hwaddrs are the same size as ethernet hwaddrs. */
-
-#ifdef HAVE_BPF
- if (mess->htype != ARPHRD_ETHER)
-#else
- if (mess->htype != ARPHRD_ETHER && mess->htype != ARPHRD_IEEE802)
-#endif
- {
- syslog(LOG_WARNING, "DHCP request for unsupported hardware type (%d) recieved on %s",
- mess->htype, iface_name);
- return 0;
- }
-
- if (mess->hlen != ETHER_ADDR_LEN)
- return 0;
-
/* check for DHCP rather than BOOTP */
if ((opt = option_find(mess, sz, OPTION_MESSAGE_TYPE, 1)))
{
@@ -147,7 +130,8 @@
}
/* do we have a lease in store? */
- lease = lease_find_by_client(mess->chaddr, clid, clid_len);
+ if (mess->htype != 0)
+ lease = lease_find_by_client(mess->chaddr, clid, clid_len);
/* If this request is missing a clid, but we've seen one before,
use it again for option matching etc. */
@@ -158,26 +142,75 @@
}
}
+ /* htype == 0 is only allowed in DHCPINFORM, this seems to be a
+ microsoftism. chaddr == NULL in that case */
+
+ if (mess->htype == 0 && mess_type == DHCPINFORM)
+ {
+ chaddr = NULL;
+ if (mess->hlen != 0)
+ return 0;
+ }
+ else
+ {
+ chaddr = mess->chaddr;
+
+ /* Token ring is supported when we have packet sockets
+ to make the HW headers for us. We don't have the code to build
+ token ring headers when using BPF. We rely on the fact that
+ token ring hwaddrs are the same size as ethernet hwaddrs. */
+
+#ifdef HAVE_BPF
+ if (mess->htype != ARPHRD_ETHER)
+#else
+ if (mess->htype != ARPHRD_ETHER && mess->htype != ARPHRD_IEEE802)
+#endif
+ {
+ syslog(LOG_WARNING, "DHCP request for unsupported hardware type (%d) recieved on %s",
+ mess->htype, iface_name);
+ return 0;
+ }
+
+ if (mess->hlen != ETHER_ADDR_LEN)
+ return 0;
+ }
+
/* 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,
we search again. If we don't have have a giaddr or explicit subnet selector,
use the ciaddr. This is necessary because a machine which got a lease via a
- relay won't use the relay to renew. */
+ relay won't use the relay to renew. If matching a ciaddr fails but we have a context
+ from the physical network, continue using that to allow correct DHCPNAK generation later. */
if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr)
{
- addr =
- subnet_addr.s_addr ? subnet_addr :
- (mess->giaddr.s_addr ? mess->giaddr : mess->ciaddr);
+ struct dhcp_context *context_tmp, *context_new = NULL;
+ struct in_addr addr = mess->ciaddr;
+ int force = 0;
- for (context = NULL, context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
+ if (subnet_addr.s_addr)
+ {
+ addr = subnet_addr;
+ force = 1;
+ }
+ else if (mess->giaddr.s_addr)
+ {
+ addr = mess->giaddr;
+ force = 1;
+ }
+
+ for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
if (context_tmp->netmask.s_addr &&
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
is_same_net(addr, context_tmp->end, context_tmp->netmask))
{
- context_tmp->current = context;
- context = context_tmp;
+ context_tmp->current = context_new;
+ context_new = context_tmp;
}
+
+ if (context_new || force)
+ context = context_new;
+
}
if (!context)
@@ -190,7 +223,7 @@
mess->op = BOOTREPLY;
- config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
+ config = find_config(daemon->dhcp_conf, context, clid, clid_len, chaddr, NULL);
if (mess_type == 0)
{
@@ -199,17 +232,6 @@
char save = mess->file[128];
struct in_addr *logaddr = NULL;
- if (have_config(config, CONFIG_ADDR))
- {
- logaddr = &config->addr;
- mess->yiaddr = config->addr;
- if (lease_find_by_addr(config->addr))
- message = "address in use";
- context = narrow_context(context, config->addr);
- }
- else
- message = "no address configured";
-
if (have_config(config, CONFIG_DISABLE))
message = "disabled";
@@ -218,12 +240,6 @@
if (have_config(config, CONFIG_NAME))
hostname = config->hostname;
- if (context->netid.net && !(context->flags & CONTEXT_FILTER))
- {
- context->netid.next = netid;
- netid = &context->netid;
- }
-
if (have_config(config, CONFIG_NETID))
{
config->netid.next = netid;
@@ -234,7 +250,7 @@
if (mess->file[0])
{
mess->file[128] = 0; /* ensure zero term. */
- id.net = mess->file;
+ id.net = (char *)mess->file;
id.next = netid;
netid = &id;
}
@@ -243,13 +259,55 @@
if (match_netid(id_list->list, netid))
message = "disabled";
- p = do_req_options(context, p, end, NULL, daemon,
- hostname, netid, subnet_addr);
- /* must do this after do_req_options since it overwrites filename field. */
- mess->siaddr = context->local;
- bootp_option_put(mess, daemon->boot_config, netid);
- p = option_end(p, end, mess);
- log_packet(NULL, logaddr, mess->chaddr, iface_name, message);
+ if (!message)
+ {
+ if (have_config(config, CONFIG_ADDR))
+ {
+ logaddr = &config->addr;
+ mess->yiaddr = config->addr;
+ if ((lease = lease_find_by_addr(config->addr)) &&
+ memcmp(lease->hwaddr, chaddr, ETHER_ADDR_LEN) != 0)
+ message = "address in use";
+ }
+ else if (!(daemon->options & OPT_BOOTP_DYNAMIC))
+ message = "no address configured";
+ else
+ {
+ if ((lease = lease_find_by_client(mess->chaddr, NULL, 0)))
+ mess->yiaddr = lease->addr;
+ else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
+ message = "no address available";
+ }
+
+ if (!message && !lease && (!(lease = lease_allocate(chaddr, NULL, 0, mess->yiaddr))))
+ message = "no leases left";
+
+ if (!message)
+ {
+ logaddr = &mess->yiaddr;
+ context = narrow_context(context, mess->yiaddr);
+
+ if (context->netid.net && !(context->flags & CONTEXT_FILTER))
+ {
+ context->netid.next = netid;
+ netid = &context->netid;
+ }
+
+ lease_set_hwaddr(lease, chaddr, NULL, 0);
+ if (hostname)
+ lease_set_hostname(lease, hostname, daemon->domain_suffix);
+ lease_set_expires(lease, 0); /* infinite lease */
+
+ p = do_req_options(context, p, end, NULL, daemon,
+ hostname, netid, subnet_addr, fqdn_flags);
+ /* must do this after do_req_options since it overwrites filename field. */
+ mess->siaddr = context->local;
+ bootp_option_put(mess, daemon->boot_config, netid);
+ p = option_end(p, end, mess);
+ }
+ }
+
+ log_packet(NULL, logaddr, chaddr, iface_name, message);
mess->file[128] = save;
if (message)
@@ -258,27 +316,73 @@
return p - (unsigned char *)mess;
}
- if (have_config(config, CONFIG_NAME))
- hostname = config->hostname;
+ if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
+ {
+ /* http://tools.ietf.org/wg/dhc/draft-ietf-dhc-fqdn-option/draft-ietf-dhc-fqdn-option-10.txt */
+ int len = option_len(opt);
+ char *pq = daemon->dhcp_buff;
+ unsigned char *pp, *op = option_ptr(opt);
+
+ fqdn_flags = *op;
+ len -= 3;
+ op += 3;
+ pp = op;
+
+ /* Always force update, since the client has no way to do it itself. */
+ if (fqdn_flags & 0x01)
+ fqdn_flags |= 0x02;
+
+ fqdn_flags &= ~0x08;
+ fqdn_flags |= 0x01;
+
+ if (fqdn_flags & 0x04)
+ while (*op != 0 && ((op + (*op) + 1) - pp) < len)
+ {
+ memcpy(pq, op+1, *op);
+ pq += *op;
+ op += (*op)+1;
+ *(pq++) = '.';
+ }
+ else
+ {
+ memcpy(pq, op, len);
+ pq += len + 1;
+ }
+
+ if (pq != daemon->dhcp_buff)
+ pq--;
+
+ *pq = 0;
+
+ if (canonicalise(daemon->dhcp_buff))
+ offer_hostname = client_hostname = daemon->dhcp_buff;
+ }
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME, 1)))
{
int len = option_len(opt);
- hostname = daemon->dhcp_buff;
- memcpy(hostname, option_ptr(opt), len);
+ memcpy(daemon->dhcp_buff, option_ptr(opt), len);
/* May not be zero terminated */
- hostname[len] = 0;
- /* ensure there are no strange chars in there */
- if (!canonicalise(hostname))
- hostname = NULL;
- else if ((hostname = strip_hostname(daemon, hostname)) && !config)
- {
- /* Search again now we have a hostname.
- Only accept configs without CLID and HWADDR here, (they won't match)
- to avoid impersonation by name. */
- struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, hostname);
- if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
- config = new;
- }
+ daemon->dhcp_buff[len] = 0;
+ if (canonicalise(daemon->dhcp_buff))
+ client_hostname = daemon->dhcp_buff;
+ }
+
+ if (have_config(config, CONFIG_NAME))
+ {
+ hostname = config->hostname;
+ /* be careful not to send an OFFER with a hostname not
+ matching the DISCOVER. */
+ if (fqdn_flags != 0 || !client_hostname || hostname_isequal(hostname, client_hostname))
+ offer_hostname = hostname;
+ }
+ else if (client_hostname && (hostname = strip_hostname(daemon, client_hostname)) && !config)
+ {
+ /* Search again now we have a hostname.
+ Only accept configs without CLID and HWADDR here, (they won't match)
+ to avoid impersonation by name. */
+ struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0, chaddr, hostname);
+ if (!have_config(new, CONFIG_CLID) && !have_config(new, CONFIG_HWADDR))
+ config = new;
}
if (have_config(config, CONFIG_NETID))
@@ -332,7 +436,7 @@
if ((opt = option_find(mess, sz, OPTION_REQUESTED_OPTIONS, 0)))
{
- req_options = daemon->dhcp_buff2;
+ req_options = (unsigned char *)daemon->dhcp_buff2;
memcpy(req_options, option_ptr(opt), option_len(opt));
req_options[option_len(opt)] = OPTION_END;
}
@@ -363,7 +467,7 @@
if (!(opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
return 0;
- log_packet("DECLINE", option_ptr(opt), mess->chaddr, iface_name, message);
+ log_packet("DECLINE", option_ptr(opt), chaddr, iface_name, message);
if (lease && lease->addr.s_addr == option_addr(opt).s_addr)
lease_prune(lease, now);
@@ -391,27 +495,31 @@
else
message = "unknown lease";
- log_packet("RELEASE", &mess->ciaddr, mess->chaddr, iface_name, message);
+ log_packet("RELEASE", &mess->ciaddr, chaddr, iface_name, message);
return 0;
case DHCPDISCOVER:
- if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
- addr = option_addr(opt);
- if (ignore || have_config(config, CONFIG_DISABLE))
- message = "ignored";
- else if (have_config(config, CONFIG_ADDR) &&
- (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
- mess->yiaddr = config->addr;
- else if (lease && address_available(context, lease->addr))
- mess->yiaddr = lease->addr;
- else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
- !config_find_by_address(daemon->dhcp_conf, addr))
- mess->yiaddr = addr;
- else if (!address_allocate(context, daemon, &mess->yiaddr, mess->chaddr, netid))
- message = "no address available";
- log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
-
+ {
+ struct in_addr addr;
+
+ if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP, INADDRSZ)))
+ addr = option_addr(opt);
+ if (ignore || have_config(config, CONFIG_DISABLE))
+ message = "ignored";
+ else if (have_config(config, CONFIG_ADDR) &&
+ (!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
+ mess->yiaddr = config->addr;
+ else if (lease && address_available(context, lease->addr))
+ mess->yiaddr = lease->addr;
+ else if (opt && address_available(context, addr) && !lease_find_by_addr(addr) &&
+ !config_find_by_address(daemon->dhcp_conf, addr))
+ mess->yiaddr = addr;
+ else if (!address_allocate(context, daemon, &mess->yiaddr, chaddr, netid, now))
+ message = "no address available";
+ log_packet("DISCOVER", opt ? &addr : NULL, chaddr, iface_name, message);
+ }
+
if (message)
return 0;
@@ -444,10 +552,10 @@
p = option_put(p, end, OPTION_T2, 4, (time*7)/8);
}
p = do_req_options(context, p, end, req_options, daemon,
- NULL, netid, subnet_addr);
+ offer_hostname, netid, subnet_addr, fqdn_flags);
p = option_end(p, end, mess);
- log_packet("OFFER" , &mess->yiaddr, mess->chaddr, iface_name, NULL);
+ log_packet("OFFER" , &mess->yiaddr, chaddr, iface_name, NULL);
return p - (unsigned char *)mess;
case DHCPREQUEST:
@@ -493,7 +601,7 @@
mess->yiaddr = mess->ciaddr;
}
- log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
+ log_packet("REQUEST", &mess->yiaddr, chaddr, iface_name, NULL);
if (!message)
{
@@ -524,23 +632,27 @@
else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
message = "address in use";
- else if (!lease && !(lease = lease_allocate(mess->chaddr, clid, clid_len, mess->yiaddr)))
+ else if (!lease && !(lease = lease_allocate(chaddr, clid, clid_len, mess->yiaddr)))
message = "no leases left";
}
if (message)
{
- log_packet("NAK", &mess->yiaddr, mess->chaddr, iface_name, message);
+ log_packet("NAK", &mess->yiaddr, chaddr, iface_name, message);
mess->siaddr.s_addr = mess->yiaddr.s_addr = mess->ciaddr.s_addr = 0;
bootp_option_put(mess, NULL, NULL);
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
+ p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(context->local.s_addr));
p = option_put_string(p, end, OPTION_MESSAGE, message);
mess->flags |= htons(0x8000); /* broadcast */
}
else
{
- log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
+ if (!hostname)
+ hostname = host_from_dns(daemon, mess->yiaddr);
+
+ log_packet("ACK", &mess->yiaddr, chaddr, iface_name, hostname);
context = narrow_context(context, mess->yiaddr);
if (context->netid.net && !(context->flags & CONTEXT_FILTER))
@@ -557,9 +669,7 @@
time = req_time;
}
- lease_set_hwaddr(lease, mess->chaddr, clid, clid_len);
- if (!hostname)
- hostname = host_from_dns(daemon, mess->yiaddr);
+ lease_set_hwaddr(lease, chaddr, clid, clid_len);
if (hostname)
lease_set_hostname(lease, hostname, daemon->domain_suffix);
lease_set_expires(lease, time == 0xffffffff ? 0 : now + (time_t)time);
@@ -577,7 +687,7 @@
p = option_put(p, end, OPTION_T2, 4, ((time * 7)/8) - fuzz);
}
p = do_req_options(context, p, end, req_options, daemon,
- hostname, netid, subnet_addr);
+ hostname, netid, subnet_addr, fqdn_flags);
}
p = option_end(p, end, mess);
@@ -587,7 +697,7 @@
if (ignore || have_config(config, CONFIG_DISABLE))
message = "ignored";
- log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
+ log_packet("INFORM", &mess->ciaddr, chaddr, iface_name, message);
if (message || mess->ciaddr.s_addr == 0)
return 0;
@@ -606,10 +716,10 @@
if (!hostname)
hostname = host_from_dns(daemon, mess->yiaddr);
p = do_req_options(context, p, end, req_options, daemon,
- hostname, netid, subnet_addr);
+ hostname, netid, subnet_addr, fqdn_flags);
p = option_end(p, end, mess);
- log_packet("ACK", &mess->ciaddr, mess->chaddr, iface_name, hostname);
+ log_packet("ACK", &mess->ciaddr, chaddr, iface_name, hostname);
return p - (unsigned char *)mess;
}
@@ -618,6 +728,11 @@
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string)
{
+ u8 empty[] = { 0, 0, 0, 0, 0, 0};
+
+ if (!hwaddr)
+ hwaddr = empty;
+
syslog(LOG_INFO, "%s%s(%s)%s%s %.2x:%.2x:%.2x:%.2x:%.2x:%.2x%s%s",
type ? "DHCP" : "BOOTP",
type ? type : "",
@@ -686,9 +801,9 @@
if (tmp)
{
if (tmp->sname)
- strncpy(mess->sname, tmp->sname, sizeof(mess->sname)-1);
+ strncpy((char *)mess->sname, tmp->sname, sizeof(mess->sname)-1);
if (tmp->file)
- strncpy(mess->file, tmp->file, sizeof(mess->file)-1);
+ strncpy((char *)mess->file, tmp->file, sizeof(mess->file)-1);
if (tmp->next_server.s_addr)
mess->siaddr = tmp->next_server;
}
@@ -864,7 +979,8 @@
struct daemon *daemon,
char *hostname,
struct dhcp_netid *netid,
- struct in_addr subnet_addr)
+ struct in_addr subnet_addr,
+ unsigned char fqdn_flags)
{
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
char *vendor_class = NULL;
@@ -903,13 +1019,56 @@
p = option_put_string(p, end, OPTION_DOMAINNAME, daemon->domain_suffix);
/* Note that we ignore attempts to set the hostname using
- --dhcp-option=12,<name> */
- if (hostname && in_list(req_options, OPTION_HOSTNAME))
- p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
-
+ --dhcp-option=12,<name> and the fqdn using
+ --dhc-option=81,<name> */
+ if (hostname)
+ {
+ if (in_list(req_options, OPTION_HOSTNAME))
+ p = option_put_string(p, end, OPTION_HOSTNAME, hostname);
+
+ if (fqdn_flags != 0)
+ {
+ int len = strlen(hostname) + 3;
+ if (fqdn_flags & 0x04)
+ len += 2;
+
+ if (daemon->domain_suffix)
+ len += strlen(daemon->domain_suffix) + 1;
+
+ if (p + len + 1 < end)
+ {
+ *(p++) = OPTION_CLIENT_FQDN;
+ *(p++) = len;
+ *(p++) = fqdn_flags;
+ *(p++) = 255;
+ *(p++) = 255;
+
+ if (fqdn_flags & 0x04)
+ {
+ p = do_rfc1035_name(p, hostname);
+ if (daemon->domain_suffix)
+ p = do_rfc1035_name(p, daemon->domain_suffix);
+ *p++ = 0;
+ }
+ else
+ {
+ memcpy(p, hostname, strlen(hostname));
+ p += strlen(hostname);
+ if (daemon->domain_suffix)
+ {
+ *(p++) = '.';
+ memcpy(p, daemon->domain_suffix, strlen(daemon->domain_suffix));
+ p += strlen(daemon->domain_suffix);
+ }
+ }
+ }
+ }
+ }
+
for (opt=config_opts; opt; opt = opt->next)
{
if (opt->opt == OPTION_HOSTNAME ||
+ opt->opt == OPTION_CLIENT_FQDN ||
opt->opt == OPTION_MAXMESSAGE ||
!in_list(req_options, opt->opt) ||
opt != option_find2(netid, config_opts, opt->opt))
@@ -927,7 +1086,7 @@
/* opt->val has terminating zero */
if (opt->opt == OPTION_VENDOR_ID)
- vendor_class = opt->val;
+ vendor_class = (char *)opt->val;
else
p = do_opt(opt, p, end, context->local);
}
@@ -937,10 +1096,10 @@
for (opt = daemon->vendor_opts; opt; opt = opt->next)
if (!opt->netid || match_netid(opt->netid, netid))
{
- if (vendor_class && strcmp(vendor_class, opt->vendor_class) != 0)
+ if (vendor_class && strcmp(vendor_class, (char *)opt->vendor_class) != 0)
syslog(LOG_WARNING, "More than one vendor class matches, using %s", vendor_class);
else
- vendor_class = opt->vendor_class;
+ vendor_class = (char *)opt->vendor_class;
}
if (vendor_class)
@@ -964,7 +1123,7 @@
for (opt = daemon->vendor_opts; opt; opt = opt->next)
if ((!opt->netid || match_netid(opt->netid, netid)) &&
- strcmp(vendor_class, opt->vendor_class) == 0)
+ strcmp(vendor_class, (char *)opt->vendor_class) == 0)
p = do_opt(opt, p, oend, context->local);
*plen = p - plen - 1;
diff --git a/src/util.c b/src/util.c
index d71c1ec..ea91f56 100644
--- a/src/util.c
+++ b/src/util.c
@@ -85,18 +85,6 @@
return( (unsigned short) (rand() >> 15) );
}
-int atoi_check(char *a, int *res)
-{
- char *p;
-
- for (p = a; *p; p++)
- if (*p < '0' || *p > '9')
- return 0;
-
- *res = atoi(a);
- return 1;
-}
-
int legal_char(char c)
{
/* check for legal char a-z A-Z 0-9 -
@@ -125,15 +113,33 @@
s[l-1] = 0;
}
- while ((c = *s++))
- if (c == '.')
- dotgap = 0;
- else if (!legal_char(c) || (++dotgap > MAXLABEL))
- return 0;
-
+ while ((c = *s))
+ {
+ if (c == '.')
+ dotgap = 0;
+ else if (!legal_char(c) || (++dotgap > MAXLABEL))
+ return 0;
+ s++;
+ }
return 1;
}
+unsigned char *do_rfc1035_name(unsigned char *p, char *sval)
+{
+ int j;
+
+ while (sval && *sval)
+ {
+ unsigned char *cp = p++;
+ for (j = 0; *sval && (*sval != '.'); sval++, j++)
+ *p++ = *sval;
+ *cp = j;
+ if (*sval)
+ sval++;
+ }
+ return p;
+}
+
/* for use during startup */
void *safe_malloc(size_t size)
{
@@ -143,20 +149,7 @@
die("could not get memory", NULL);
return ret;
-}
-
-char *safe_string_alloc(char *cp)
-{
- char *ret = NULL;
-
- if (cp && strlen(cp) != 0)
- {
- ret = safe_malloc(strlen(cp)+1);
- strcpy(ret, cp);
- }
-
- return ret;
-}
+}
static void log_err(char *message, char *arg1)
{
@@ -176,8 +169,8 @@
{
char buff[256];
- sprintf(buff, "%s at line %d of %s", message, lineno, file);
- log_err(buff, NULL);
+ sprintf(buff, "%s at line %d of %%s", message, lineno);
+ log_err(buff, file);
}
void die(char *message, char *arg1)
@@ -221,13 +214,13 @@
}
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
-int hostname_isequal(unsigned char *a, unsigned char *b)
+int hostname_isequal(char *a, char *b)
{
unsigned int c1, c2;
do {
- c1 = *a++;
- c2 = *b++;
+ c1 = (unsigned char) *a++;
+ c2 = (unsigned char) *b++;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
@@ -250,6 +243,9 @@
char buf[30];
lseek(fd, 0, SEEK_SET);
read(fd, buf, 30);
+ /* ensure the time is terminated even if /proc/uptime sends something unexpected */
+ buf[29] = 0;
+ read(fd, buf, 30);
return (time_t)atol(buf);
#else
fd = 0; /* stop warning */
@@ -279,6 +275,30 @@
return 0;
}
+/* returns port number from address */
+int prettyprint_addr(union mysockaddr *addr, char *buf)
+{
+ int port = 0;
+
+#ifdef HAVE_IPV6
+ if (addr->sa.sa_family == AF_INET)
+ {
+ inet_ntop(AF_INET, &addr->in.sin_addr, buf, ADDRSTRLEN);
+ port = ntohs(addr->in.sin_port);
+ }
+ else if (addr->sa.sa_family == AF_INET6)
+ {
+ inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
+ port = ntohs(addr->in6.sin6_port);
+ }
+#else
+ strcpy(buf, inet_ntoa(addr->in.sin_addr));
+ port = ntohs(addr->in.sin_port);
+#endif
+
+ return port;
+}
+
void prettyprint_time(char *buf, unsigned int t)
{
if (t == 0xffffffff)
@@ -286,7 +306,9 @@
else
{
unsigned int x, p = 0;
- if ((x = t/3600))
+ if ((x = t/86400))
+ p += sprintf(&buf[p], "%dd", x);
+ if ((x = (t/3600)%24))
p += sprintf(&buf[p], "%dh", x);
if ((x = (t/60)%60))
p += sprintf(&buf[p], "%dm", x);