mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
7
Commits
v2.57
..
v2.60test7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
984d2fded6 | ||
|
|
a4f04ed45a | ||
|
|
07736e8dcb | ||
|
|
00fc082d68 | ||
|
|
c72daea868 | ||
|
|
74c95c2542 | ||
|
|
7de060b08d |
No files matched your search
@@ -1,3 +1,144 @@
|
|||||||
|
version 2.60
|
||||||
|
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||||
|
Flebbe for the patch.
|
||||||
|
|
||||||
|
Fix DHCP when using --listen-address with an IP address
|
||||||
|
which is not the primary address of an interface.
|
||||||
|
|
||||||
|
Add --dhcp-client-update option.
|
||||||
|
|
||||||
|
Add Lua integration. Dnsmasq can now execute a DHCP
|
||||||
|
lease-change script written in Lua. This needs to be
|
||||||
|
enabled at compile time by setting HAVE_LUASCRIPT in
|
||||||
|
src/config.h or running "make COPTS=-DHAVE_LUASCRIPT"
|
||||||
|
Thanks to Jan-Piet Mens for the idea and proof-of-concept
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
Tidied src/config.h to distinguish between
|
||||||
|
platform-dependent compile-time options which are selected
|
||||||
|
automatically, and builder-selectable compile time
|
||||||
|
options. Document the latter better, and describe how to
|
||||||
|
set them from the make command line.
|
||||||
|
|
||||||
|
Tidied up IPPROTO_IP/SOL_IP (and IPv6 equivalent)
|
||||||
|
confusion. IPPROTO_IP works everywhere now.
|
||||||
|
|
||||||
|
Set TOS on DHCP sockets, this improves things on busy
|
||||||
|
wireless networks. Thanks to Dave Taht for the patch.
|
||||||
|
|
||||||
|
Determine VERSION automatically based on git magic:
|
||||||
|
release tags or hash values.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.59
|
||||||
|
Fix regression in 2.58 which caused failure to start up
|
||||||
|
with some combinations of dnsmasq config and IPv6 kernel
|
||||||
|
network config. Thanks to Brielle Bruns for the bug
|
||||||
|
report.
|
||||||
|
|
||||||
|
Improve dnsmasq's behaviour when network interfaces are
|
||||||
|
still doing duplicate address detection (DAD). Previously,
|
||||||
|
dnsmasq would wait up to 20 seconds at start-up for the
|
||||||
|
DAD state to terminate. This is broken for bridge
|
||||||
|
interfaces on recent Linux kernels, which don't start DAD
|
||||||
|
until the bridge comes up, and so can take arbitrary
|
||||||
|
time. The new behaviour lets dnsmasq poll for an arbitrary
|
||||||
|
time whilst providing service on other interfaces. Thanks
|
||||||
|
to Stephen Hemminger for pointing out the problem.
|
||||||
|
|
||||||
|
|
||||||
|
version 2.58
|
||||||
|
Provide a definition of the SA_SIZE macro where it's
|
||||||
|
missing. Fixes build failure on openBSD.
|
||||||
|
|
||||||
|
Don't include a zero terminator at the end of messages
|
||||||
|
sent to /dev/log when /dev/log is a datagram socket.
|
||||||
|
Thanks to Didier Rabound for spotting the problem.
|
||||||
|
|
||||||
|
Add --dhcp-sequential-ip flag, to force allocation of IP
|
||||||
|
addresses in ascending order. Note that the default
|
||||||
|
pseudo-random mode is in general better but some
|
||||||
|
server-deployment applications need this.
|
||||||
|
|
||||||
|
Fix problem where a server-id of 0.0.0.0 is sent to a
|
||||||
|
client when a dhcp-relay is in use if a client renews a
|
||||||
|
lease after dnsmasq restart and before any clients on the
|
||||||
|
subnet get a new lease. Thanks to Mike Ruiz for assistance
|
||||||
|
in chasing this one down.
|
||||||
|
|
||||||
|
Don't return NXDOMAIN to an AAAA query if we have CNAME
|
||||||
|
which points to an A record only: NODATA is the correct
|
||||||
|
reply in this case. Thanks to Tom Fernandes for spotting
|
||||||
|
the problem.
|
||||||
|
|
||||||
|
Relax the need to supply a netmask in --dhcp-range for
|
||||||
|
networks which use a DHCP relay. Whilst this is still
|
||||||
|
desireable, in the absence of a netmask dnsmasq will use
|
||||||
|
a default based on the class (A, B, or C) of the address.
|
||||||
|
This should at least remove a cause of mysterious failure
|
||||||
|
for people using RFC1918 addresses and relays.
|
||||||
|
|
||||||
|
Add support for Linux conntrack connection marking. If
|
||||||
|
enabled with --conntrack, the connection mark for incoming
|
||||||
|
DNS queries will be copied to the outgoing connections
|
||||||
|
used to answer those queries. This allows clever firewall
|
||||||
|
and accounting stuff. Only available if dnsmasq is
|
||||||
|
compiled with HAVE_CONNTRACK and adds a dependency on
|
||||||
|
libnetfilter-conntrack. Thanks to Ed Wildgoose for the
|
||||||
|
initial idea, testing and sponsorship of this function.
|
||||||
|
|
||||||
|
Provide a sane error message when someone attempts to
|
||||||
|
match a tag in --dhcp-host.
|
||||||
|
|
||||||
|
Tweak the behaviour of --domain-needed, to avoid problems
|
||||||
|
with recursive nameservers downstream of dnsmasq. The new
|
||||||
|
behaviour only stops A and AAAA queries, and returns
|
||||||
|
NODATA rather than NXDOMAIN replies.
|
||||||
|
|
||||||
|
Efficiency fix for very large DHCP configurations, thanks
|
||||||
|
to James Gartrell and Mike Ruiz for help with this.
|
||||||
|
|
||||||
|
Allow the TFTP-server address in --dhcp-boot to be a
|
||||||
|
domain-name which is looked up in /etc/hosts. This can
|
||||||
|
give multiple IP addresses which are used round-robin,
|
||||||
|
thus doing TFTP server load-balancing. Thanks to Sushil
|
||||||
|
Agrawal for the patch.
|
||||||
|
|
||||||
|
When two tagged dhcp-options for a particular option
|
||||||
|
number are both valid, use the one which is valid without
|
||||||
|
a tag from the dhcp-range. Allows overriding of the value
|
||||||
|
of a DHCP option for a particular host as well as
|
||||||
|
per-network values. So
|
||||||
|
--dhcp-range=set:interface1,......
|
||||||
|
--dhcp-host=set:myhost,.....
|
||||||
|
--dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||||
|
--dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||||
|
will set the NIS-domain to domain1 for hosts in the range, but
|
||||||
|
override that to domain2 for a particular host.
|
||||||
|
|
||||||
|
Fix bug which resulted in truncated files and timeouts for
|
||||||
|
some TFTP transfers. The bug only occurs with netascii
|
||||||
|
transfers and needs an unfortunate relationship between
|
||||||
|
file size, blocksize and the number of newlines in the
|
||||||
|
last block before it manifests itself. Many thanks to
|
||||||
|
Alkis Georgopoulos for spotting the problem and providing
|
||||||
|
a comprehensive test-case.
|
||||||
|
|
||||||
|
Fix regression in TFTP server on *BSD platforms introduced
|
||||||
|
in version 2.56, due to confusion with sockaddr
|
||||||
|
length. Many thanks to Loïc Pefferkorn for finding this.
|
||||||
|
|
||||||
|
Support scope-ids in IPv6 addresses of nameservers from
|
||||||
|
/etc/resolv.conf and in --server options. Eg
|
||||||
|
nameserver fe80::202:a412:4512:7bbf%eth0 or
|
||||||
|
server=fe80::202:a412:4512:7bbf%eth0. Thanks to
|
||||||
|
Michael Stapelberg for the suggestion.
|
||||||
|
|
||||||
|
Update Polish translation, thanks to Jan Psota.
|
||||||
|
|
||||||
|
Update French translation. Thanks to Gildas Le Nadan.
|
||||||
|
|
||||||
|
|
||||||
version 2.57
|
version 2.57
|
||||||
Add patches to allow build under Android.
|
Add patches to allow build under Android.
|
||||||
|
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
|||||||
|
|
||||||
Q: What does the dhcp-authoritative option do?
|
Q: What does the dhcp-authoritative option do?
|
||||||
|
|
||||||
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
|
A: See http://www.isc.org/files/auth.html - that's
|
||||||
for the ISC daemon, but the same applies to dnsmasq.
|
for the ISC daemon, but the same applies to dnsmasq.
|
||||||
|
|
||||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||||
@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
|
|||||||
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
||||||
them, as recommended in RFC2131?
|
them, as recommended in RFC2131?
|
||||||
|
|
||||||
A: Yes, dynmaically allocated IP addresses are checked by sending an
|
A: Yes, dynamically allocated IP addresses are checked by sending an
|
||||||
ICMP echo request (ping). If a reply is received, then dnsmasq
|
ICMP echo request (ping). If a reply is received, then dnsmasq
|
||||||
assumes that the address is in use, and attempts to allocate an
|
assumes that the address is in use, and attempts to allocate an
|
||||||
different address. The wait for a reply is between two and three
|
different address. The wait for a reply is between two and three
|
||||||
|
|||||||
@@ -32,20 +32,25 @@ SRC = src
|
|||||||
PO = po
|
PO = po
|
||||||
MAN = man
|
MAN = man
|
||||||
|
|
||||||
DNSMASQ_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
DBUS_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||||
DNSMASQ_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||||
IDN_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||||
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||||
|
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||||
|
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||||
|
LUA_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
|
||||||
|
LUA_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
|
||||||
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
||||||
|
VERSION= -DVERSION='\"`../bld/get-version`\"'
|
||||||
|
|
||||||
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
|
OBJS = cache.o rfc1035.o util.o option.o forward.o network.o \
|
||||||
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
|
||||||
helper.o tftp.o log.o
|
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o
|
||||||
|
|
||||||
all :
|
all :
|
||||||
@cd $(SRC) && $(MAKE) \
|
@cd $(SRC) && $(MAKE) \
|
||||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) $(IDN_CFLAGS)" \
|
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS)" \
|
||||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(IDN_LIBS) $(SUNOS_LIBS)" \
|
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS)" \
|
||||||
-f ../Makefile dnsmasq
|
-f ../Makefile dnsmasq
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
@@ -61,9 +66,9 @@ install-common :
|
|||||||
|
|
||||||
all-i18n :
|
all-i18n :
|
||||||
@cd $(SRC) && $(MAKE) \
|
@cd $(SRC) && $(MAKE) \
|
||||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
I18N=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
|
||||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
BUILD_CFLAGS="$(VERSION) $(DBUS_CFLAGS) $(CT_CFLAGS) $(LUA_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(LUA_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||||
-f ../Makefile dnsmasq
|
-f ../Makefile dnsmasq
|
||||||
@cd $(PO); for f in *.po; do \
|
@cd $(PO); for f in *.po; do \
|
||||||
cd ../$(SRC) && $(MAKE) \
|
cd ../$(SRC) && $(MAKE) \
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||||
forward.c helper.c lease.c log.c \
|
forward.c helper.c lease.c log.c \
|
||||||
netlink.c network.c option.c rfc1035.c \
|
netlink.c network.c option.c rfc1035.c \
|
||||||
rfc2131.c tftp.c util.c
|
rfc2131.c tftp.c util.c conntrack.c
|
||||||
|
|
||||||
LOCAL_MODULE := dnsmasq
|
LOCAL_MODULE := dnsmasq
|
||||||
|
|
||||||
|
|||||||
Executable
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Determine the version string to build into a binary.
|
||||||
|
# When building in the git repository, we can use the output
|
||||||
|
# of "git describe" which gives an unequivocal answer.
|
||||||
|
#
|
||||||
|
# Failing that, we use the contents of the VERSION file
|
||||||
|
# which has a set of references substituted into it by git.
|
||||||
|
# If we can find one which matches $v[0-9].* then we assume it's
|
||||||
|
# a version-number tag, else we just use the whole string.
|
||||||
|
|
||||||
|
# we're called with pwd == src
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
if [ -d .git ]; then
|
||||||
|
git describe
|
||||||
|
else
|
||||||
|
vers=`cat VERSION | sed 's/[(), ]/\n/ g' | grep -m 1 $v[0-9]`
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo ${vers#v}
|
||||||
|
else
|
||||||
|
cat VERSION
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
search=$1
|
search=$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if grep "^\#.*define.*$search" config.h 2>&1 >/dev/null || \
|
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h 2>&1 >/dev/null || \
|
||||||
grep $search 2>&1 >/dev/null ; then
|
grep $search 2>&1 >/dev/null ; then
|
||||||
exec $*
|
exec $*
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
Linux iptables includes that ability to mark individual network packets
|
||||||
|
with a "firewall mark". Additionally there is a component called
|
||||||
|
"conntrack" which tries to string sequences of related packets together
|
||||||
|
into a "connection" (it even relates sequences of UDP and ICMP packets).
|
||||||
|
There is a related mark for a connection called a "connection mark".
|
||||||
|
Marks can be copied freely between the firewall and connection marks
|
||||||
|
|
||||||
|
Using these two features it become possible to tag all related traffic
|
||||||
|
in arbitrary ways, eg authenticated users, traffic from a particular IP,
|
||||||
|
port, etc. Unfortunately any kind of "proxy" breaks this relationship
|
||||||
|
because network packets go in one side of the proxy and a completely new
|
||||||
|
connection comes out of the other side. However, sometimes, we want to
|
||||||
|
maintain that relationship through the proxy and continue the connection
|
||||||
|
mark on packets upstream of our proxy
|
||||||
|
|
||||||
|
DNSMasq includes such a feature enabled by the --conntrack
|
||||||
|
option. This allows, for example, using iptables to mark traffic from
|
||||||
|
a particular IP, and that mark to be persisted to requests made *by*
|
||||||
|
DNSMasq. Such a feature could be useful for bandwidth accounting,
|
||||||
|
captive portals and the like. Note a similar feature has been
|
||||||
|
implemented in Squid 2.2
|
||||||
|
|
||||||
|
|
||||||
|
As an example consider the following iptables rules:
|
||||||
|
|
||||||
|
|
||||||
|
1) iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
|
||||||
|
2) iptables -t mangle -A PREROUTING -m mark --mark 0 -s 192.168.111.137
|
||||||
|
-j MARK --set-mark 137
|
||||||
|
3) iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
|
||||||
|
|
||||||
|
4) iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark
|
||||||
|
|
||||||
|
1-3) are all applied to the PREROUTING table and affect all packets
|
||||||
|
entering the firewall.
|
||||||
|
|
||||||
|
1) copies any existing connection mark into the firewall mark. 2) Checks
|
||||||
|
the packet not already marked and if not applies an arbitrary mark based
|
||||||
|
on IP address. 3) Saves the firewall mark back to the connection mark
|
||||||
|
(which will persist it across related packets)
|
||||||
|
|
||||||
|
4) is applied to the OUTPUT table, which is where we first see packets
|
||||||
|
generated locally. DNSMasq will have already copied the firewall mark
|
||||||
|
from the request, across to the new packet, and so all that remains is
|
||||||
|
for iptables to copy it to the connection mark so it's persisted across
|
||||||
|
packets.
|
||||||
|
|
||||||
|
Note: iptables can be quite confusing to the beginner. The following
|
||||||
|
diagram is extremely helpful in understanding the flows
|
||||||
|
http://linux-ip.net/nf/nfk-traversal.png
|
||||||
|
Additionally the following URL contains a useful "starting guide" on
|
||||||
|
linux connection tracking/marking
|
||||||
|
http://home.regit.org/netfilter-en/netfilter-connmark/
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
Hello,
|
||||||
|
|
||||||
|
I created a systemd service file for dnsmasq.
|
||||||
|
systemd is a sysvinit replacement (see [1] for more information).
|
||||||
|
One of the goals of systemd is to encourage standardization between different
|
||||||
|
distributions. This means, while I also submitted a ticket in Debian GNU/Linux,
|
||||||
|
I would like to ask you to accept this service file as the upstream
|
||||||
|
distributor, so that other distributions can use the same service file and
|
||||||
|
don’t have to ship their own.
|
||||||
|
|
||||||
|
Please include this file in your next release (just like in init script).
|
||||||
|
|
||||||
|
|
||||||
|
[1] http://en.wikipedia.org/wiki/Systemd
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=A lightweight DHCP and caching DNS server
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=uk.org.thekelleys.dnsmasq
|
||||||
|
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||||
|
ExecStart=/usr/sbin/dnsmasq -k
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
.TH DHCP_LEASE_TIME 1
|
||||||
|
.SH NAME
|
||||||
|
dhcp_lease_time \- Query remaining time of a lease on a the local dnsmasq DHCP server.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dhcp_lease_time <address>
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
Send a DHCPINFORM message to a dnsmasq server running on the local host
|
||||||
|
and print (to stdout) the time remaining in any lease for the given
|
||||||
|
address. The time is given as string printed to stdout.
|
||||||
|
|
||||||
|
If an error occurs or no lease exists for the given address,
|
||||||
|
nothing is sent to stdout a message is sent to stderr and a
|
||||||
|
non-zero error code is returned.
|
||||||
|
|
||||||
|
Requires dnsmasq 2.40 or later and may not work with other DHCP servers.
|
||||||
|
|
||||||
|
The address argument is a dotted-quad IP addresses and mandatory.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dnsmasq (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
.TH DHCP_RELEASE 1
|
||||||
|
.SH NAME
|
||||||
|
dhcp_release \- Release a DHCP lease on a the local dnsmasq DHCP server.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dhcp_release <interface> <address> <MAC address> <client_id>
|
||||||
|
.SH "DESCRIPTION"
|
||||||
|
A utility which forces the DHCP server running on this machine to release a
|
||||||
|
DHCP lease.
|
||||||
|
.PP
|
||||||
|
Send a DHCPRELEASE message via the specified interface to tell the
|
||||||
|
local DHCP server to delete a particular lease.
|
||||||
|
|
||||||
|
The interface argument is the interface in which a DHCP
|
||||||
|
request _would_ be received if it was coming from the client,
|
||||||
|
rather than being faked up here.
|
||||||
|
|
||||||
|
The address argument is a dotted-quad IP addresses and mandatory.
|
||||||
|
|
||||||
|
The MAC address is colon separated hex, and is mandatory. It may be
|
||||||
|
prefixed by an address-type byte followed by -, eg
|
||||||
|
|
||||||
|
10-11:22:33:44:55:66
|
||||||
|
|
||||||
|
but if the address-type byte is missing it is assumed to be 1, the type
|
||||||
|
for ethernet. This encoding is the one used in dnsmasq lease files.
|
||||||
|
|
||||||
|
The client-id is optional. If it is "*" then it treated as being missing.
|
||||||
|
.SH NOTES
|
||||||
|
MUST be run as root - will fail otherwise.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dnsmasq (8)
|
||||||
|
.SH AUTHOR
|
||||||
|
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.
|
||||||
|
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ static int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct in_addr find_interface(struct in_addr client, int fd, int index)
|
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
|
||||||
{
|
{
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
struct nlmsghdr *h;
|
struct nlmsghdr *h;
|
||||||
|
|||||||
Vendored
+1010
File diff suppressed because it is too large.
Load diff
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
/etc/init.d/dnsmasq
|
||||||
|
/etc/default/dnsmasq
|
||||||
|
/etc/dnsmasq.conf
|
||||||
|
/etc/resolvconf/update.d/dnsmasq
|
||||||
|
/etc/dbus-1/system.d/dnsmasq.conf
|
||||||
|
/etc/insserv.conf.d/dnsmasq
|
||||||
Vendored
+41
@@ -0,0 +1,41 @@
|
|||||||
|
Source: dnsmasq
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
|
||||||
|
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
|
||||||
|
Standards-Version: 3.9.2
|
||||||
|
|
||||||
|
Package: dnsmasq
|
||||||
|
Architecture: all
|
||||||
|
Depends: netbase, adduser, dnsmasq-base(>= ${source:Version})
|
||||||
|
Suggests: resolvconf
|
||||||
|
Conflicts: resolvconf (<<1.15)
|
||||||
|
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||||
|
Dnsmasq is a lightweight, easy to configure, DNS forwarder and DHCP
|
||||||
|
server. It is designed to provide DNS and optionally, DHCP, to a
|
||||||
|
small network. It can serve the names of local machines which are
|
||||||
|
not in the global DNS. The DHCP server integrates with the DNS
|
||||||
|
server and allows machines with DHCP-allocated addresses
|
||||||
|
to appear in the DNS with names configured either in each host or
|
||||||
|
in a central configuration file. Dnsmasq supports static and dynamic
|
||||||
|
DHCP leases and BOOTP/TFTP for network booting of diskless machines.
|
||||||
|
|
||||||
|
Package: dnsmasq-base
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.41)
|
||||||
|
Description: Small caching DNS proxy and DHCP/TFTP server
|
||||||
|
This package contains the dnsmasq executable and documentation, but
|
||||||
|
not the infrastructure required to run it as a system daemon. For
|
||||||
|
that, install the dnsmasq package.
|
||||||
|
|
||||||
|
Package: dnsmasq-utils
|
||||||
|
Architecture: linux-any
|
||||||
|
Depends: ${shlibs:Depends}
|
||||||
|
Conflicts: dnsmasq (<<2.40)
|
||||||
|
Description: Utilities for manipulating DHCP leases
|
||||||
|
Small utilities to query a DHCP server's lease database and
|
||||||
|
remove leases from it. These programs are distributed with dnsmasq
|
||||||
|
and may not work correctly with other DHCP servers.
|
||||||
|
|
||||||
|
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||||
|
|
||||||
|
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
On Debian GNU/Linux systems, the text of the GNU general public license is
|
||||||
|
available in the file /usr/share/common-licenses/GPL-2 or
|
||||||
|
/usr/share/common-licenses/GPL-3
|
||||||
|
|
||||||
|
The Debian package of dnsmasq was created by Simon Kelley with assistance
|
||||||
|
from Lars Bahner.
|
||||||
|
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE busconfig PUBLIC
|
||||||
|
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||||||
|
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||||||
|
<busconfig>
|
||||||
|
<policy user="root">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy user="dnsmasq">
|
||||||
|
<allow own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<allow send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
<policy context="default">
|
||||||
|
<deny own="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
<deny send_destination="uk.org.thekelleys.dnsmasq"/>
|
||||||
|
</policy>
|
||||||
|
</busconfig>
|
||||||
|
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
# This file has five functions:
|
||||||
|
# 1) to completely disable starting dnsmasq,
|
||||||
|
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
|
||||||
|
# 3) to select an alternative config file
|
||||||
|
# by setting DNSMASQ_OPTS to --conf-file=<file>
|
||||||
|
# 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for
|
||||||
|
# more configuration variables.
|
||||||
|
# 5) to stop the resolvconf package from controlling dnsmasq's
|
||||||
|
# idea of which upstream nameservers to use.
|
||||||
|
# For upgraders from very old versions, all the shell variables set
|
||||||
|
# here in previous versions are still honored by the init script
|
||||||
|
# so if you just keep your old version of this file nothing will break.
|
||||||
|
|
||||||
|
#DOMAIN_SUFFIX=`dnsdomainname`
|
||||||
|
#DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt"
|
||||||
|
|
||||||
|
# Whether or not to run the dnsmasq daemon; set to 0 to disable.
|
||||||
|
ENABLED=1
|
||||||
|
|
||||||
|
# By default search this drop directory for configuration options.
|
||||||
|
# Libvirt leaves a file here to make the system dnsmasq play nice.
|
||||||
|
# Comment out this line if you don't want this. The dpkg-* are file
|
||||||
|
# endings which cause dnsmasq to skip that file. This avoids pulling
|
||||||
|
# in backups made by dpkg.
|
||||||
|
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
|
||||||
|
|
||||||
|
# If the resolvconf package is installed, dnsmasq will use its output
|
||||||
|
# rather than the contents of /etc/resolv.conf to find upstream
|
||||||
|
# nameservers. Uncommenting this line inhibits this behaviour.
|
||||||
|
# Not that including a "resolv-file=<filename>" line in
|
||||||
|
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
|
||||||
|
# installed: the line below must be uncommented.
|
||||||
|
#IGNORE_RESOLVCONF=yes
|
||||||
Vendored
+266
@@ -0,0 +1,266 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: dnsmasq
|
||||||
|
# Required-Start: $network $remote_fs $syslog
|
||||||
|
# Required-Stop: $network $remote_fs $syslog
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Description: DHCP and DNS server
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
set +e # Don't exit on error status
|
||||||
|
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
DAEMON=/usr/sbin/dnsmasq
|
||||||
|
NAME=dnsmasq
|
||||||
|
DESC="DNS forwarder and DHCP server"
|
||||||
|
|
||||||
|
# Most configuration options in /etc/default/dnsmasq are deprecated
|
||||||
|
# but still honoured.
|
||||||
|
ENABLED=1
|
||||||
|
if [ -r /etc/default/$NAME ]; then
|
||||||
|
. /etc/default/$NAME
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the system locale, so that messages are in the correct language, and the
|
||||||
|
# charset for IDN is correct
|
||||||
|
if [ -r /etc/default/locale ]; then
|
||||||
|
. /etc/default/locale
|
||||||
|
export LANG
|
||||||
|
fi
|
||||||
|
|
||||||
|
test -x $DAEMON || exit 0
|
||||||
|
|
||||||
|
# Provide skeleton LSB log functions for backports which don't have LSB functions.
|
||||||
|
if [ -f /lib/lsb/init-functions ]; then
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
else
|
||||||
|
log_warning_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_success_msg () {
|
||||||
|
echo "${@}."
|
||||||
|
}
|
||||||
|
|
||||||
|
log_daemon_msg () {
|
||||||
|
echo -n "${1}: $2"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_end_msg () {
|
||||||
|
if [ $1 -eq 0 ]; then
|
||||||
|
echo "."
|
||||||
|
elif [ $1 -eq 255 ]; then
|
||||||
|
/bin/echo -e " (warning)."
|
||||||
|
else
|
||||||
|
/bin/echo -e " failed!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# RESOLV_CONF:
|
||||||
|
# If the resolvconf package is installed then use the resolv conf file
|
||||||
|
# that it provides as the default. Otherwise use /etc/resolv.conf as
|
||||||
|
# the default.
|
||||||
|
#
|
||||||
|
# If IGNORE_RESOLVCONF is set in /etc/default/dnsmasq or an explicit
|
||||||
|
# filename is set there then this inhibits the use of the resolvconf-provided
|
||||||
|
# information.
|
||||||
|
#
|
||||||
|
# Note that if the resolvconf package is installed it is not possible to
|
||||||
|
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
|
||||||
|
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
|
||||||
|
|
||||||
|
if [ ! "$RESOLV_CONF" ] &&
|
||||||
|
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
|
||||||
|
[ -x /sbin/resolvconf ]
|
||||||
|
then
|
||||||
|
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_INTERFACE; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
for INTERFACE in $DNSMASQ_EXCEPT; do
|
||||||
|
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ ! "$DNSMASQ_USER" ]; then
|
||||||
|
DNSMASQ_USER="dnsmasq"
|
||||||
|
fi
|
||||||
|
|
||||||
|
start()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been started
|
||||||
|
# 1 if daemon was already running
|
||||||
|
# 2 if daemon could not be started
|
||||||
|
|
||||||
|
# /var/run may be volatile, so we need to ensure that
|
||||||
|
# /var/run/dnsmasq exists here as well as in postinst
|
||||||
|
if [ ! -d /var/run/dnsmasq ]; then
|
||||||
|
mkdir /var/run/dnsmasq || return 2
|
||||||
|
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
|
||||||
|
-x /var/run/dnsmasq/$NAME.pid \
|
||||||
|
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
|
||||||
|
${MAILTARGET:+ -t $MAILTARGET} \
|
||||||
|
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
|
||||||
|
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
|
||||||
|
${DHCP_LEASE:+ -l $DHCP_LEASE} \
|
||||||
|
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
|
||||||
|
${RESOLV_CONF:+ -r $RESOLV_CONF} \
|
||||||
|
${CACHESIZE:+ -c $CACHESIZE} \
|
||||||
|
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
|
||||||
|
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
|
||||||
|
|| return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
start_resolvconf()
|
||||||
|
{
|
||||||
|
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
|
||||||
|
# Then dnsmasq won't be providing local DNS, so don't add it to
|
||||||
|
# the resolvconf server set.
|
||||||
|
for interface in $DNSMASQ_EXCEPT
|
||||||
|
do
|
||||||
|
[ $interface = lo ] && return
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stop()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been stopped
|
||||||
|
# 1 if daemon was already stopped
|
||||||
|
# 2 if daemon could not be stopped
|
||||||
|
# other if a failure occurred
|
||||||
|
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
|
||||||
|
RETVAL="$?"
|
||||||
|
[ "$RETVAL" = 2 ] && return 2
|
||||||
|
return "$RETVAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_resolvconf()
|
||||||
|
{
|
||||||
|
if [ -x /sbin/resolvconf ] ; then
|
||||||
|
/sbin/resolvconf -d lo.$NAME
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
status()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon is running
|
||||||
|
# 1 if daemon is dead and pid file exists
|
||||||
|
# 3 if daemon is not running
|
||||||
|
# 4 if daemon status is unknown
|
||||||
|
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
|
||||||
|
case "$?" in
|
||||||
|
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
|
||||||
|
1) return 0 ;;
|
||||||
|
*) return 4 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
test "$ENABLED" != "0" || exit 0
|
||||||
|
log_daemon_msg "Starting $DESC" "$NAME"
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
log_success_msg "(already running)"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
stop_resolvconf
|
||||||
|
if [ "$ENABLED" != "0" ]; then
|
||||||
|
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||||
|
fi
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
if [ "$ENABLED" = "0" ]; then
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
case "$RETVAL" in
|
||||||
|
0) log_end_msg 0 ; exit 0 ;;
|
||||||
|
1) log_warning_msg "(not running)" ; exit 0 ;;
|
||||||
|
*) log_end_msg 1; exit 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
restart|force-reload)
|
||||||
|
test "$ENABLED" != "0" || exit 1
|
||||||
|
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
NAME="configuration syntax check"
|
||||||
|
RETVAL="2"
|
||||||
|
else
|
||||||
|
stop_resolvconf
|
||||||
|
stop
|
||||||
|
RETVAL="$?"
|
||||||
|
fi
|
||||||
|
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||||
|
case "$RETVAL" in
|
||||||
|
0|1)
|
||||||
|
sleep 2
|
||||||
|
start
|
||||||
|
case "$?" in
|
||||||
|
0)
|
||||||
|
log_end_msg 0
|
||||||
|
start_resolvconf
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
log_end_msg 1
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
log_daemon_msg "Checking $DESC" "$NAME"
|
||||||
|
status
|
||||||
|
case "$?" in
|
||||||
|
0) log_success_msg "(running)" ; exit 0 ;;
|
||||||
|
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
|
||||||
|
3) log_success_msg "(not running)" ; exit 3 ;;
|
||||||
|
*) log_success_msg "(unknown)" ; exit 4 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
$named dnsmasq
|
||||||
Vendored
+49
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# create a user to run as (code stolen from dovecot-common)
|
||||||
|
if [ "$1" = "configure" ]; then
|
||||||
|
if [ -z "`id -u dnsmasq 2> /dev/null`" ]; then
|
||||||
|
adduser --system --home /var/lib/misc --gecos "dnsmasq" \
|
||||||
|
--no-create-home --disabled-password \
|
||||||
|
--quiet dnsmasq || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make the directory where we keep the pid file - this
|
||||||
|
# has to be owned by "dnsmasq" do that the file can be unlinked.
|
||||||
|
if [ ! -d /var/run/dnsmasq ]; then
|
||||||
|
mkdir /var/run/dnsmasq
|
||||||
|
chown dnsmasq:nogroup /var/run/dnsmasq
|
||||||
|
fi
|
||||||
|
|
||||||
|
# handle new location of pidfile during an upgrade
|
||||||
|
if [ -e /var/run/dnsmasq.pid ]; then
|
||||||
|
mv /var/run/dnsmasq.pid /var/run/dnsmasq
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x /etc/init.d/dnsmasq ]; then
|
||||||
|
update-rc.d dnsmasq defaults 15 85 >/dev/null
|
||||||
|
|
||||||
|
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
|
||||||
|
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
|
||||||
|
ACTION=restart
|
||||||
|
else
|
||||||
|
ACTION=start
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq $ACTION || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq $ACTION || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dpkg can botch the change of /usr/share/doc/dnsmasq from
|
||||||
|
# directory to symlink. Fix up here.
|
||||||
|
if [ ! -h /usr/share/doc/dnsmasq ] && { rmdir /usr/share/doc/dnsmasq; }; then
|
||||||
|
cd /usr/share/doc/
|
||||||
|
ln -s /usr/share/doc/dnsmasq-base dnsmasq
|
||||||
|
fi
|
||||||
|
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ purge = "$1" ]; then
|
||||||
|
update-rc.d dnsmasq remove >/dev/null
|
||||||
|
if [ -x "$(command -v deluser)" ]; then
|
||||||
|
deluser --quiet --system dnsmasq > /dev/null || true
|
||||||
|
else
|
||||||
|
echo >&2 "not removing dnsmasq system account because deluser command was not found"
|
||||||
|
fi
|
||||||
|
rm -rf /var/run/dnsmasq
|
||||||
|
fi
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$1" = "remove" ]; then
|
||||||
|
if [ -x /usr/sbin/invoke-rc.d ] ; then
|
||||||
|
invoke-rc.d dnsmasq stop || true
|
||||||
|
else
|
||||||
|
/etc/init.d/dnsmasq stop || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
||||||
Vendored
+70
@@ -0,0 +1,70 @@
|
|||||||
|
Notes on configuring dnsmasq as packaged for Debian.
|
||||||
|
|
||||||
|
(1) To configure dnsmasq edit /etc/dnsmasq.conf. The file is well
|
||||||
|
commented; see also the dnsmasq.8 man page for explanation of
|
||||||
|
the options. The file /etc/default/dnsmasq also exists but it
|
||||||
|
shouldn't need to be touched in most cases. To set up DHCP
|
||||||
|
options you might need to refer to a copy of RFC 2132. This is
|
||||||
|
available on Debian systems in the package doc-rfc-std as the file
|
||||||
|
/usr/share/doc/RFC/draft-standard/rfc2132.txt.gz .
|
||||||
|
|
||||||
|
(2) Installing the dnsmasq package also creates the directory
|
||||||
|
/etc/dnsmasq.d which is searched by dnsmasq for configuration file
|
||||||
|
fragments. This behaviour can be disabled by editing
|
||||||
|
/etc/default/dnsmasq.
|
||||||
|
|
||||||
|
(3) If the Debian resolvconf package is installed then, regardless
|
||||||
|
of what interface configuration daemons are employed, the list of
|
||||||
|
nameservers to which dnsmasq should forward queries can be found
|
||||||
|
in /var/run/dnsmasq/resolv.conf; also, 127.0.0.1 is listed as the
|
||||||
|
first nameserver address in /etc/resolv.conf. This works using the
|
||||||
|
default configurations of resolvconf and dnsmasq.
|
||||||
|
|
||||||
|
(4) In the absence of resolvconf, if you are using dhcpcd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/dhcpc/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(5) In the absence of resolvconf, if you are using pppd then
|
||||||
|
dnsmasq should read the list of nameservers from the automatically
|
||||||
|
generated file /etc/ppp/resolv.conf. You should list 127.0.0.1
|
||||||
|
as the first nameserver address in /etc/resolv.conf.
|
||||||
|
|
||||||
|
(6) In the absence of resolvconf, dns-nameservers lines in
|
||||||
|
/etc/network/interfaces are ignored. If you do do not use
|
||||||
|
resolvconf, list 127.0.0.1 as the first nameserver address
|
||||||
|
in /etc/resolv.conf and configure your nameservers using
|
||||||
|
"server=<IP-address>" lines in /etc/dnsmasq.conf.
|
||||||
|
|
||||||
|
(7) If you run multiple DNS servers on a single machine, each
|
||||||
|
listening on a different interface, then it is necessary to use
|
||||||
|
the bind-interfaces option by uncommenting "bind-interfaces" in
|
||||||
|
/etc/dnsmasq.conf. This option stops dnsmasq from binding the
|
||||||
|
wildcard address and allows servers listening on port 53 on
|
||||||
|
interfaces not in use by dnsmasq to work. The Debian
|
||||||
|
libvirt package will add a configuration file in /etc/dnsmasq.d
|
||||||
|
which does this so that the "system" dnsmasq and "private" dnsmasq
|
||||||
|
instances started by libvirt do not clash.
|
||||||
|
|
||||||
|
(8) The following options are supported in DEB_BUILD_OPTIONS
|
||||||
|
noopt : compile without optimisation.
|
||||||
|
nostrip : don't remove symbols from binary.
|
||||||
|
nodocs : omit documentation.
|
||||||
|
notftp : omit TFTP support.
|
||||||
|
nodhcp : omit DHCP support.
|
||||||
|
noscript : omit lease-change script support.
|
||||||
|
noipv6 : omit IPv6 support.
|
||||||
|
nodbus : omit DBus support.
|
||||||
|
noconntrack : omit connection tracking support.
|
||||||
|
nortc : compile alternate mode suitable for systems without an RTC.
|
||||||
|
noi18n : omit translations and internationalisation support.
|
||||||
|
noidn : omit international domain name support, must be
|
||||||
|
combined with noi18n to be effective.
|
||||||
|
|
||||||
|
(9) Dnsmasq comes as two packages - dnsmasq-base and
|
||||||
|
dnsmasq. dnsmasq-base provides the dnsmasq executable and
|
||||||
|
documentation (including this file). Dnsmasq, which depends on
|
||||||
|
dnsmasq-base, provides the init script and configuration
|
||||||
|
infrastructure. This file assumes that both are installed. It is
|
||||||
|
possible to install only dnsmasq-base and use dnsmasq as a
|
||||||
|
non-"system" daemon. Libvirt, for instance, does this.
|
||||||
Vendored
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# All files in this directory will be read by dnsmasq as
|
||||||
|
# configuration files, except if their names end in
|
||||||
|
# ".dpkg-dist",".dpkg-old" or ".dpkg-new"
|
||||||
|
#
|
||||||
|
# This can be changed by editing /etc/default/dnsmasq
|
||||||
|
|
||||||
|
|
||||||
Vendored
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Script to update the resolver list for dnsmasq
|
||||||
|
#
|
||||||
|
# N.B. Resolvconf may run us even if dnsmasq is not running.
|
||||||
|
# If dnsmasq is installed then we go ahead and update
|
||||||
|
# the resolver list in case dnsmasq is started later.
|
||||||
|
#
|
||||||
|
# Assumption: On entry, PWD contains the resolv.conf-type files
|
||||||
|
#
|
||||||
|
# Requires bash because it uses a non-POSIX printf extension.
|
||||||
|
#
|
||||||
|
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
|
||||||
|
#
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RUN_DIR="/var/run/dnsmasq"
|
||||||
|
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
|
||||||
|
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
|
||||||
|
|
||||||
|
[ -x /usr/sbin/dnsmasq ] || exit 0
|
||||||
|
[ -x /lib/resolvconf/list-records ] || exit 1
|
||||||
|
|
||||||
|
PATH=/bin:/sbin
|
||||||
|
|
||||||
|
report_err() { echo "$0: Error: $*" >&2 ; }
|
||||||
|
|
||||||
|
# Stores arguments (minus duplicates) in RSLT, separated by spaces
|
||||||
|
# Doesn't work properly if an argument itself contain whitespace
|
||||||
|
uniquify()
|
||||||
|
{
|
||||||
|
RSLT=""
|
||||||
|
while [ "$1" ] ; do
|
||||||
|
for E in $RSLT ; do
|
||||||
|
[ "$1" = "$E" ] && { shift ; continue 2 ; }
|
||||||
|
done
|
||||||
|
RSLT="${RSLT:+$RSLT }$1"
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
|
||||||
|
report_err "Failed trying to create directory $RUN_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
|
||||||
|
|
||||||
|
NMSRVRS=""
|
||||||
|
if [ "$RSLVCNFFILES" ] ; then
|
||||||
|
uniquify $(sed -n -e 's/^[[:space:]]*nameserver[[:space:]]\+//p' $RSLVCNFFILES)
|
||||||
|
NMSRVRS="$RSLT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
|
||||||
|
# to detect changes in the file. This means that if a resolvconf update occurs
|
||||||
|
# within one second of the previous one then dnsmasq may fail to notice the
|
||||||
|
# more recent change. To work around this problem we sleep here to ensure
|
||||||
|
# that the new mtime is different.
|
||||||
|
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
clean_up() { rm -f "$TMP_FILE" ; }
|
||||||
|
trap clean_up EXIT
|
||||||
|
: >| "$TMP_FILE"
|
||||||
|
for N in $NMSRVRS ; do echo "nameserver $N" >> "$TMP_FILE" ; done
|
||||||
|
mv -f "$TMP_FILE" "$RSLVRLIST_FILE"
|
||||||
|
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Resolvconf packaging event hook script for the dnsmasq package
|
||||||
|
restart_dnsmasq() {
|
||||||
|
if which invoke-rc.d >/dev/null 2>&1 ; then
|
||||||
|
invoke-rc.d dnsmasq restart
|
||||||
|
elif [ -x /etc/init.d/dnsmasq ] ; then
|
||||||
|
/etc/init.d/dnsmasq restart
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
install) restart_dnsmasq ;;
|
||||||
|
esac
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
# debian/rules file - for dnsmasq.
|
||||||
|
# Copyright 2001-2011 by Simon Kelley
|
||||||
|
# Based on the sample in the debian hello package which carries the following:
|
||||||
|
# Copyright 1994,1995 by Ian Jackson.
|
||||||
|
# I hereby give you perpetual unlimited permission to copy,
|
||||||
|
# modify and relicense this file, provided that you do not remove
|
||||||
|
# my name from the file itself. (I assert my moral right of
|
||||||
|
# paternity under the Copyright, Designs and Patents Act 1988.)
|
||||||
|
# This file may have to be extensively modified
|
||||||
|
|
||||||
|
package=dnsmasq-base
|
||||||
|
|
||||||
|
# policy manual, section 10.1
|
||||||
|
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
|
||||||
|
CFLAGS = -g -O0 -Wall -W
|
||||||
|
else
|
||||||
|
CFLAGS = -g -O2 -Wall -W
|
||||||
|
endif
|
||||||
|
|
||||||
|
COPTS =
|
||||||
|
TARGET = install-i18n
|
||||||
|
|
||||||
|
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
|
||||||
|
|
||||||
|
ifeq (,$(findstring nodbus,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_DBUS
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq (,$(findstring noconntrack,$(DEB_BUILD_OPTIONS)))
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
COPTS += -DHAVE_CONNTRACK
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noipv6,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_IPV6
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring notftp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_TFTP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring nodhcp,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_DHCP
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noscript,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DNO_SCRIPT
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring nortc,$(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_BROKEN_RTC
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring noi18n,$(DEB_BUILD_OPTIONS)))
|
||||||
|
TARGET = install
|
||||||
|
ifeq (,$(findstring noidn, $(DEB_BUILD_OPTIONS)))
|
||||||
|
COPTS += -DHAVE_IDN
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
|
||||||
|
make clean
|
||||||
|
make -C contrib/wrt clean
|
||||||
|
|
||||||
|
binary-indep: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/daemon
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/daemon/DEBIAN \
|
||||||
|
-d debian/daemon/usr/share/doc \
|
||||||
|
-d debian/daemon/etc/init.d \
|
||||||
|
-d debian/daemon/etc/dnsmasq.d \
|
||||||
|
-d debian/daemon/etc/resolvconf/update.d \
|
||||||
|
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
|
||||||
|
-d debian/daemon/etc/default \
|
||||||
|
-d debian/daemon/etc/dbus-1/system.d \
|
||||||
|
-d debian/daemon/lib/systemd/system \
|
||||||
|
-d debian/daemon/etc/insserv.conf.d
|
||||||
|
install -m 644 debian/conffiles debian/daemon/DEBIAN
|
||||||
|
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
|
||||||
|
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
|
||||||
|
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
|
||||||
|
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
|
||||||
|
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
|
||||||
|
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
|
||||||
|
install -m 644 debian/dbus.conf debian/daemon/etc/dbus-1/system.d/dnsmasq.conf
|
||||||
|
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
|
||||||
|
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
|
||||||
|
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
|
||||||
|
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
|
||||||
|
chown -R root.root debian/daemon
|
||||||
|
chmod -R g-ws debian/daemon
|
||||||
|
dpkg --build debian/daemon ..
|
||||||
|
|
||||||
|
binary-arch: checkroot
|
||||||
|
$(checkdir)
|
||||||
|
rm -rf debian/base
|
||||||
|
install -m 755 \
|
||||||
|
-d debian/base/DEBIAN \
|
||||||
|
-d debian/base/usr/share/doc/$(package) \
|
||||||
|
-d debian/base/usr/share/doc/$(package)/examples \
|
||||||
|
-d debian/base/var/run \
|
||||||
|
-d debian/base/var/lib/misc
|
||||||
|
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
|
||||||
|
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
|
||||||
|
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
|
||||||
|
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
|
||||||
|
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog
|
||||||
|
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
|
||||||
|
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
|
||||||
|
endif
|
||||||
|
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||||
|
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
|
||||||
|
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
|
||||||
|
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
|
||||||
|
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
|
||||||
|
for f in debian/base/usr/share/man/*; do \
|
||||||
|
if [ -f $$f/man8/dnsmasq.8 ]; then \
|
||||||
|
gzip -9 $$f/man8/dnsmasq.8 ; \
|
||||||
|
fi \
|
||||||
|
done
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
|
||||||
|
endif
|
||||||
|
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
|
||||||
|
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
|
||||||
|
chown -R root.root debian/base
|
||||||
|
chmod -R g-ws debian/base
|
||||||
|
dpkg --build debian/base ..
|
||||||
|
|
||||||
|
ifeq ($(DEB_BUILD_ARCH_OS),linux)
|
||||||
|
rm -rf debian/utils
|
||||||
|
install -m 755 -d debian/utils/DEBIAN \
|
||||||
|
-d debian/utils/usr/share/man/man1 \
|
||||||
|
-d debian/utils/usr/bin \
|
||||||
|
-d debian/utils/usr/share/doc/dnsmasq-utils
|
||||||
|
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" COPTS="$(COPTS)" CC=gcc
|
||||||
|
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
|
||||||
|
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
|
||||||
|
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
|
||||||
|
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
|
||||||
|
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
|
||||||
|
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
|
||||||
|
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
endif
|
||||||
|
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
|
||||||
|
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
|
||||||
|
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
|
||||||
|
chown -R root.root debian/utils
|
||||||
|
chmod -R g-ws debian/utils
|
||||||
|
dpkg --build debian/utils ..
|
||||||
|
endif
|
||||||
|
|
||||||
|
define checkdir
|
||||||
|
test -f Makefile -a -f debian/rules
|
||||||
|
endef
|
||||||
|
|
||||||
|
# Below here is fairly generic really
|
||||||
|
|
||||||
|
binary: binary-arch binary-indep
|
||||||
|
build:
|
||||||
|
|
||||||
|
checkroot:
|
||||||
|
test root = "`whoami`"
|
||||||
|
|
||||||
|
.PHONY: binary binary-arch binary-indep clean checkroot
|
||||||
|
|
||||||
|
|
||||||
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
1.0
|
||||||
Vendored
+31
@@ -0,0 +1,31 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=A lightweight DHCP and caching DNS server
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=dbus
|
||||||
|
BusName=uk.org.thekelleys.dnsmasq
|
||||||
|
|
||||||
|
# Test the config file and refuse starting if it is not valid.
|
||||||
|
ExecStartPre=/usr/sbin/dnsmasq --test
|
||||||
|
|
||||||
|
# Enable DBus by default because we use DBus activation.
|
||||||
|
#
|
||||||
|
# Drop privileges and become the 'dnsmasq' user. It is recommended by dnsmasq
|
||||||
|
# upstream to run dnsmasq as an isolated user that does not run any other
|
||||||
|
# processes, owns no files and has no shell. The default 'nobody' user has a
|
||||||
|
# shell and might be used for other processes.
|
||||||
|
#
|
||||||
|
# Debian-specific: add /etc/dnsmasq.d to config search path (with the exception
|
||||||
|
# of .dpkg-*). Packages such as libvirt leave config files there.
|
||||||
|
#
|
||||||
|
# --pid-file without argument disables writing a PIDfile, we don't need one.
|
||||||
|
ExecStart=/usr/sbin/dnsmasq -k \
|
||||||
|
--enable-dbus \
|
||||||
|
--user=dnsmasq \
|
||||||
|
-7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new \
|
||||||
|
--pid-file
|
||||||
|
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -348,6 +348,9 @@
|
|||||||
# external one. (See below for how to enable the TFTP server.)
|
# external one. (See below for how to enable the TFTP server.)
|
||||||
#dhcp-boot=pxelinux.0
|
#dhcp-boot=pxelinux.0
|
||||||
|
|
||||||
|
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||||
|
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||||
|
|
||||||
# Boot for Etherboot gPXE. The idea is to send two different
|
# Boot for Etherboot gPXE. The idea is to send two different
|
||||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||||
@@ -422,6 +425,14 @@
|
|||||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||||
|
|
||||||
|
# If there are multiple external tftp servers having a same name
|
||||||
|
# (using /etc/hosts) then that name can be specified as the
|
||||||
|
# tftp_servername (the third option to dhcp-boot) and in that
|
||||||
|
# case dnsmasq resolves this name and returns the resultant IP
|
||||||
|
# addresses in round robin fasion. This facility can be used to
|
||||||
|
# load balance the tftp load among a set of servers.
|
||||||
|
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||||
|
|
||||||
# Set the limit on DHCP leases, the default is 150
|
# Set the limit on DHCP leases, the default is 150
|
||||||
#dhcp-lease-max=150
|
#dhcp-lease-max=150
|
||||||
|
|
||||||
|
|||||||
+61
-9
@@ -51,7 +51,7 @@ apply to domain names in cnames, PTR records, TXT records etc.
|
|||||||
.B \-T, --local-ttl=<time>
|
.B \-T, --local-ttl=<time>
|
||||||
When replying with information from /etc/hosts or the DHCP leases
|
When replying with information from /etc/hosts or the DHCP leases
|
||||||
file dnsmasq by default sets the time-to-live field to zero, meaning
|
file dnsmasq by default sets the time-to-live field to zero, meaning
|
||||||
that the requestor should not itself cache the information. This is
|
that the requester should not itself cache the information. This is
|
||||||
the correct thing to do in almost all situations. This option allows a
|
the correct thing to do in almost all situations. This option allows a
|
||||||
time-to-live (in seconds) to be given for these replies. This will
|
time-to-live (in seconds) to be given for these replies. This will
|
||||||
reduce the load on the server at the expense of clients using stale
|
reduce the load on the server at the expense of clients using stale
|
||||||
@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
|
|||||||
.B \-r, --resolv-file=<file>
|
.B \-r, --resolv-file=<file>
|
||||||
Read the IP addresses of the upstream nameservers from <file>, instead of
|
Read the IP addresses of the upstream nameservers from <file>, instead of
|
||||||
/etc/resolv.conf. For the format of this file see
|
/etc/resolv.conf. For the format of this file see
|
||||||
.BR resolv.conf (5)
|
.BR resolv.conf (5).
|
||||||
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
The only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
||||||
be told to poll more than one resolv.conf file, the first file name specified
|
be told to poll more than one resolv.conf file, the first file name specified
|
||||||
overrides the default, subsequent ones add to the list. This is only
|
overrides the default, subsequent ones add to the list. This is only
|
||||||
allowed when polling; the file with the currently latest modification
|
allowed when polling; the file with the currently latest modification
|
||||||
@@ -276,7 +276,7 @@ server strictly in the order they appear in /etc/resolv.conf
|
|||||||
By default, when dnsmasq has more than one upstream server available,
|
By default, when dnsmasq has more than one upstream server available,
|
||||||
it will send queries to just one server. Setting this flag forces
|
it will send queries to just one server. Setting this flag forces
|
||||||
dnsmasq to send all queries to all available servers. The reply from
|
dnsmasq to send all queries to all available servers. The reply from
|
||||||
the server which answers first will be returned to the original requestor.
|
the server which answers first will be returned to the original requester.
|
||||||
.TP
|
.TP
|
||||||
.B --stop-dns-rebind
|
.B --stop-dns-rebind
|
||||||
Reject (and log) addresses from upstream nameservers which are in the
|
Reject (and log) addresses from upstream nameservers which are in the
|
||||||
@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
|
|||||||
data than that held in cache.
|
data than that held in cache.
|
||||||
.TP
|
.TP
|
||||||
.B \-D, --domain-needed
|
.B \-D, --domain-needed
|
||||||
Tells dnsmasq to never forward queries for plain names, without dots
|
Tells dnsmasq to never forward A or AAAA queries for plain names, without dots
|
||||||
or domain parts, to upstream nameservers. If the name is not known
|
or domain parts, to upstream nameservers. If the name is not known
|
||||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||||
.TP
|
.TP
|
||||||
@@ -350,6 +350,9 @@ is a synonym for
|
|||||||
.B server
|
.B server
|
||||||
to make configuration files clearer in this case.
|
to make configuration files clearer in this case.
|
||||||
|
|
||||||
|
IPv6 addresses may include a %interface scope-id, eg
|
||||||
|
fe80::202:a412:4512:7bbf%eth0.
|
||||||
|
|
||||||
The optional string after the @ character tells
|
The optional string after the @ character tells
|
||||||
dnsmasq how to set the source of the queries to this
|
dnsmasq how to set the source of the queries to this
|
||||||
nameserver. It should be an ip-address, which should belong to the machine on which
|
nameserver. It should be an ip-address, which should belong to the machine on which
|
||||||
@@ -481,6 +484,16 @@ If you use the first DNSSEC mode, validating resolvers in clients,
|
|||||||
this option is not required. Dnsmasq always returns all the data
|
this option is not required. Dnsmasq always returns all the data
|
||||||
needed for a client to do validation itself.
|
needed for a client to do validation itself.
|
||||||
.TP
|
.TP
|
||||||
|
.B --conntrack
|
||||||
|
Read the Linux connection track mark associated with incoming DNS
|
||||||
|
queries and set the same mark value on upstream traffic used to answer
|
||||||
|
those queries. This allows traffic generated by dnsmasq to be
|
||||||
|
associated with the queries which cause it, useful for bandwidth
|
||||||
|
accounting and firewalling. Dnsmasq must have conntrack support
|
||||||
|
compiled in and the kernel must have conntrack support
|
||||||
|
included and configured. This option cannot be combined with
|
||||||
|
--query-port.
|
||||||
|
.TP
|
||||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
|
.B \-F, --dhcp-range=[interface:<interface>,][tag:<tag>[,tag:<tag>],][set:<tag],]<start-addr>,<end-addr>[,<netmask>[,<broadcast>]][,<lease time>]
|
||||||
Enable the DHCP server. Addresses will be given out from the range
|
Enable the DHCP server. Addresses will be given out from the range
|
||||||
<start-addr> to <end-addr> and from statically defined addresses given
|
<start-addr> to <end-addr> and from statically defined addresses given
|
||||||
@@ -494,8 +507,11 @@ minimum lease time is two minutes. This
|
|||||||
option may be repeated, with different addresses, to enable DHCP
|
option may be repeated, with different addresses, to enable DHCP
|
||||||
service to more than one network. For directly connected networks (ie,
|
service to more than one network. For directly connected networks (ie,
|
||||||
networks on which the machine running dnsmasq has an interface) the
|
networks on which the machine running dnsmasq has an interface) the
|
||||||
netmask is optional. It is, however, required for networks which
|
netmask is optional: dnsmasq will determine it from the interface
|
||||||
receive DHCP service via a relay agent. The broadcast address is
|
configuration. For networks which receive DHCP service via a relay
|
||||||
|
agent, dnsmasq cannot determine the netmask itself, so it should be
|
||||||
|
specified, otherwise dnsmasq will have to guess, based on the class (A, B or
|
||||||
|
C) of the network address. The broadcast address is
|
||||||
always optional. It is always
|
always optional. It is always
|
||||||
allowed to have more than one dhcp-range in a single subnet.
|
allowed to have more than one dhcp-range in a single subnet.
|
||||||
|
|
||||||
@@ -529,7 +545,7 @@ Specify per host parameters for the DHCP server. This allows a machine
|
|||||||
with a particular hardware address to be always allocated the same
|
with a particular hardware address to be always allocated the same
|
||||||
hostname, IP address and lease time. A hostname specified like this
|
hostname, IP address and lease time. A hostname specified like this
|
||||||
overrides any supplied by the DHCP client on the machine. It is also
|
overrides any supplied by the DHCP client on the machine. It is also
|
||||||
allowable to ommit the hardware address and include the hostname, in
|
allowable to omit the hardware address and include the hostname, in
|
||||||
which case the IP address and lease times will apply to any machine
|
which case the IP address and lease times will apply to any machine
|
||||||
claiming that name. For example
|
claiming that name. For example
|
||||||
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
.B --dhcp-host=00:20:e0:3b:13:af,wap,infinite
|
||||||
@@ -845,7 +861,7 @@ to supply no tags, in which case this is unconditional. Most DHCP clients which
|
|||||||
need broadcast replies set a flag in their requests so that this
|
need broadcast replies set a flag in their requests so that this
|
||||||
happens automatically, some old BOOTP clients do not.
|
happens automatically, some old BOOTP clients do not.
|
||||||
.TP
|
.TP
|
||||||
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>]]
|
.B \-M, --dhcp-boot=[tag:<tag>,]<filename>,[<servername>[,<server address>|<tftp_servername>]]
|
||||||
Set BOOTP options to be returned by the DHCP server. Server name and
|
Set BOOTP options to be returned by the DHCP server. Server name and
|
||||||
address are optional: if not provided, the name is left empty, and the
|
address are optional: if not provided, the name is left empty, and the
|
||||||
address set to the address of the machine running dnsmasq. If dnsmasq
|
address set to the address of the machine running dnsmasq. If dnsmasq
|
||||||
@@ -854,6 +870,23 @@ is providing a TFTP service (see
|
|||||||
) then only the filename is required here to enable network booting.
|
) then only the filename is required here to enable network booting.
|
||||||
If the optional tag(s) are given,
|
If the optional tag(s) are given,
|
||||||
they must match for this configuration to be sent.
|
they must match for this configuration to be sent.
|
||||||
|
Instead of an IP address, the TFTP server address can be given as a domain
|
||||||
|
name which is looked up in /etc/hosts. This name can be associated in
|
||||||
|
/etc/hosts with multiple IP addresses, which are used round-robin.
|
||||||
|
This facility can be used to load balance the tftp load among a set of servers.
|
||||||
|
.TP
|
||||||
|
.B --dhcp-sequential-ip
|
||||||
|
Dnsmasq is designed to choose IP addresses for DHCP clients using a
|
||||||
|
hash of the client's MAC address. This normally allows a client's
|
||||||
|
address to remain stable long-term, even if the client sometimes allows its DHCP
|
||||||
|
lease to expire. In this default mode IP addresses are distributed
|
||||||
|
pseudo-randomly over the entire available address range. There are
|
||||||
|
sometimes circumstances (typically server deployment) where it is more
|
||||||
|
convenient to have IP
|
||||||
|
addresses allocated sequentially, starting from the lowest available
|
||||||
|
address, and setting this flag enables this mode. Note that in the
|
||||||
|
sequential mode, clients which allow a lease to expire are much more
|
||||||
|
likely to move IP address; for this reason it should not be generally used.
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
|
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
|
||||||
Most uses of PXE boot-ROMS simply allow the PXE
|
Most uses of PXE boot-ROMS simply allow the PXE
|
||||||
@@ -1101,6 +1134,14 @@ without an address specified when
|
|||||||
.B --dhcp-fqdn
|
.B --dhcp-fqdn
|
||||||
is set.
|
is set.
|
||||||
.TP
|
.TP
|
||||||
|
.B --dhcp-client-update
|
||||||
|
Normally, when giving a DHCP lease, dnsmasq sets flags in the FQDN
|
||||||
|
option to tell the client not to attempt a DDNS update with its name
|
||||||
|
and IP address. This is because the name-IP pair is automatically
|
||||||
|
added into dnsmasq's DNS view. This flag suppresses that behaviour,
|
||||||
|
this is useful, for instance, to allow Windows clients to update
|
||||||
|
Active Directory servers. See RFC 4702 for details.
|
||||||
|
.TP
|
||||||
.B --enable-tftp[=<interface>]
|
.B --enable-tftp[=<interface>]
|
||||||
Enable the TFTP server function. This is deliberately limited to that
|
Enable the TFTP server function. This is deliberately limited to that
|
||||||
needed to net-boot a client. Only reading is allowed; the tsize and
|
needed to net-boot a client. Only reading is allowed; the tsize and
|
||||||
@@ -1324,6 +1365,17 @@ so --dhcp=option=tag:!purple,3,1.2.3.4 sends the option when the
|
|||||||
tag purple is not in the set of valid tags. (If using this in a
|
tag purple is not in the set of valid tags. (If using this in a
|
||||||
command line rather than a configuration file, be sure to escape !,
|
command line rather than a configuration file, be sure to escape !,
|
||||||
which is a shell metacharacter)
|
which is a shell metacharacter)
|
||||||
|
|
||||||
|
When selecting dhcp-options, a tag from dhcp-range is second class
|
||||||
|
relative to other tags, to make it easy to override options for
|
||||||
|
individual hosts, so
|
||||||
|
.B dhcp-range=set:interface1,......
|
||||||
|
.B dhcp-host=set:myhost,.....
|
||||||
|
.B dhcp-option=tag:interface1,option:nis-domain,"domain1"
|
||||||
|
.B dhcp-option=tag:myhost,option:nis-domain,"domain2"
|
||||||
|
will set the NIS-domain to domain1 for hosts in the range, but
|
||||||
|
override that to domain2 for a particular host.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Note that for
|
Note that for
|
||||||
.B dhcp-range
|
.B dhcp-range
|
||||||
|
|||||||
+61
-9
@@ -347,10 +347,10 @@ Cela est utile si les nouveaux serveurs sont susceptibles d'avoir des données
|
|||||||
différentes de celles stockées dans le cache.
|
différentes de celles stockées dans le cache.
|
||||||
.TP
|
.TP
|
||||||
.B \-D, --domain-needed
|
.B \-D, --domain-needed
|
||||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms
|
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
|
||||||
simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas
|
des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
|
||||||
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type
|
nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
|
||||||
"non trouvé" est renvoyée.
|
de type "non trouvé" est renvoyée.
|
||||||
.TP
|
.TP
|
||||||
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
|
.B \-S, --local, --server=[/[<domaine>]/[domaine/]][<Adresse IP>[#<port>][@<Adresse IP source>|<interface>[#<port>]]]
|
||||||
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
|
Spécifie directement l'adresse IP d'un serveur de nom amont. Cette option ne
|
||||||
@@ -402,6 +402,10 @@ est synonyme de
|
|||||||
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
||||||
usage particulier.
|
usage particulier.
|
||||||
|
|
||||||
|
Les adresses IPv6 peuvent inclure un identifiant de zone sous la forme
|
||||||
|
%interface tel que par exemple
|
||||||
|
fe80::202:a412:4512:7bbf%eth0.
|
||||||
|
|
||||||
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
|
La chaîne de caractères optionnelle suivant le caractère @ permet de définir
|
||||||
la source que Dnsmasq doit utiliser pour les réponses à ce
|
la source que Dnsmasq doit utiliser pour les réponses à ce
|
||||||
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
|
serveur de nom. Il doit s'agir d'une des adresses IP appartenant à la machine sur
|
||||||
@@ -565,6 +569,16 @@ Si vous utilisez le premier mode DNSSEC, la validation par le resolveur des
|
|||||||
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
clients, cette option n'est pas requise. Dnsmasq retourne toujours toutes les
|
||||||
données nécessaires par un client pour effectuer la validation lui-même.
|
données nécessaires par un client pour effectuer la validation lui-même.
|
||||||
.TP
|
.TP
|
||||||
|
.B --conntrack
|
||||||
|
Lis le marquage de suivi de connexion Linux associé aux requêtes DNS entrantes
|
||||||
|
et positionne la même marque au trafic amont utilisé pour répondre à ces
|
||||||
|
requétes. Cela permet au trafic généré par Dnsmasq d'étre associé aux requêtes
|
||||||
|
l'ayant déclenché, ce qui est pratique pour la gestion de la bande passante
|
||||||
|
(accounting) et le filtrage (firewall). Dnsmasq doit pour cela être compilé
|
||||||
|
avec le support conntrack, le noyau doit également inclure conntrack et être
|
||||||
|
configuré pour cela. Cette option ne peut pas être combinée avec
|
||||||
|
--query-port.
|
||||||
|
.TP
|
||||||
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
.B \-F, --dhcp-range=[interface:<interface>,][tag:<label>[,tag:<label>],][set:<label],]<adresse de début>,<adresse de fin>[,<masque de réseau>[,<broadcast>]][,<durée de bail>]
|
||||||
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
Active le serveur DHCP. Les adresses seront données dans la plage comprise entre
|
||||||
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
<adresse de début> et <adresse de fin> et à partir des adresses définies
|
||||||
@@ -579,9 +593,14 @@ minutes.
|
|||||||
Cette option peut être répétée, avec différentes adresses,
|
Cette option peut être répétée, avec différentes adresses,
|
||||||
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
|
pour activer le service DHCP sur plus d'un réseau. Pour des réseaux directement
|
||||||
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
|
connectés (c'est-à-dire des réseaux dans lesquels la machine sur laquelle tourne
|
||||||
Dnsmasq possède une interface), le masque de réseau est optionnel. Il est par
|
Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
|
||||||
contre requis pour les réseaux pour lesquels le service DHCP se fait via un
|
déterminera à partir de la configuration des interfaces.
|
||||||
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
|
|
||||||
|
Pour les réseaux pour lesquels le service DHCP se fait via un relais DHCP
|
||||||
|
("relay agent"), Dnsmasq est incapable de déterminer le masque par lui-même,
|
||||||
|
aussi il doit être spécifié, faute de quoi Dnsmasq essaiera de le deviner en
|
||||||
|
fonction de la classe (A, B ou C) de l'adresse réseau. L'adresse de broadcast
|
||||||
|
est toujours optionnelle.
|
||||||
|
|
||||||
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
|
Il est toujours possible d'avoir plus d'une plage DHCP pour un même
|
||||||
sous-réseau.
|
sous-réseau.
|
||||||
@@ -969,7 +988,7 @@ option s'applique inconditionnellement. La plupart des clients DHCP nécessitant
|
|||||||
d'un broadcast activent une option dans leur requête, ce qui fait que cela
|
d'un broadcast activent une option dans leur requête, ce qui fait que cela
|
||||||
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
|
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
|
||||||
.TP
|
.TP
|
||||||
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>]]
|
.B \-M, --dhcp-boot=[tag:<label>,]<nom de fichier>,[<nom de serveur>[,<adresse de serveur>|<nom du serveur tftp>]]
|
||||||
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
|
Spécifie les options BOOTP devant être retournées par le serveur DHCP. Le nom de
|
||||||
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
|
serveur ainsi que l'adresse sont optionnels : s'ils ne sont pas fournis, le nom
|
||||||
est laissé vide et l'adresse fournie est celle de la machine sur laquelle
|
est laissé vide et l'adresse fournie est celle de la machine sur laquelle
|
||||||
@@ -979,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
|||||||
le réseau.
|
le réseau.
|
||||||
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
||||||
ceux du client pour que cet élement de configuration lui soit envoyé.
|
ceux du client pour que cet élement de configuration lui soit envoyé.
|
||||||
|
Une adresse de serveur TFTP peut être spécifiée à la place de l'adresse IP,
|
||||||
|
sous la forme d'un nom de domaine qui sera cherché dans le fichier /etc/hosts.
|
||||||
|
Ce nom peut être associé dans /etc/hosts avec plusieurs adresses IP, auquel cas
|
||||||
|
celles-ci seront utilisées tour à tour (algorithme round-robin).
|
||||||
|
Cela peut-être utiliser pour équilibrer la charge tftp sur plusieurs serveurs.
|
||||||
|
.TP
|
||||||
|
.B --dhcp-sequential-ip
|
||||||
|
Dnsmasq est conçu pour choisir l'adresse IP des clients DHCP en utilisant
|
||||||
|
un hachage de l'adresse MAC du client. Cela permet en général à l'adresse
|
||||||
|
IP du client de rester stable au fil du temps, même lorsque le client laisse
|
||||||
|
expirer son bail DHCP de temps en temps. Dans ce mode de fonctionnement par
|
||||||
|
défaut, les adresses IP sont distribuées de façon pseudo-aléatoire dans la
|
||||||
|
totalité de la plage d'adresses utilisable. Il existe des circonstances (par
|
||||||
|
exemples pour du déploiement de serveur) où il est plus pratique d'allouer les
|
||||||
|
adresses IP de manière séquentielle, en commençant par la plus petite adresse
|
||||||
|
disponible, et c'est ce mode de fonctionnement qui est permis par cette option.
|
||||||
|
Veuillez noter que dans ce mode séquentiel, les clients qui laissent expirer
|
||||||
|
leur bail ont beaucoup plus de chance de voir leur adresse IP changer, aussi
|
||||||
|
cette option ne devrait pas être utilisée dans un cas général.
|
||||||
.TP
|
.TP
|
||||||
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
|
.B --pxe-service=[tag:<label>,]<CSA>,<entrée de menu>[,<nom de fichier>|<type de service de démarrage>][,<adresse de serveur>]
|
||||||
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
|
La plupart des ROMS de démarrage PXE ne permettent au système PXE que la simple
|
||||||
@@ -1417,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
|
|||||||
.B create
|
.B create
|
||||||
et
|
et
|
||||||
.B delaycompress.
|
.B delaycompress.
|
||||||
|
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
||||||
@@ -1509,6 +1546,21 @@ labels définis pour l'hôte considéré. (dans le cas de l'utilisation dans une
|
|||||||
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
|
ligne de commande au lieu d'un fichier de configuration, ne pas oublier
|
||||||
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
||||||
shell).
|
shell).
|
||||||
|
|
||||||
|
+When selecting dhcp-options, a tag from dhcp-range is second class
|
||||||
|
+relative to other tags, to make it easy to override options for
|
||||||
|
+individual hosts, so
|
||||||
|
|
||||||
|
Lors de la sélection d'une option, une étiquette spécifiée par dhcp-range
|
||||||
|
passe après les autres étiquettes, ce qui permet de facilement remplacer des
|
||||||
|
option génériques pour des hôtes spécifiques, ainsi :
|
||||||
|
.B dhcp-range=set:interface1,......
|
||||||
|
.B dhcp-host=set:monhote,.....
|
||||||
|
.B dhcp-option=tag:interface1,option:nis-domain,"domaine1"
|
||||||
|
.B dhcp-option=tag:monhote,option:nis-domain,"domaine2"
|
||||||
|
va positionner l'option NIS-domain à domaine1 pour les hôtes dans la plage
|
||||||
|
d'adresse, sauf pour monhote pour lequel cette valeur sera domaine2.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Veuillez noter que pour
|
Veuillez noter que pour
|
||||||
.B dhcp-range
|
.B dhcp-range
|
||||||
|
|||||||
+504
-433
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
|
|||||||
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
Sending SIGHUP to the dnsmasq process will cause it to empty its cache and
|
||||||
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
then re-load <TT>/etc/hosts</TT> and <TT>/etc/resolv.conf</TT>.
|
||||||
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
<P> Sending SIGUSR1 (killall -10 dnsmasq) to the dnsmasq process will
|
||||||
cause to to write cache usage statisticss to the log, typically
|
cause to write cache usage statisticss to the log, typically
|
||||||
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
<TT>/var/log/syslog</TT> or <TT>/var/log/messages</TT>.
|
||||||
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
<P> The <TT>log-queries</TT> option tells dnsmasq to verbosely log the queries
|
||||||
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
it is handling and causes SIGUSR1 to trigger a complete dump of the
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ static struct iovec ifreq = {
|
|||||||
#include <net/if_dl.h>
|
#include <net/if_dl.h>
|
||||||
#include <netinet/if_ether.h>
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
|
#ifndef SA_SIZE
|
||||||
|
#define SA_SIZE(sa) \
|
||||||
|
( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
|
||||||
|
sizeof(long) : \
|
||||||
|
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
|
||||||
|
#endif
|
||||||
|
|
||||||
int arp_enumerate(void *parm, int (*callback)())
|
int arp_enumerate(void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
int mib[6];
|
int mib[6];
|
||||||
@@ -175,9 +182,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
addr->s6_addr[2] = 0;
|
addr->s6_addr[2] = 0;
|
||||||
addr->s6_addr[3] = 0;
|
addr->s6_addr[3] = 0;
|
||||||
}
|
}
|
||||||
if (!((*callback)(addr,
|
/* We have no way to determine the prefix, so we assume it's 64 for now....... */
|
||||||
|
if (!((*callback)(addr, 64,
|
||||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||||
(int)if_nametoindex(ifr->ifr_name),
|
(int)if_nametoindex(ifr->ifr_name), 0,
|
||||||
parm)))
|
parm)))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-16
@@ -25,7 +25,6 @@ static int cache_inserted = 0, cache_live_freed = 0, insert_error;
|
|||||||
static union bigname *big_free = NULL;
|
static union bigname *big_free = NULL;
|
||||||
static int bignames_left, hash_size;
|
static int bignames_left, hash_size;
|
||||||
static int uid = 0;
|
static int uid = 0;
|
||||||
static char *addrbuff = NULL;
|
|
||||||
|
|
||||||
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
/* type->string mapping: this is also used by the name-hash function as a mixing table. */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -75,9 +74,6 @@ void cache_init(void)
|
|||||||
struct crec *crecp;
|
struct crec *crecp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (option_bool(OPT_LOG))
|
|
||||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
|
||||||
|
|
||||||
bignames_left = daemon->cachesize/10;
|
bignames_left = daemon->cachesize/10;
|
||||||
|
|
||||||
if (daemon->cachesize > 0)
|
if (daemon->cachesize > 0)
|
||||||
@@ -922,6 +918,21 @@ char *get_domain(struct in_addr addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
|
struct in_addr a_record_from_hosts(char *name, time_t now)
|
||||||
|
{
|
||||||
|
struct crec *crecp = NULL;
|
||||||
|
struct in_addr ret;
|
||||||
|
|
||||||
|
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
|
||||||
|
if (crecp->flags & F_HOSTS)
|
||||||
|
return *(struct in_addr *)&crecp->addr;
|
||||||
|
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
|
||||||
|
|
||||||
|
ret.s_addr = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void cache_unhash_dhcp(void)
|
void cache_unhash_dhcp(void)
|
||||||
{
|
{
|
||||||
struct crec *cache, **up;
|
struct crec *cache, **up;
|
||||||
@@ -1042,9 +1053,6 @@ void dump_cache(time_t now)
|
|||||||
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
my_syslog(LOG_INFO, _("queries forwarded %u, queries answered locally %u"),
|
||||||
daemon->queries_forwarded, daemon->local_answer);
|
daemon->queries_forwarded, daemon->local_answer);
|
||||||
|
|
||||||
if (!addrbuff && !(addrbuff = whine_malloc(ADDRSTRLEN)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* sum counts from different records for same server */
|
/* sum counts from different records for same server */
|
||||||
for (serv = daemon->servers; serv; serv = serv->next)
|
for (serv = daemon->servers; serv; serv = serv->next)
|
||||||
serv->flags &= ~SERV_COUNTED;
|
serv->flags &= ~SERV_COUNTED;
|
||||||
@@ -1064,8 +1072,8 @@ void dump_cache(time_t now)
|
|||||||
queries += serv1->queries;
|
queries += serv1->queries;
|
||||||
failed_queries += serv1->failed_queries;
|
failed_queries += serv1->failed_queries;
|
||||||
}
|
}
|
||||||
port = prettyprint_addr(&serv->addr, addrbuff);
|
port = prettyprint_addr(&serv->addr, daemon->addrbuff);
|
||||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), daemon->addrbuff, port, queries, failed_queries);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||||
@@ -1090,11 +1098,11 @@ void dump_cache(time_t now)
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a = addrbuff;
|
a = daemon->addrbuff;
|
||||||
if (cache->flags & F_IPV4)
|
if (cache->flags & F_IPV4)
|
||||||
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
else if (cache->flags & F_IPV6)
|
else if (cache->flags & F_IPV6)
|
||||||
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &cache->addr.addr, a, ADDRSTRLEN);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
else
|
else
|
||||||
@@ -1149,7 +1157,7 @@ void querystr(char *str, unsigned short type)
|
|||||||
|
|
||||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
||||||
{
|
{
|
||||||
char *source, *dest = addrbuff;
|
char *source, *dest = daemon->addrbuff;
|
||||||
char *verb = "is";
|
char *verb = "is";
|
||||||
|
|
||||||
if (!option_bool(OPT_LOG))
|
if (!option_bool(OPT_LOG))
|
||||||
@@ -1159,16 +1167,16 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
|
|||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||||
addr, addrbuff, ADDRSTRLEN);
|
addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
#else
|
#else
|
||||||
strncpy(addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
strncpy(daemon->addrbuff, inet_ntoa(addr->addr.addr4), ADDRSTRLEN);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_REVERSE)
|
if (flags & F_REVERSE)
|
||||||
{
|
{
|
||||||
dest = name;
|
dest = name;
|
||||||
name = addrbuff;
|
name = daemon->addrbuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & F_NEG)
|
if (flags & F_NEG)
|
||||||
|
|||||||
+206
-119
@@ -14,8 +14,6 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define VERSION "2.57"
|
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||||
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||||
@@ -34,12 +32,102 @@
|
|||||||
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
#define SMALLDNAME 40 /* most domain names are smaller than this */
|
||||||
#define HOSTSFILE "/etc/hosts"
|
#define HOSTSFILE "/etc/hosts"
|
||||||
#define ETHERSFILE "/etc/ethers"
|
#define ETHERSFILE "/etc/ethers"
|
||||||
#ifdef __uClinux__
|
|
||||||
# define RESOLVFILE "/etc/config/resolv.conf"
|
|
||||||
#else
|
|
||||||
# define RESOLVFILE "/etc/resolv.conf"
|
|
||||||
#endif
|
|
||||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||||
|
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||||
|
#define CHUSER "nobody"
|
||||||
|
#define CHGRP "dip"
|
||||||
|
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
||||||
|
#define LOG_MAX 5 /* log-queue length */
|
||||||
|
#define RANDFILE "/dev/urandom"
|
||||||
|
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
||||||
|
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* DBUS interface specifics */
|
||||||
|
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
||||||
|
|
||||||
|
/* compile-time options: uncomment below to enable or do eg.
|
||||||
|
make COPTS=-DHAVE_BROKEN_RTC
|
||||||
|
|
||||||
|
HAVE_BROKEN_RTC
|
||||||
|
define this on embedded systems which don't have an RTC
|
||||||
|
which keeps time over reboots. Causes dnsmasq to use uptime
|
||||||
|
for timing, and keep lease lengths rather than expiry times
|
||||||
|
in its leases file. This also make dnsmasq "flash disk friendly".
|
||||||
|
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
||||||
|
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
||||||
|
is in effect, the lease file is only written when a new lease is
|
||||||
|
created, or an old one destroyed. (Because those are the only times
|
||||||
|
it changes.) This vastly reduces the number of file writes, and makes
|
||||||
|
it viable to keep the lease file on a flash filesystem.
|
||||||
|
NOTE: when enabling or disabling this, be sure to delete any old
|
||||||
|
leases file, otherwise dnsmasq may get very confused.
|
||||||
|
|
||||||
|
HAVE_TFTP
|
||||||
|
define this to get dnsmasq's built-in TFTP server.
|
||||||
|
|
||||||
|
HAVE_DHCP
|
||||||
|
define this to get dnsmasq's DHCPv4 server.
|
||||||
|
|
||||||
|
HAVE_DHCP6
|
||||||
|
define this to get dnsmasq's DHCPv6 server. (implies HAVE_DHCP).
|
||||||
|
|
||||||
|
HAVE_SCRIPT
|
||||||
|
define this to get the ability to call scripts on lease-change.
|
||||||
|
|
||||||
|
HAVE_LUASCRIPT
|
||||||
|
define this to get the ability to call Lua script on lease-change. (implies HAVE_SCRIPT)
|
||||||
|
|
||||||
|
HAVE_DBUS
|
||||||
|
define this if you want to link against libdbus, and have dnsmasq
|
||||||
|
support some methods to allow (re)configuration of the upstream DNS
|
||||||
|
servers via DBus.
|
||||||
|
|
||||||
|
HAVE_IDN
|
||||||
|
define this if you want international domain name support.
|
||||||
|
NOTE: for backwards compatibility, IDN support is automatically
|
||||||
|
included when internationalisation support is built, using the
|
||||||
|
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||||
|
|
||||||
|
HAVE_CONNTRACK
|
||||||
|
define this to include code which propogates conntrack marks from
|
||||||
|
incoming DNS queries to the corresponding upstream queries. This adds
|
||||||
|
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||||
|
still run happily on a kernel without conntrack support.
|
||||||
|
|
||||||
|
NO_IPV6
|
||||||
|
NO_TFTP
|
||||||
|
NO_DHCP
|
||||||
|
NO_DHCP6
|
||||||
|
NO_SCRIPT
|
||||||
|
NO_LARGEFILE
|
||||||
|
these are avilable to explictly disable compile time options which would
|
||||||
|
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
|
||||||
|
which are enabled by default in the distributed source tree. Building dnsmasq
|
||||||
|
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
|
||||||
|
|
||||||
|
LEASEFILE
|
||||||
|
CONFFILE
|
||||||
|
RESOLVFILE
|
||||||
|
the default locations of these files are determined below, but may be overridden
|
||||||
|
in a build command line using COPTS.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* The default set of options to build. Built with these options, dnsmasq
|
||||||
|
has no library dependencies other than libc */
|
||||||
|
|
||||||
|
#define HAVE_DHCP
|
||||||
|
/* #define HAVE_DHCP6 */
|
||||||
|
#define HAVE_TFTP
|
||||||
|
#define HAVE_SCRIPT
|
||||||
|
/* #define HAVE_LUASCRIPT */
|
||||||
|
/* #define HAVE_BROKEN_RTC */
|
||||||
|
/* #define HAVE_DBUS */
|
||||||
|
/* #define HAVE_IDN */
|
||||||
|
/* #define HAVE_CONNTRACK */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Default locations for important system files. */
|
||||||
|
|
||||||
#ifndef LEASEFILE
|
#ifndef LEASEFILE
|
||||||
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
# if defined(__FreeBSD__) || defined (__OpenBSD__) || defined(__DragonFly__) || defined(__NetBSD__)
|
||||||
@@ -61,124 +149,34 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
#ifndef RESOLVFILE
|
||||||
#define CHUSER "nobody"
|
# if defined(__uClinux__)
|
||||||
#define CHGRP "dip"
|
# define RESOLVFILE "/etc/config/resolv.conf"
|
||||||
#define NAMESERVER_PORT 53
|
# else
|
||||||
#define DHCP_SERVER_PORT 67
|
# define RESOLVFILE "/etc/resolv.conf"
|
||||||
#define DHCP_CLIENT_PORT 68
|
# endif
|
||||||
#define DHCP_SERVER_ALTPORT 1067
|
#endif
|
||||||
#define DHCP_CLIENT_ALTPORT 1068
|
|
||||||
#define PXE_PORT 4011
|
|
||||||
#define TFTP_PORT 69
|
|
||||||
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
|
|
||||||
#define LOG_MAX 5 /* log-queue length */
|
|
||||||
#define RANDFILE "/dev/urandom"
|
|
||||||
#define DAD_WAIT 20 /* retry binding IPv6 sockets for this long */
|
|
||||||
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
|
|
||||||
|
|
||||||
/* DBUS interface specifics */
|
|
||||||
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq"
|
|
||||||
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
|
|
||||||
|
|
||||||
/* Follows system specific switches. If you run on a
|
|
||||||
new system, you may want to edit these.
|
/* platform dependent options: these are determined automatically below
|
||||||
May replace this with Autoconf one day.
|
|
||||||
|
|
||||||
HAVE_LINUX_NETWORK
|
HAVE_LINUX_NETWORK
|
||||||
HAVE_BSD_NETWORK
|
HAVE_BSD_NETWORK
|
||||||
HAVE_SOLARIS_NETWORK
|
HAVE_SOLARIS_NETWORK
|
||||||
define exactly one of these to alter interaction with kernel networking.
|
define exactly one of these to alter interaction with kernel networking.
|
||||||
|
|
||||||
HAVE_BROKEN_RTC
|
|
||||||
define this on embedded systems which don't have an RTC
|
|
||||||
which keeps time over reboots. Causes dnsmasq to use uptime
|
|
||||||
for timing, and keep lease lengths rather than expiry times
|
|
||||||
in its leases file. This also make dnsmasq "flash disk friendly".
|
|
||||||
Normally, dnsmasq tries very hard to keep the on-disk leases file
|
|
||||||
up-to-date: rewriting it after every renewal. When HAVE_BROKEN_RTC
|
|
||||||
is in effect, the lease file is only written when a new lease is
|
|
||||||
created, or an old one destroyed. (Because those are the only times
|
|
||||||
it changes.) This vastly reduces the number of file writes, and makes
|
|
||||||
it viable to keep the lease file on a flash filesystem.
|
|
||||||
NOTE: when enabling or disabling this, be sure to delete any old
|
|
||||||
leases file, otherwise dnsmasq may get very confused.
|
|
||||||
|
|
||||||
HAVE_TFTP
|
|
||||||
define this to get dnsmasq's built-in TFTP server.
|
|
||||||
|
|
||||||
HAVE_DHCP
|
|
||||||
define this to get dnsmasq's DHCP server.
|
|
||||||
|
|
||||||
HAVE_SCRIPT
|
|
||||||
define this to get the ability to call scripts on lease-change
|
|
||||||
|
|
||||||
HAVE_GETOPT_LONG
|
HAVE_GETOPT_LONG
|
||||||
define this if you have GNU libc or GNU getopt.
|
defined when GNU-sty;e getopt_long available.
|
||||||
|
|
||||||
HAVE_ARC4RANDOM
|
HAVE_ARC4RANDOM
|
||||||
define this if you have arc4random() to get better security from DNS spoofs
|
defined if arc4random() available to get better security from DNS spoofs
|
||||||
by using really random ids (OpenBSD)
|
by using really random ids (OpenBSD)
|
||||||
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
HAVE_SOCKADDR_SA_LEN
|
||||||
define this if struct sockaddr has sa_len field (*BSD)
|
defined if struct sockaddr has sa_len field (*BSD)
|
||||||
|
|
||||||
HAVE_DBUS
|
|
||||||
define this if you want to link against libdbus, and have dnsmasq
|
|
||||||
support some methods to allow (re)configuration of the upstream DNS
|
|
||||||
servers via DBus.
|
|
||||||
|
|
||||||
HAVE_IDN
|
|
||||||
define this if you want international domain name support.
|
|
||||||
NOTE: for backwards compatibility, IDN support is automatically
|
|
||||||
included when internationalisation support is built, using the
|
|
||||||
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
|
||||||
|
|
||||||
NOTES:
|
|
||||||
For Linux you should define
|
|
||||||
HAVE_LINUX_NETWORK
|
|
||||||
HAVE_GETOPT_LONG
|
|
||||||
you should NOT define
|
|
||||||
HAVE_ARC4RANDOM
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
|
|
||||||
For *BSD systems you should define
|
|
||||||
HAVE_BSD_NETWORK
|
|
||||||
HAVE_SOCKADDR_SA_LEN
|
|
||||||
and you MAY define
|
|
||||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
|
||||||
HAVE_GETOPT_LONG - NetBSD, later FreeBSD
|
|
||||||
(FreeBSD and OpenBSD only if you link GNU getopt)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* platform independent options- uncomment to enable */
|
|
||||||
#define HAVE_DHCP
|
|
||||||
#define HAVE_TFTP
|
|
||||||
#define HAVE_SCRIPT
|
|
||||||
/* #define HAVE_BROKEN_RTC */
|
|
||||||
/* #define HAVE_DBUS */
|
|
||||||
/* #define HAVE_IDN */
|
|
||||||
|
|
||||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
|
||||||
#ifdef NO_TFTP
|
|
||||||
#undef HAVE_TFTP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allow DHCP to be disabled with COPTS=-DNO_DHCP */
|
|
||||||
#ifdef NO_DHCP
|
|
||||||
#undef HAVE_DHCP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Allow scripts to be disabled with COPTS=-DNO_SCRIPT */
|
|
||||||
#ifdef NO_SCRIPT
|
|
||||||
#undef HAVE_SCRIPT
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* platform dependent options. */
|
|
||||||
|
|
||||||
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
/* Must preceed __linux__ since uClinux defines __linux__ too. */
|
||||||
#if defined(__uClinux__)
|
#if defined(__uClinux__)
|
||||||
#define HAVE_LINUX_NETWORK
|
#define HAVE_LINUX_NETWORK
|
||||||
@@ -253,18 +251,12 @@ NOTES:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Decide if we're going to support IPv6 */
|
/* Decide if we're going to support IPv6 */
|
||||||
/* IPv6 can be forced off with "make COPTS=-DNO_IPV6" */
|
|
||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
headers don't have ntop and pton either */
|
||||||
|
|
||||||
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
|
||||||
# define HAVE_IPV6
|
# define HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||||
# if defined(SOL_IPV6)
|
|
||||||
# define IPV6_LEVEL SOL_IPV6
|
|
||||||
# else
|
|
||||||
# define IPV6_LEVEL IPPROTO_IPV6
|
|
||||||
# endif
|
|
||||||
#elif defined(INET_ADDRSTRLEN)
|
#elif defined(INET_ADDRSTRLEN)
|
||||||
# undef HAVE_IPV6
|
# undef HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET_ADDRSTRLEN
|
# define ADDRSTRLEN INET_ADDRSTRLEN
|
||||||
@@ -273,8 +265,103 @@ NOTES:
|
|||||||
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Can't do scripts without fork */
|
|
||||||
#ifdef NOFORK
|
/* rules to implement compile-time option dependencies and
|
||||||
# undef HAVE_SCRIPT
|
the NO_XXX flags */
|
||||||
|
|
||||||
|
#ifdef NO_IPV6
|
||||||
|
#undef HAVE_IPV6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_TFTP
|
||||||
|
#undef HAVE_TFTP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NO_DHCP
|
||||||
|
#undef HAVE_DHCP
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
|
||||||
|
#undef HAVE_DHCP6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* DHCP6 needs DHCP too */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#define HAVE_DHCP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
|
||||||
|
#undef HAVE_SCRIPT
|
||||||
|
#undef HAVE_LUASCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Must HAVE_SCRIPT to HAVE_LUASCRIPT */
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#define HAVE_SCRIPT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Define a string indicating which options are in use.
|
||||||
|
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
|
||||||
|
|
||||||
|
#ifdef DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
|
static char *compile_opts =
|
||||||
|
#ifndef HAVE_IPV6
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IPv6 "
|
||||||
|
#ifndef HAVE_GETOPT_LONG
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"GNU-getopt "
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
"no-RTC "
|
||||||
|
#endif
|
||||||
|
#ifdef NO_FORK
|
||||||
|
"no-MMU "
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_DBUS
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DBus "
|
||||||
|
#ifndef LOCALEDIR
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"i18n "
|
||||||
|
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"IDN "
|
||||||
|
#ifndef HAVE_DHCP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"DHCP "
|
||||||
|
#if defined(HAVE_DHCP)
|
||||||
|
# if !defined (HAVE_DHCP6)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"DHCPv6 "
|
||||||
|
# if !defined(HAVE_SCRIPT)
|
||||||
|
"no-scripts "
|
||||||
|
# else
|
||||||
|
# if !defined(HAVE_LUASCRIPT)
|
||||||
|
"no-"
|
||||||
|
# endif
|
||||||
|
"Lua "
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef HAVE_TFTP
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"TFTP "
|
||||||
|
#ifndef HAVE_CONNTRACK
|
||||||
|
"no-"
|
||||||
|
#endif
|
||||||
|
"conntrack";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
|
||||||
|
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
||||||
|
|
||||||
|
static int gotit = 0; /* yuck */
|
||||||
|
|
||||||
|
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data);
|
||||||
|
|
||||||
|
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr, int istcp, unsigned int *markp)
|
||||||
|
{
|
||||||
|
struct nf_conntrack *ct;
|
||||||
|
struct nfct_handle *h;
|
||||||
|
|
||||||
|
gotit = 0;
|
||||||
|
|
||||||
|
if ((ct = nfct_new()))
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L4PROTO, istcp ? IPPROTO_TCP : IPPROTO_UDP);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(daemon->port));
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (peer_addr->sa.sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
|
||||||
|
nfct_set_attr(ct, ATTR_IPV6_SRC, peer_addr->in6.sin6_addr.s6_addr);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in6.sin6_port);
|
||||||
|
nfct_set_attr(ct, ATTR_IPV6_DST, local_addr->addr.addr6.s6_addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
|
||||||
|
nfct_set_attr_u32(ct, ATTR_IPV4_SRC, peer_addr->in.sin_addr.s_addr);
|
||||||
|
nfct_set_attr_u16(ct, ATTR_PORT_SRC, peer_addr->in.sin_port);
|
||||||
|
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ((h = nfct_open(CONNTRACK, 0)))
|
||||||
|
{
|
||||||
|
nfct_callback_register(h, NFCT_T_ALL, callback, (void *)markp);
|
||||||
|
if (nfct_query(h, NFCT_Q_GET, ct) == -1)
|
||||||
|
{
|
||||||
|
static int warned = 0;
|
||||||
|
if (!warned)
|
||||||
|
{
|
||||||
|
my_syslog(LOG_ERR, _("Conntrack connection mark retrieval failed: %s"), strerror(errno));
|
||||||
|
warned = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nfct_close(h);
|
||||||
|
}
|
||||||
|
nfct_destroy(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gotit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data)
|
||||||
|
{
|
||||||
|
unsigned int *ret = (unsigned int *)data;
|
||||||
|
*ret = nfct_get_attr_u32(ct, ATTR_MARK);
|
||||||
|
(void)type; /* eliminate warning */
|
||||||
|
gotit = 1;
|
||||||
|
|
||||||
|
return NFCT_CB_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+210
-139
@@ -19,13 +19,19 @@
|
|||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
|
|
||||||
struct iface_param {
|
struct iface_param {
|
||||||
struct in_addr relay, primary;
|
|
||||||
struct dhcp_context *current;
|
struct dhcp_context *current;
|
||||||
int ind;
|
int ind;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct match_param {
|
||||||
|
int ind, matched;
|
||||||
|
struct in_addr netmask, broadcast, addr;
|
||||||
|
};
|
||||||
|
|
||||||
static int complete_context(struct in_addr local, int if_index,
|
static int complete_context(struct in_addr local, int if_index,
|
||||||
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam);
|
||||||
|
|
||||||
static int make_fd(int port)
|
static int make_fd(int port)
|
||||||
{
|
{
|
||||||
@@ -35,16 +41,22 @@ static int make_fd(int port)
|
|||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
int mtu = IP_PMTUDISC_DONT;
|
int mtu = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
int tos = IPTOS_CLASS_CS6;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
die (_("cannot create DHCP socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
if (!fix_fd(fd) ||
|
if (!fix_fd(fd) ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(fd, SOL_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu, sizeof(mtu)) == -1 ||
|
||||||
|
#endif
|
||||||
|
#if defined(IP_TOS) && defined(IPTOS_CLASS_CS6)
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#else
|
#else
|
||||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
@@ -111,7 +123,41 @@ void dhcp_init(void)
|
|||||||
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
daemon->dhcp_packet.iov_len = sizeof(struct dhcp_packet);
|
||||||
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
daemon->dhcp_packet.iov_base = safe_malloc(daemon->dhcp_packet.iov_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
|
||||||
|
{
|
||||||
|
ssize_t sz;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
msg->msg_flags = 0;
|
||||||
|
while ((sz = recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (sz == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!(msg->msg_flags & MSG_TRUNC))
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Very new Linux kernels return the actual size needed,
|
||||||
|
older ones always return truncated size */
|
||||||
|
if ((size_t)sz == daemon->dhcp_packet.iov_len)
|
||||||
|
{
|
||||||
|
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expand_buf(&daemon->dhcp_packet, sz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
|
||||||
|
}
|
||||||
|
|
||||||
void dhcp_packet(time_t now, int pxe_fd)
|
void dhcp_packet(time_t now, int pxe_fd)
|
||||||
{
|
{
|
||||||
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
|
||||||
@@ -125,7 +171,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
ssize_t sz;
|
ssize_t sz;
|
||||||
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
int iface_index = 0, unicast_dest = 0, is_inform = 0;
|
||||||
struct in_addr iface_addr, *addrp = NULL;
|
struct in_addr iface_addr;
|
||||||
struct iface_param parm;
|
struct iface_param parm;
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
struct arpreq arp_req;
|
struct arpreq arp_req;
|
||||||
@@ -141,56 +187,23 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
char control[CMSG_SPACE(sizeof(struct sockaddr_dl))];
|
||||||
#endif
|
#endif
|
||||||
} control_u;
|
} control_u;
|
||||||
|
struct dhcp_bridge *bridge, *alias;
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
msg.msg_controllen = sizeof(control_u);
|
||||||
msg.msg_name = NULL;
|
msg.msg_control = control_u.control;
|
||||||
msg.msg_namelen = 0;
|
msg.msg_name = &dest;
|
||||||
|
msg.msg_namelen = sizeof(dest);
|
||||||
msg.msg_iov = &daemon->dhcp_packet;
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
while (1)
|
if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
|
||||||
{
|
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
|
||||||
msg.msg_flags = 0;
|
|
||||||
while ((sz = recvmsg(fd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if (sz == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!(msg.msg_flags & MSG_TRUNC))
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* Very new Linux kernels return the actual size needed,
|
|
||||||
older ones always return truncated size */
|
|
||||||
if ((size_t)sz == daemon->dhcp_packet.iov_len)
|
|
||||||
{
|
|
||||||
if (!expand_buf(&daemon->dhcp_packet, sz + 100))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expand_buf(&daemon->dhcp_packet, sz);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* expand_buf may have moved buffer */
|
|
||||||
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
|
|
||||||
msg.msg_controllen = sizeof(control_u);
|
|
||||||
msg.msg_control = control_u.control;
|
|
||||||
msg.msg_flags = 0;
|
|
||||||
msg.msg_name = &dest;
|
|
||||||
msg.msg_namelen = sizeof(dest);
|
|
||||||
|
|
||||||
while ((sz = recvmsg(fd, &msg, 0)) == -1 && errno == EINTR);
|
|
||||||
|
|
||||||
if ((msg.msg_flags & MSG_TRUNC) || sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined (HAVE_LINUX_NETWORK)
|
#if defined (HAVE_LINUX_NETWORK)
|
||||||
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
if (msg.msg_controllen >= sizeof(struct cmsghdr))
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -237,26 +250,50 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* One form of bridging on BSD has the property that packets
|
||||||
|
can be recieved on bridge interfaces which do not have an IP address.
|
||||||
|
We allow these to be treated as aliases of another interface which does have
|
||||||
|
an IP address with --dhcp-bridge=interface,alias,alias */
|
||||||
|
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
||||||
|
{
|
||||||
|
for (alias = bridge->alias; alias; alias = alias->next)
|
||||||
|
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
|
||||||
|
{
|
||||||
|
if (!(iface_index = if_nametoindex(bridge->iface)))
|
||||||
|
{
|
||||||
|
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alias)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef MSG_BCAST
|
#ifdef MSG_BCAST
|
||||||
/* OpenBSD tells us when a packet was broadcast */
|
/* OpenBSD tells us when a packet was broadcast */
|
||||||
if (!(msg.msg_flags & MSG_BCAST))
|
if (!(msg.msg_flags & MSG_BCAST))
|
||||||
unicast_dest = 1;
|
unicast_dest = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ifr.ifr_addr.sa_family = AF_INET;
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
|
||||||
|
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
addrp = &iface_addr;
|
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!iface_check(AF_INET, (struct all_addr *)addrp, ifr.ifr_name, &iface_index))
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* weird libvirt-inspired access control */
|
/* weird libvirt-inspired access control */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
@@ -264,42 +301,40 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* unlinked contexts are marked by context->current == context */
|
/* unlinked contexts are marked by context->current == context */
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
context->current = context;
|
context->current = context;
|
||||||
|
|
||||||
parm.relay = mess->giaddr;
|
|
||||||
parm.primary = iface_addr;
|
|
||||||
parm.current = NULL;
|
parm.current = NULL;
|
||||||
parm.ind = iface_index;
|
parm.ind = iface_index;
|
||||||
|
|
||||||
/* interface may have been changed by alias in iface_check, make sure it gets priority in case
|
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
|
||||||
there is more than one address on the interface in the same subnet */
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) == -1)
|
|
||||||
{
|
{
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
|
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
|
||||||
return;
|
for a secondary */
|
||||||
}
|
struct match_param match;
|
||||||
else
|
|
||||||
{
|
|
||||||
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFNETMASK, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
if (ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
|
||||||
{
|
|
||||||
struct in_addr broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
|
||||||
complete_context(iface_addr, iface_index, netmask, broadcast, &parm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
match.matched = 0;
|
||||||
|
match.ind = iface_index;
|
||||||
|
|
||||||
|
if (!daemon->if_addrs ||
|
||||||
|
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
|
||||||
|
!match.matched)
|
||||||
|
return;
|
||||||
|
|
||||||
|
iface_addr = match.addr;
|
||||||
|
/* make sure secondary address gets priority in case
|
||||||
|
there is more than one address on the interface in the same subnet */
|
||||||
|
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
|
||||||
|
}
|
||||||
|
|
||||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
iov.iov_len = dhcp_reply(parm.current, ifr.ifr_name, iface_index, (size_t)sz,
|
||||||
now, unicast_dest, &is_inform, pxe_fd);
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr);
|
||||||
lease_update_file(now);
|
lease_update_file(now);
|
||||||
lease_update_dns();
|
lease_update_dns();
|
||||||
|
|
||||||
@@ -319,7 +354,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
dest.sin_len = sizeof(struct sockaddr_in);
|
dest.sin_len = sizeof(struct sockaddr_in);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pxe_fd)
|
if (pxe_fd)
|
||||||
{
|
{
|
||||||
if (mess->ciaddr.s_addr != 0)
|
if (mess->ciaddr.s_addr != 0)
|
||||||
@@ -357,7 +392,7 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
pkt->ipi_ifindex = iface_index;
|
pkt->ipi_ifindex = iface_index;
|
||||||
pkt->ipi_spec_dst.s_addr = 0;
|
pkt->ipi_spec_dst.s_addr = 0;
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
dest.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
dest.sin_port = htons(daemon->dhcp_client_port);
|
dest.sin_port = htons(daemon->dhcp_client_port);
|
||||||
@@ -414,6 +449,30 @@ void dhcp_packet(time_t now, int pxe_fd)
|
|||||||
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check against secondary interface addresses */
|
||||||
|
static int check_listen_addrs(struct in_addr local, int if_index,
|
||||||
|
struct in_addr netmask, struct in_addr broadcast, void *vparam)
|
||||||
|
{
|
||||||
|
struct match_param *param = vparam;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
if (if_index == param->ind)
|
||||||
|
{
|
||||||
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
|
if ( tmp->addr.sa.sa_family == AF_INET &&
|
||||||
|
tmp->addr.in.sin_addr.s_addr == local.s_addr)
|
||||||
|
{
|
||||||
|
param->matched = 1;
|
||||||
|
param->addr = local;
|
||||||
|
param->netmask = netmask;
|
||||||
|
param->broadcast = broadcast;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
/* This is a complex routine: it gets called with each (address,netmask,broadcast) triple
|
||||||
of each interface (and any relay address) and does the following things:
|
of each interface (and any relay address) and does the following things:
|
||||||
|
|
||||||
@@ -448,38 +507,27 @@ static int complete_context(struct in_addr local, int if_index,
|
|||||||
context->netmask = netmask;
|
context->netmask = netmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->netmask.s_addr)
|
if (context->netmask.s_addr != 0 &&
|
||||||
|
is_same_net(local, context->start, context->netmask) &&
|
||||||
|
is_same_net(local, context->end, context->netmask))
|
||||||
{
|
{
|
||||||
if (is_same_net(local, context->start, context->netmask) &&
|
/* link it onto the current chain if we've not seen it before */
|
||||||
is_same_net(local, context->end, context->netmask))
|
if (if_index == param->ind && context->current == context)
|
||||||
{
|
{
|
||||||
/* link it onto the current chain if we've not seen it before */
|
context->router = local;
|
||||||
if (if_index == param->ind && context->current == context)
|
context->local = local;
|
||||||
{
|
context->current = param->current;
|
||||||
context->router = local;
|
param->current = context;
|
||||||
context->local = local;
|
}
|
||||||
context->current = param->current;
|
|
||||||
param->current = context;
|
if (!(context->flags & CONTEXT_BRDCAST))
|
||||||
}
|
|
||||||
|
|
||||||
if (!(context->flags & CONTEXT_BRDCAST))
|
|
||||||
{
|
|
||||||
if (is_same_net(broadcast, context->start, context->netmask))
|
|
||||||
context->broadcast = broadcast;
|
|
||||||
else
|
|
||||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (param->relay.s_addr && is_same_net(param->relay, context->start, context->netmask))
|
|
||||||
{
|
{
|
||||||
context->router = param->relay;
|
if (is_same_net(broadcast, context->start, context->netmask))
|
||||||
context->local = param->primary;
|
context->broadcast = broadcast;
|
||||||
/* fill in missing broadcast addresses for relayed ranges */
|
else
|
||||||
if (!(context->flags & CONTEXT_BRDCAST))
|
|
||||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -505,7 +553,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
|||||||
start = ntohl(tmp->start.s_addr);
|
start = ntohl(tmp->start.s_addr);
|
||||||
end = ntohl(tmp->end.s_addr);
|
end = ntohl(tmp->end.s_addr);
|
||||||
|
|
||||||
if (!(tmp->flags & CONTEXT_STATIC) &&
|
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
|
||||||
addr >= start &&
|
addr >= start &&
|
||||||
addr <= end &&
|
addr <= end &&
|
||||||
match_netid(tmp->filter, netids, 1))
|
match_netid(tmp->filter, netids, 1))
|
||||||
@@ -540,7 +588,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
|||||||
if (!tmp)
|
if (!tmp)
|
||||||
for (tmp = context; tmp; tmp = tmp->current)
|
for (tmp = context; tmp; tmp = tmp->current)
|
||||||
if (match_netid(tmp->filter, netids, 1) &&
|
if (match_netid(tmp->filter, netids, 1) &&
|
||||||
is_same_net(taddr, tmp->start, tmp->netmask))
|
is_same_net(taddr, tmp->start, tmp->netmask) &&
|
||||||
|
!(tmp->flags & CONTEXT_PROXY))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,16 +675,22 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
for (pass = 0; pass <= 1; pass++)
|
for (pass = 0; pass <= 1; pass++)
|
||||||
for (c = context; c; c = c->current)
|
for (c = context; c; c = c->current)
|
||||||
if (c->flags & CONTEXT_STATIC)
|
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||||
continue;
|
continue;
|
||||||
else if (!match_netid(c->filter, netids, pass))
|
else if (!match_netid(c->filter, netids, pass))
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
if (option_bool(OPT_CONSEC_ADDR))
|
||||||
start.s_addr = addr.s_addr =
|
/* seed is largest extant lease addr in this context */
|
||||||
htonl(ntohl(c->start.s_addr) +
|
start = lease_find_max_addr(c);
|
||||||
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
else
|
||||||
|
/* pick a seed based on hwaddr */
|
||||||
|
start.s_addr = htonl(ntohl(c->start.s_addr) +
|
||||||
|
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||||
|
|
||||||
|
/* iterate until we find a free address. */
|
||||||
|
addr = start;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
/* eliminate addresses in use by the server. */
|
/* eliminate addresses in use by the server. */
|
||||||
@@ -660,9 +715,6 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
*addrp = addr;
|
*addrp = addr;
|
||||||
|
|
||||||
if (option_bool(OPT_NO_PING))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* check if we failed to ping addr sometime in the last
|
/* check if we failed to ping addr sometime in the last
|
||||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||||
This avoids problems when a stupid client bangs
|
This avoids problems when a stupid client bangs
|
||||||
@@ -672,33 +724,51 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||||
victim = r; /* old record */
|
victim = r; /* old record */
|
||||||
else if (++count == max || r->addr.s_addr == addr.s_addr)
|
else
|
||||||
return 1;
|
{
|
||||||
|
count++;
|
||||||
if (icmp_ping(addr))
|
if (r->addr.s_addr == addr.s_addr)
|
||||||
/* address in use: perturb address selection so that we are
|
{
|
||||||
less likely to try this address again. */
|
/* consec-ip mode: we offered this address for another client
|
||||||
c->addr_epoch++;
|
(different hash) recently, don't offer it to this one. */
|
||||||
else
|
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
|
||||||
|
break;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r)
|
||||||
{
|
{
|
||||||
/* at this point victim may hold an expired record */
|
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
||||||
if (!victim)
|
|
||||||
{
|
{
|
||||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
/* address in use: perturb address selection so that we are
|
||||||
|
less likely to try this address again. */
|
||||||
|
if (!option_bool(OPT_CONSEC_ADDR))
|
||||||
|
c->addr_epoch++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* at this point victim may hold an expired record */
|
||||||
|
if (!victim)
|
||||||
{
|
{
|
||||||
victim->next = daemon->ping_results;
|
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||||
daemon->ping_results = victim;
|
{
|
||||||
|
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;
|
||||||
|
victim->hash = j;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* record that this address is OK for 30s
|
|
||||||
without more ping checks */
|
|
||||||
if (victim)
|
|
||||||
{
|
|
||||||
victim->addr = addr;
|
|
||||||
victim->time = now;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,6 +779,7 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
|
|
||||||
} while (addr.s_addr != start.s_addr);
|
} while (addr.s_addr != start.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+220
@@ -0,0 +1,220 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
struct iface_param {
|
||||||
|
struct dhcp_context *current;
|
||||||
|
int ind;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int join_multicast(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, void *vparam);
|
||||||
|
|
||||||
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, void *vparam);
|
||||||
|
|
||||||
|
void dhcp6_init(void)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
int class = IPTOS_CLASS_CS6;
|
||||||
|
|
||||||
|
if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
|
||||||
|
setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
|
||||||
|
!fix_fd(fd) ||
|
||||||
|
!set_ipv6pktinfo(fd))
|
||||||
|
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
saddr.sin6_len = sizeof(addr.in6);
|
||||||
|
#endif
|
||||||
|
saddr.sin6_family = AF_INET6;
|
||||||
|
saddr.sin6_addr = in6addr_any;
|
||||||
|
saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
|
||||||
|
die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
/* join multicast groups on each interface we're interested in */
|
||||||
|
if (!iface_enumerate(AF_INET6, &fd, join_multicast))
|
||||||
|
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
|
||||||
|
|
||||||
|
daemon->dhcp6fd = fd;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int join_multicast(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, void *vparam)
|
||||||
|
{
|
||||||
|
char ifrn_name[IFNAMSIZ];
|
||||||
|
struct ipv6_mreq mreq;
|
||||||
|
struct in6_addr maddr;
|
||||||
|
int fd = *((int *)vparam);
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
(void)prefix;
|
||||||
|
(void)scope; /* warnings */
|
||||||
|
|
||||||
|
if (!indextoname(fd, if_index, ifrn_name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Are we doing DHCP on this interface? */
|
||||||
|
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, ifrn_name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
mreq.ipv6mr_interface = if_index;
|
||||||
|
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &maddr);
|
||||||
|
|
||||||
|
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, ALL_SERVERS, &maddr);
|
||||||
|
|
||||||
|
if (!setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void dhcp6_packet(time_t now)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param parm;
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
|
struct msghdr msg;
|
||||||
|
int if_index = 0;
|
||||||
|
union {
|
||||||
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
|
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||||
|
} control_u;
|
||||||
|
union mysockaddr from;
|
||||||
|
struct all_addr dest;
|
||||||
|
ssize_t sz;
|
||||||
|
struct ifreq ifr;
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
msg.msg_control = control_u.control6;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
msg.msg_flags = 0;
|
||||||
|
msg.msg_name = &from;
|
||||||
|
msg.msg_namelen = sizeof(from);
|
||||||
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
|
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg) == -1) || sz <= 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
unsigned char *c;
|
||||||
|
struct in6_pktinfo *p;
|
||||||
|
} p;
|
||||||
|
p.c = CMSG_DATA(cmptr);
|
||||||
|
|
||||||
|
if_index = p.p->ipi6_ifindex;
|
||||||
|
dest.addr.addr6 = p.p->ipi6_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
ls -l
|
||||||
|
if (!iface_check(AF_INET6, (struct all_addr *)&dest, ifr.ifr_name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* weird libvirt-inspired access control */
|
||||||
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
|
if (!context->interface || strcmp(context->interface, ifr.ifr_name) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* unlinked contexts are marked by context->current == context */
|
||||||
|
for (context = daemon->dhcp; context; context = context->next)
|
||||||
|
context->current = context;
|
||||||
|
|
||||||
|
parm.current = NULL;
|
||||||
|
parm.ind = if_index;
|
||||||
|
|
||||||
|
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
|
||||||
|
return;
|
||||||
|
|
||||||
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
|
|
||||||
|
msg.msg_iov = &daemon->dhcp_packet;
|
||||||
|
sz = dhcp6_reply(parm.current, sz);
|
||||||
|
/* ifr.ifr_name, if_index, (size_t)sz,
|
||||||
|
now, unicast_dest, &is_inform, pxe_fd, iface_addr); */
|
||||||
|
lease_update_file(now);
|
||||||
|
lease_update_dns();
|
||||||
|
|
||||||
|
if (sz != 0)
|
||||||
|
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, sz, &from, &dest, if_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int complete_context6(struct in6_addr *local, int prefix,
|
||||||
|
int scope, int if_index, void *vparam)
|
||||||
|
{
|
||||||
|
struct dhcp_context *context;
|
||||||
|
struct iface_param *param = vparam;
|
||||||
|
|
||||||
|
for (context = daemon->dhcp6; context; context = context->next)
|
||||||
|
{
|
||||||
|
if ((context->flags & CONTEXT_IPV6) &&
|
||||||
|
prefix == context->prefix &&
|
||||||
|
is_same_net6(local, &context->start6, prefix) &&
|
||||||
|
is_same_net6(local, &context->end6, prefix))
|
||||||
|
{
|
||||||
|
/* link it onto the current chain if we've not seen it before */
|
||||||
|
if (if_index == param->ind && context->current == context)
|
||||||
|
{
|
||||||
|
context->current = param->current;
|
||||||
|
param->current = context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DHCPV6_SERVER_PORT 547
|
||||||
|
#define DHCPV6_CLIENT_PORT 546
|
||||||
|
|
||||||
|
#define ALL_SERVERS "FF05::1:3"
|
||||||
|
#define ALL_RELAY_AGENTS_AND_SERVERS "FF02::1:2"
|
||||||
|
|
||||||
|
#define DHCP6SOLICIT 1
|
||||||
|
#define DHCP6ADVERTISE 2
|
||||||
|
#define DHCP6REQUEST 3
|
||||||
|
#define DHCP6CONFIRM 4
|
||||||
|
#define DHCP6RENEW 5
|
||||||
|
#define DHCP6REBIND 6
|
||||||
|
#define DHCP6REPLY 7
|
||||||
|
#define DHCP6RELEASE 8
|
||||||
|
#define DHCP6DECLINE 9
|
||||||
|
#define DHCP6RECONFIGURE 10
|
||||||
|
#define DHCP6IREQ 11
|
||||||
|
#define DHCP6RELAYFORW 12
|
||||||
|
#define DHCP6RELAYREPL 13
|
||||||
|
|
||||||
|
#define OPTION6_CLIENT_ID 1
|
||||||
|
#define OPTION6_SERVER_ID 2
|
||||||
|
#define OPTION6_IA_NA 3
|
||||||
|
#define OPTION6_IA_TA 4
|
||||||
|
#define OPTION6_IAADDR 5
|
||||||
|
#define OPTION6_ORO 6
|
||||||
|
#define OPTION6_PREFERENCE 7
|
||||||
|
#define OPTION6_ELAPSED_TIME 8
|
||||||
|
#define OPTION6_RELAY_MSG 9
|
||||||
|
#define OPTION6_AUTH 11
|
||||||
|
#define OPTION6_UNICAST 12
|
||||||
|
#define OPTION6_STATUS_CODE 13
|
||||||
|
#define OPTION6_RAPID_COMMIT 14
|
||||||
|
#define OPTION6_USER_CLASS 15
|
||||||
|
#define OPTION6_VENDOR_CLASS 16
|
||||||
|
#define OPTION6_VENDOR_OPTS 17
|
||||||
|
#define OPTION6_INTERFACE_ID 18
|
||||||
|
#define OPTION6_RECONFIGURE_MSG 19
|
||||||
|
#define OPTION6_RECONF_ACCEPT 20
|
||||||
@@ -13,6 +13,11 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
#define DHCP_CLIENT_PORT 68
|
||||||
|
#define DHCP_SERVER_ALTPORT 1067
|
||||||
|
#define DHCP_CLIENT_ALTPORT 1068
|
||||||
|
#define PXE_PORT 4011
|
||||||
|
|
||||||
#define BOOTREQUEST 1
|
#define BOOTREQUEST 1
|
||||||
#define BOOTREPLY 2
|
#define BOOTREPLY 2
|
||||||
|
|||||||
+4
-1
@@ -14,6 +14,9 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define NAMESERVER_PORT 53
|
||||||
|
#define TFTP_PORT 69
|
||||||
|
|
||||||
#define IN6ADDRSZ 16
|
#define IN6ADDRSZ 16
|
||||||
#define INADDRSZ 4
|
#define INADDRSZ 4
|
||||||
|
|
||||||
@@ -56,7 +59,7 @@ struct dns_header {
|
|||||||
u16 id;
|
u16 id;
|
||||||
u8 hb3,hb4;
|
u8 hb3,hb4;
|
||||||
u16 qdcount,ancount,nscount,arcount;
|
u16 qdcount,ancount,nscount,arcount;
|
||||||
} ;
|
};
|
||||||
|
|
||||||
#define HB3_QR 0x80
|
#define HB3_QR 0x80
|
||||||
#define HB3_OPCODE 0x78
|
#define HB3_OPCODE 0x78
|
||||||
|
|||||||
+122
-92
@@ -14,50 +14,13 @@
|
|||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declare static char *compiler_opts in config.h */
|
||||||
|
#define DNSMASQ_COMPILE_OPTS
|
||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
struct daemon *daemon;
|
struct daemon *daemon;
|
||||||
|
|
||||||
static char *compile_opts =
|
|
||||||
#ifndef HAVE_IPV6
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"IPv6 "
|
|
||||||
#ifndef HAVE_GETOPT_LONG
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"GNU-getopt "
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
"no-RTC "
|
|
||||||
#endif
|
|
||||||
#ifdef NO_FORK
|
|
||||||
"no-MMU "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_DBUS
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DBus "
|
|
||||||
#ifndef LOCALEDIR
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"I18N "
|
|
||||||
#ifndef HAVE_DHCP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"DHCP "
|
|
||||||
#if defined(HAVE_DHCP) && !defined(HAVE_SCRIPT)
|
|
||||||
"no-scripts "
|
|
||||||
#endif
|
|
||||||
#ifndef HAVE_TFTP
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"TFTP "
|
|
||||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
|
||||||
"no-"
|
|
||||||
#endif
|
|
||||||
"IDN";
|
|
||||||
|
|
||||||
|
|
||||||
static volatile pid_t pid = 0;
|
static volatile pid_t pid = 0;
|
||||||
static volatile int pipewrite;
|
static volatile int pipewrite;
|
||||||
|
|
||||||
@@ -65,7 +28,8 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp);
|
|||||||
static void check_dns_listeners(fd_set *set, time_t now);
|
static void check_dns_listeners(fd_set *set, time_t now);
|
||||||
static void sig_handler(int sig);
|
static void sig_handler(int sig);
|
||||||
static void async_event(int pipe, time_t now);
|
static void async_event(int pipe, time_t now);
|
||||||
static void fatal_event(struct event_desc *ev);
|
static void fatal_event(struct event_desc *ev, char *msg);
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg);
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -75,7 +39,7 @@ int main (int argc, char **argv)
|
|||||||
struct iname *if_tmp;
|
struct iname *if_tmp;
|
||||||
int piperead, pipefd[2], err_pipe[2];
|
int piperead, pipefd[2], err_pipe[2];
|
||||||
struct passwd *ent_pw = NULL;
|
struct passwd *ent_pw = NULL;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
uid_t script_uid = 0;
|
uid_t script_uid = 0;
|
||||||
gid_t script_gid = 0;
|
gid_t script_gid = 0;
|
||||||
#endif
|
#endif
|
||||||
@@ -118,6 +82,8 @@ int main (int argc, char **argv)
|
|||||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||||
|
|
||||||
|
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
if (!daemon->lease_file)
|
if (!daemon->lease_file)
|
||||||
{
|
{
|
||||||
@@ -148,6 +114,14 @@ int main (int argc, char **argv)
|
|||||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
|
||||||
|
die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
|
||||||
|
#else
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SOLARIS_NETWORK
|
#ifdef HAVE_SOLARIS_NETWORK
|
||||||
if (daemon->max_logs != 0)
|
if (daemon->max_logs != 0)
|
||||||
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
||||||
@@ -178,7 +152,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (option_bool(OPT_NOWILD))
|
if (option_bool(OPT_NOWILD))
|
||||||
{
|
{
|
||||||
daemon->listeners = create_bound_listeners();
|
create_bound_listeners(1);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
if (if_tmp->name && !if_tmp->used)
|
if (if_tmp->name && !if_tmp->used)
|
||||||
@@ -192,7 +166,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
daemon->listeners = create_wildcard_listeners();
|
create_wildcard_listeners();
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
cache_init();
|
cache_init();
|
||||||
@@ -213,9 +187,10 @@ int main (int argc, char **argv)
|
|||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
pre_allocate_sfds();
|
pre_allocate_sfds();
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* Note getpwnam returns static storage */
|
/* Note getpwnam returns static storage */
|
||||||
if (daemon->dhcp && daemon->lease_change_command && daemon->scriptuser)
|
if (daemon->dhcp && daemon->scriptuser &&
|
||||||
|
(daemon->lease_change_command || daemon->luascript))
|
||||||
{
|
{
|
||||||
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
if ((ent_pw = getpwnam(daemon->scriptuser)))
|
||||||
{
|
{
|
||||||
@@ -278,7 +253,7 @@ int main (int argc, char **argv)
|
|||||||
piperead = pipefd[0];
|
piperead = pipefd[0];
|
||||||
pipewrite = pipefd[1];
|
pipewrite = pipefd[1];
|
||||||
/* prime the pipe to load stuff first time. */
|
/* prime the pipe to load stuff first time. */
|
||||||
send_event(pipewrite, EVENT_RELOAD, 0);
|
send_event(pipewrite, EVENT_RELOAD, 0, NULL);
|
||||||
|
|
||||||
err_pipe[1] = -1;
|
err_pipe[1] = -1;
|
||||||
|
|
||||||
@@ -301,18 +276,19 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
/* fd == -1 since we've not forked, never returns. */
|
/* fd == -1 since we've not forked, never returns. */
|
||||||
send_event(-1, EVENT_FORK_ERR, errno);
|
send_event(-1, EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
char *msg;
|
||||||
|
|
||||||
/* close our copy of write-end */
|
/* close our copy of write-end */
|
||||||
close(err_pipe[1]);
|
close(err_pipe[1]);
|
||||||
|
|
||||||
/* check for errors after the fork */
|
/* check for errors after the fork */
|
||||||
if (read_write(err_pipe[0], (unsigned char *)&ev, sizeof(ev), 1))
|
if (read_event(err_pipe[0], &ev, &msg))
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
|
|
||||||
_exit(EC_GOOD);
|
_exit(EC_GOOD);
|
||||||
}
|
}
|
||||||
@@ -324,7 +300,7 @@ int main (int argc, char **argv)
|
|||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = fork()) == -1)
|
||||||
send_event(err_pipe[1], EVENT_FORK_ERR, errno);
|
send_event(err_pipe[1], EVENT_FORK_ERR, errno, NULL);
|
||||||
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
_exit(0);
|
_exit(0);
|
||||||
@@ -344,7 +320,7 @@ int main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (getuid() == 0)
|
else if (getuid() == 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_PIDFILE, errno);
|
send_event(err_pipe[1], EVENT_PIDFILE, errno, daemon->runfile);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,8 +340,8 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
/* if we are to run scripts, we need to fork a helper before dropping root. */
|
||||||
daemon->helperfd = -1;
|
daemon->helperfd = -1;
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#ifdef HAVE_SCRIPT
|
||||||
if (daemon->dhcp && daemon->lease_change_command)
|
if (daemon->dhcp && (daemon->lease_change_command || daemon->luascript))
|
||||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -379,17 +355,23 @@ int main (int argc, char **argv)
|
|||||||
(setgroups(0, &dummy) == -1 ||
|
(setgroups(0, &dummy) == -1 ||
|
||||||
setgid(gp->gr_gid) == -1))
|
setgid(gp->gr_gid) == -1))
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_GROUP_ERR, errno);
|
send_event(err_pipe[1], EVENT_GROUP_ERR, errno, daemon->groupname);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ent_pw && ent_pw->pw_uid != 0)
|
if (ent_pw && ent_pw->pw_uid != 0)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
/* On linux, we keep CAP_NETADMIN (for ARP-injection) and
|
||||||
CAP_NET_RAW (for icmp) if we're doing dhcp */
|
CAP_NET_RAW (for icmp) if we're doing dhcp. If we have yet to bind
|
||||||
data->effective = data->permitted = data->inheritable =
|
ports because of DAD, we need CAP_NET_BIND_SERVICE too. */
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
if (is_dad_listeners())
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) |
|
||||||
|
(1 << CAP_SETUID) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted = data->inheritable =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||||
|
|
||||||
/* Tell kernel to not clear capabilities when dropping root */
|
/* Tell kernel to not clear capabilities when dropping root */
|
||||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||||
@@ -419,26 +401,30 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (bad_capabilities != 0)
|
if (bad_capabilities != 0)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities);
|
send_event(err_pipe[1], EVENT_CAP_ERR, bad_capabilities, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finally drop root */
|
/* finally drop root */
|
||||||
if (setuid(ent_pw->pw_uid) == -1)
|
if (setuid(ent_pw->pw_uid) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_USER_ERR, errno);
|
send_event(err_pipe[1], EVENT_USER_ERR, errno, daemon->username);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
data->effective = data->permitted =
|
if (is_dad_listeners())
|
||||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_NET_BIND_SERVICE);
|
||||||
|
else
|
||||||
|
data->effective = data->permitted =
|
||||||
|
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
|
||||||
data->inheritable = 0;
|
data->inheritable = 0;
|
||||||
|
|
||||||
/* lose the setuid and setgid capbilities */
|
/* lose the setuid and setgid capbilities */
|
||||||
if (capset(hdr, data) == -1)
|
if (capset(hdr, data) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_pipe[1], EVENT_CAP_ERR, errno);
|
send_event(err_pipe[1], EVENT_CAP_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -593,6 +579,13 @@ int main (int argc, char **argv)
|
|||||||
t.tv_usec = 250000;
|
t.tv_usec = 250000;
|
||||||
tp = &t;
|
tp = &t;
|
||||||
}
|
}
|
||||||
|
/* Wake every second whilst waiting for DAD to complete */
|
||||||
|
else if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
t.tv_sec = 1;
|
||||||
|
t.tv_usec = 0;
|
||||||
|
tp = &t;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DBUS
|
#ifdef HAVE_DBUS
|
||||||
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
set_dbus_listeners(&maxfd, &rset, &wset, &eset);
|
||||||
@@ -647,6 +640,15 @@ int main (int argc, char **argv)
|
|||||||
now = dnsmasq_time();
|
now = dnsmasq_time();
|
||||||
|
|
||||||
check_log_writer(&wset);
|
check_log_writer(&wset);
|
||||||
|
|
||||||
|
/* Check the interfaces to see if any have exited DAD state
|
||||||
|
and if so, bind the address. */
|
||||||
|
if (is_dad_listeners())
|
||||||
|
{
|
||||||
|
enumerate_interfaces();
|
||||||
|
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
|
||||||
|
create_bound_listeners(0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LINUX_NETWORK
|
#ifdef HAVE_LINUX_NETWORK
|
||||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||||
@@ -741,28 +743,57 @@ static void sig_handler(int sig)
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
send_event(pipewrite, event, 0);
|
send_event(pipewrite, event, 0, NULL);
|
||||||
errno = errsave;
|
errno = errsave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_event(int fd, int event, int data)
|
void send_event(int fd, int event, int data, char *msg)
|
||||||
{
|
{
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
|
struct iovec iov[2];
|
||||||
|
|
||||||
ev.event = event;
|
ev.event = event;
|
||||||
ev.data = data;
|
ev.data = data;
|
||||||
|
ev.msg_sz = msg ? strlen(msg) : 0;
|
||||||
|
|
||||||
|
iov[0].iov_base = &ev;
|
||||||
|
iov[0].iov_len = sizeof(ev);
|
||||||
|
iov[1].iov_base = msg;
|
||||||
|
iov[1].iov_len = ev.msg_sz;
|
||||||
|
|
||||||
/* error pipe, debug mode. */
|
/* error pipe, debug mode. */
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
fatal_event(&ev);
|
fatal_event(&ev, msg);
|
||||||
else
|
else
|
||||||
/* pipe is non-blocking and struct event_desc is smaller than
|
/* pipe is non-blocking and struct event_desc is smaller than
|
||||||
PIPE_BUF, so this either fails or writes everything */
|
PIPE_BUF, so this either fails or writes everything */
|
||||||
while (write(fd, &ev, sizeof(ev)) == -1 && errno == EINTR);
|
while (writev(fd, iov, msg ? 2 : 1) == -1 && errno == EINTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fatal_event(struct event_desc *ev)
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
static int read_event(int fd, struct event_desc *evp, char **msg)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (!read_write(fd, (unsigned char *)evp, sizeof(struct event_desc), 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*msg = NULL;
|
||||||
|
|
||||||
|
if (evp->msg_sz != 0 &&
|
||||||
|
(buf = malloc(evp->msg_sz + 1)) &&
|
||||||
|
read_write(fd, (unsigned char *)buf, evp->msg_sz, 1))
|
||||||
|
{
|
||||||
|
buf[evp->msg_sz] = 0;
|
||||||
|
*msg = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fatal_event(struct event_desc *ev, char *msg)
|
||||||
{
|
{
|
||||||
errno = ev->data;
|
errno = ev->data;
|
||||||
|
|
||||||
@@ -781,19 +812,19 @@ static void fatal_event(struct event_desc *ev)
|
|||||||
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
die(_("setting capabilities failed: %s"), NULL, EC_MISC);
|
||||||
|
|
||||||
case EVENT_USER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_HUSER_ERR:
|
die(_("failed to change user-id to %s: %s"), msg, EC_MISC);
|
||||||
die(_("failed to change user-id to %s: %s"),
|
|
||||||
ev->event == EVENT_USER_ERR ? daemon->username : daemon->scriptuser,
|
|
||||||
EC_MISC);
|
|
||||||
|
|
||||||
case EVENT_GROUP_ERR:
|
case EVENT_GROUP_ERR:
|
||||||
die(_("failed to change group-id to %s: %s"), daemon->groupname, EC_MISC);
|
die(_("failed to change group-id to %s: %s"), msg, EC_MISC);
|
||||||
|
|
||||||
case EVENT_PIDFILE:
|
case EVENT_PIDFILE:
|
||||||
die(_("failed to open pidfile %s: %s"), daemon->runfile, EC_FILE);
|
die(_("failed to open pidfile %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
case EVENT_LOG_ERR:
|
case EVENT_LOG_ERR:
|
||||||
die(_("cannot open %s: %s"), daemon->log_file ? daemon->log_file : "log", EC_FILE);
|
die(_("cannot open log %s: %s"), msg, EC_FILE);
|
||||||
|
|
||||||
|
case EVENT_LUA_ERR:
|
||||||
|
die(_("failed to load Lua script: %s"), msg, EC_MISC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,8 +833,12 @@ static void async_event(int pipe, time_t now)
|
|||||||
pid_t p;
|
pid_t p;
|
||||||
struct event_desc ev;
|
struct event_desc ev;
|
||||||
int i;
|
int i;
|
||||||
|
char *msg;
|
||||||
if (read_write(pipe, (unsigned char *)&ev, sizeof(ev), 1))
|
|
||||||
|
/* NOTE: the memory used to return msg is leaked: use msgs in events only
|
||||||
|
to describe fatal errors. */
|
||||||
|
|
||||||
|
if (read_event(pipe, &ev, &msg))
|
||||||
switch (ev.event)
|
switch (ev.event)
|
||||||
{
|
{
|
||||||
case EVENT_RELOAD:
|
case EVENT_RELOAD:
|
||||||
@@ -848,11 +883,11 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_KILLED:
|
case EVENT_KILLED:
|
||||||
my_syslog(LOG_WARNING, _("child process killed by signal %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process killed by signal %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXITED:
|
case EVENT_EXITED:
|
||||||
my_syslog(LOG_WARNING, _("child process exited with status %d"), ev.data);
|
my_syslog(LOG_WARNING, _("script process exited with status %d"), ev.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_EXEC_ERR:
|
case EVENT_EXEC_ERR:
|
||||||
@@ -861,9 +896,10 @@ static void async_event(int pipe, time_t now)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* necessary for fatal errors in helper */
|
/* necessary for fatal errors in helper */
|
||||||
case EVENT_HUSER_ERR:
|
case EVENT_USER_ERR:
|
||||||
case EVENT_DIE:
|
case EVENT_DIE:
|
||||||
fatal_event(&ev);
|
case EVENT_LUA_ERR:
|
||||||
|
fatal_event(&ev, msg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_REOPEN:
|
case EVENT_REOPEN:
|
||||||
@@ -880,7 +916,7 @@ static void async_event(int pipe, time_t now)
|
|||||||
if (daemon->tcp_pids[i] != 0)
|
if (daemon->tcp_pids[i] != 0)
|
||||||
kill(daemon->tcp_pids[i], SIGALRM);
|
kill(daemon->tcp_pids[i], SIGALRM);
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
#if defined(HAVE_SCRIPT)
|
||||||
/* handle pending lease transitions */
|
/* handle pending lease transitions */
|
||||||
if (daemon->helperfd != -1)
|
if (daemon->helperfd != -1)
|
||||||
{
|
{
|
||||||
@@ -1147,9 +1183,6 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
unsigned char *buff;
|
unsigned char *buff;
|
||||||
struct server *s;
|
struct server *s;
|
||||||
int flags;
|
int flags;
|
||||||
struct in_addr dst_addr_4;
|
|
||||||
|
|
||||||
dst_addr_4.s_addr = 0;
|
|
||||||
|
|
||||||
#ifndef NO_FORK
|
#ifndef NO_FORK
|
||||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||||
@@ -1168,10 +1201,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
|||||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
|
|
||||||
if (listener->family == AF_INET)
|
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
|
||||||
dst_addr_4 = iface->addr.in.sin_addr;
|
|
||||||
|
|
||||||
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
|
|
||||||
|
|
||||||
shutdown(confd, SHUT_RDWR);
|
shutdown(confd, SHUT_RDWR);
|
||||||
close(confd);
|
close(confd);
|
||||||
|
|||||||
+73
-15
@@ -39,9 +39,14 @@
|
|||||||
/* get these before config.h for IPv6 stuff... */
|
/* get these before config.h for IPv6 stuff... */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
/* Define before netinet/in.h to select API. OSX Lion onwards. */
|
||||||
|
# define __APPLE_USE_RFC_3542
|
||||||
|
#endif
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
/* and this. */
|
/* Also needed before config.h. */
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -52,6 +57,9 @@ typedef unsigned int u32;
|
|||||||
|
|
||||||
#include "dns_protocol.h"
|
#include "dns_protocol.h"
|
||||||
#include "dhcp_protocol.h"
|
#include "dhcp_protocol.h"
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
#include "dhcp6_protocol.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define gettext_noop(S) (S)
|
#define gettext_noop(S) (S)
|
||||||
#ifndef LOCALEDIR
|
#ifndef LOCALEDIR
|
||||||
@@ -127,7 +135,7 @@ extern int capget(cap_user_header_t header, cap_user_data_t data);
|
|||||||
|
|
||||||
/* Async event queue */
|
/* Async event queue */
|
||||||
struct event_desc {
|
struct event_desc {
|
||||||
int event, data;
|
int event, data, msg_sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define EVENT_RELOAD 1
|
#define EVENT_RELOAD 1
|
||||||
@@ -148,6 +156,7 @@ struct event_desc {
|
|||||||
#define EVENT_DIE 16
|
#define EVENT_DIE 16
|
||||||
#define EVENT_LOG_ERR 17
|
#define EVENT_LOG_ERR 17
|
||||||
#define EVENT_FORK_ERR 18
|
#define EVENT_FORK_ERR 18
|
||||||
|
#define EVENT_LUA_ERR 19
|
||||||
|
|
||||||
/* Exit codes. */
|
/* Exit codes. */
|
||||||
#define EC_GOOD 0
|
#define EC_GOOD 0
|
||||||
@@ -202,7 +211,10 @@ struct event_desc {
|
|||||||
#define OPT_NO_REBIND 31
|
#define OPT_NO_REBIND 31
|
||||||
#define OPT_ADD_MAC 32
|
#define OPT_ADD_MAC 32
|
||||||
#define OPT_DNSSEC 33
|
#define OPT_DNSSEC 33
|
||||||
#define OPT_LAST 34
|
#define OPT_CONSEC_ADDR 34
|
||||||
|
#define OPT_CONNTRACK 35
|
||||||
|
#define OPT_FQDN_UPDATE 36
|
||||||
|
#define OPT_LAST 37
|
||||||
|
|
||||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||||
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
not to occupy the same bits as priorities, no matter how syslog.h is set up. */
|
||||||
@@ -309,7 +321,6 @@ struct crec {
|
|||||||
#define F_RRNAME (1u<<17)
|
#define F_RRNAME (1u<<17)
|
||||||
#define F_SERVER (1u<<18)
|
#define F_SERVER (1u<<18)
|
||||||
#define F_QUERY (1u<<19)
|
#define F_QUERY (1u<<19)
|
||||||
#define F_NSRR (1u<<20)
|
|
||||||
|
|
||||||
|
|
||||||
/* struct sockaddr is not large enough to hold any address,
|
/* struct sockaddr is not large enough to hold any address,
|
||||||
@@ -362,7 +373,7 @@ struct server {
|
|||||||
struct irec {
|
struct irec {
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct in_addr netmask; /* only valid for IPv4 */
|
struct in_addr netmask; /* only valid for IPv4 */
|
||||||
int tftp_ok, mtu;
|
int tftp_ok, mtu, done, dad;
|
||||||
char *name;
|
char *name;
|
||||||
struct irec *next;
|
struct irec *next;
|
||||||
};
|
};
|
||||||
@@ -443,6 +454,9 @@ struct dhcp_lease {
|
|||||||
unsigned char *extradata;
|
unsigned char *extradata;
|
||||||
unsigned int extradata_len, extradata_size;
|
unsigned int extradata_len, extradata_size;
|
||||||
int last_interface;
|
int last_interface;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
char is_ipv6;
|
||||||
|
#endif
|
||||||
struct dhcp_lease *next;
|
struct dhcp_lease *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -517,9 +531,10 @@ struct dhcp_opt {
|
|||||||
#define DHOPT_HEX 512
|
#define DHOPT_HEX 512
|
||||||
#define DHOPT_VENDOR_MATCH 1024
|
#define DHOPT_VENDOR_MATCH 1024
|
||||||
#define DHOPT_RFC3925 2048
|
#define DHOPT_RFC3925 2048
|
||||||
|
#define DHOPT_TAGOK 4096
|
||||||
|
|
||||||
struct dhcp_boot {
|
struct dhcp_boot {
|
||||||
char *file, *sname;
|
char *file, *sname, *tftp_sname;
|
||||||
struct in_addr next_server;
|
struct in_addr next_server;
|
||||||
struct dhcp_netid *netid;
|
struct dhcp_netid *netid;
|
||||||
struct dhcp_boot *next;
|
struct dhcp_boot *next;
|
||||||
@@ -571,6 +586,10 @@ struct dhcp_context {
|
|||||||
struct in_addr netmask, broadcast;
|
struct in_addr netmask, broadcast;
|
||||||
struct in_addr local, router;
|
struct in_addr local, router;
|
||||||
struct in_addr start, end; /* range of available addresses */
|
struct in_addr start, end; /* range of available addresses */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct in6_addr start6, end6; /* range of available addresses */
|
||||||
|
int prefix;
|
||||||
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
char *interface;
|
char *interface;
|
||||||
struct dhcp_netid netid, *filter;
|
struct dhcp_netid netid, *filter;
|
||||||
@@ -581,10 +600,12 @@ struct dhcp_context {
|
|||||||
#define CONTEXT_NETMASK 2
|
#define CONTEXT_NETMASK 2
|
||||||
#define CONTEXT_BRDCAST 4
|
#define CONTEXT_BRDCAST 4
|
||||||
#define CONTEXT_PROXY 8
|
#define CONTEXT_PROXY 8
|
||||||
|
#define CONTEXT_IPV6 16
|
||||||
|
|
||||||
struct ping_result {
|
struct ping_result {
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
time_t time;
|
time_t time;
|
||||||
|
unsigned int hash;
|
||||||
struct ping_result *next;
|
struct ping_result *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -642,6 +663,7 @@ extern struct daemon {
|
|||||||
char *mxtarget;
|
char *mxtarget;
|
||||||
char *lease_file;
|
char *lease_file;
|
||||||
char *username, *groupname, *scriptuser;
|
char *username, *groupname, *scriptuser;
|
||||||
|
char *luascript;
|
||||||
int group_set, osport;
|
int group_set, osport;
|
||||||
char *domain_suffix;
|
char *domain_suffix;
|
||||||
struct cond_domain *cond_domain;
|
struct cond_domain *cond_domain;
|
||||||
@@ -657,7 +679,7 @@ extern struct daemon {
|
|||||||
int port, query_port, min_port;
|
int port, query_port, min_port;
|
||||||
unsigned long local_ttl, neg_ttl, max_ttl;
|
unsigned long local_ttl, neg_ttl, max_ttl;
|
||||||
struct hostsfile *addn_hosts;
|
struct hostsfile *addn_hosts;
|
||||||
struct dhcp_context *dhcp;
|
struct dhcp_context *dhcp, *dhcp6;
|
||||||
struct dhcp_config *dhcp_conf;
|
struct dhcp_config *dhcp_conf;
|
||||||
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
struct dhcp_opt *dhcp_opts, *dhcp_match;
|
||||||
struct dhcp_vendor *dhcp_vendors;
|
struct dhcp_vendor *dhcp_vendors;
|
||||||
@@ -713,7 +735,12 @@ extern struct daemon {
|
|||||||
struct ping_result *ping_results;
|
struct ping_result *ping_results;
|
||||||
FILE *lease_stream;
|
FILE *lease_stream;
|
||||||
struct dhcp_bridge *bridges;
|
struct dhcp_bridge *bridges;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int duid_len;
|
||||||
|
unsigned char *duid;
|
||||||
|
struct iovec outpacket;
|
||||||
|
int dhcp6fd;
|
||||||
|
#endif
|
||||||
/* DBus stuff */
|
/* DBus stuff */
|
||||||
/* void * here to avoid depending on dbus headers outside dbus.c */
|
/* void * here to avoid depending on dbus headers outside dbus.c */
|
||||||
void *dbus;
|
void *dbus;
|
||||||
@@ -724,6 +751,9 @@ extern struct daemon {
|
|||||||
/* TFTP stuff */
|
/* TFTP stuff */
|
||||||
struct tftp_transfer *tftp_trans;
|
struct tftp_transfer *tftp_trans;
|
||||||
|
|
||||||
|
/* utility string buffer, hold max sized IP address as string */
|
||||||
|
char *addrbuff;
|
||||||
|
|
||||||
} *daemon;
|
} *daemon;
|
||||||
|
|
||||||
/* cache.c */
|
/* cache.c */
|
||||||
@@ -742,6 +772,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
|||||||
time_t now, unsigned long ttl, unsigned short flags);
|
time_t now, unsigned long ttl, unsigned short flags);
|
||||||
void cache_reload(void);
|
void cache_reload(void);
|
||||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
||||||
|
struct in_addr a_record_from_hosts(char *name, time_t now);
|
||||||
void cache_unhash_dhcp(void);
|
void cache_unhash_dhcp(void);
|
||||||
void dump_cache(time_t now);
|
void dump_cache(time_t now);
|
||||||
char *cache_get_name(struct crec *crecp);
|
char *cache_get_name(struct crec *crecp);
|
||||||
@@ -781,6 +812,9 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
|||||||
int hostname_isequal(char *a, char *b);
|
int hostname_isequal(char *a, char *b);
|
||||||
time_t dnsmasq_time(void);
|
time_t dnsmasq_time(void);
|
||||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen);
|
||||||
|
#endif
|
||||||
int retry_send(void);
|
int retry_send(void);
|
||||||
void prettyprint_time(char *buf, unsigned int t);
|
void prettyprint_time(char *buf, unsigned int t);
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
int prettyprint_addr(union mysockaddr *addr, char *buf);
|
||||||
@@ -813,9 +847,12 @@ struct hostsfile *expand_filelist(struct hostsfile *list);
|
|||||||
void reply_query(int fd, int family, time_t now);
|
void reply_query(int fd, int family, time_t now);
|
||||||
void receive_query(struct listener *listen, time_t now);
|
void receive_query(struct listener *listen, time_t now);
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
unsigned char *tcp_request(int confd, time_t now,
|
||||||
struct in_addr local_addr, struct in_addr netmask);
|
union mysockaddr *local_addr, struct in_addr netmask);
|
||||||
void server_gone(struct server *server);
|
void server_gone(struct server *server);
|
||||||
struct frec *get_new_frec(time_t now, int *wait);
|
struct frec *get_new_frec(time_t now, int *wait);
|
||||||
|
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
|
union mysockaddr *to, struct all_addr *source,
|
||||||
|
unsigned int iface);
|
||||||
|
|
||||||
/* network.c */
|
/* network.c */
|
||||||
int indextoname(int fd, int index, char *name);
|
int indextoname(int fd, int index, char *name);
|
||||||
@@ -825,16 +862,21 @@ void pre_allocate_sfds(void);
|
|||||||
int reload_servers(char *fname);
|
int reload_servers(char *fname);
|
||||||
void check_servers(void);
|
void check_servers(void);
|
||||||
int enumerate_interfaces();
|
int enumerate_interfaces();
|
||||||
struct listener *create_wildcard_listeners(void);
|
void create_wildcard_listeners(void);
|
||||||
struct listener *create_bound_listeners(void);
|
void create_bound_listeners(int die);
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp);
|
int is_dad_listeners(void);
|
||||||
|
int iface_check(int family, struct all_addr *addr, char *name);
|
||||||
int fix_fd(int fd);
|
int fix_fd(int fd);
|
||||||
struct in_addr get_ifaddr(char *intr);
|
struct in_addr get_ifaddr(char *intr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
void dhcp_init(void);
|
void dhcp_init(void);
|
||||||
void dhcp_packet(time_t now, int pxe_fd);
|
void dhcp_packet(time_t now, int pxe_fd);
|
||||||
|
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg);
|
||||||
struct dhcp_context *address_available(struct dhcp_context *context,
|
struct dhcp_context *address_available(struct dhcp_context *context,
|
||||||
struct in_addr addr,
|
struct in_addr addr,
|
||||||
struct dhcp_netid *netids);
|
struct dhcp_netid *netids);
|
||||||
@@ -866,7 +908,10 @@ char *get_domain(struct in_addr addr);
|
|||||||
void lease_update_file(time_t now);
|
void lease_update_file(time_t now);
|
||||||
void lease_update_dns();
|
void lease_update_dns();
|
||||||
void lease_init(time_t now);
|
void lease_init(time_t now);
|
||||||
struct dhcp_lease *lease_allocate(struct in_addr addr);
|
struct dhcp_lease *lease_allocate4(struct in_addr addr);
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp);
|
||||||
|
#endif
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr,
|
||||||
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
unsigned char *clid, int hw_len, int hw_type, int clid_len);
|
||||||
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
|
void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth);
|
||||||
@@ -875,6 +920,7 @@ void lease_set_interface(struct dhcp_lease *lease, int interface);
|
|||||||
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int hw_type,
|
||||||
unsigned char *clid, int clid_len);
|
unsigned char *clid, int clid_len);
|
||||||
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
struct dhcp_lease *lease_find_by_addr(struct in_addr addr);
|
||||||
|
struct in_addr lease_find_max_addr(struct dhcp_context *context);
|
||||||
void lease_prune(struct dhcp_lease *target, time_t now);
|
void lease_prune(struct dhcp_lease *target, time_t now);
|
||||||
void lease_update_from_configs(void);
|
void lease_update_from_configs(void);
|
||||||
int do_script_run(time_t now);
|
int do_script_run(time_t now);
|
||||||
@@ -884,7 +930,7 @@ void rerun_scripts(void);
|
|||||||
/* rfc2131.c */
|
/* rfc2131.c */
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd);
|
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe_fd, struct in_addr fallback);
|
||||||
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
||||||
int clid_len, unsigned char *clid, int *len_out);
|
int clid_len, unsigned char *clid, int *len_out);
|
||||||
#endif
|
#endif
|
||||||
@@ -894,7 +940,7 @@ unsigned char *extended_hwaddr(int hwtype, int hwlen, unsigned char *hwaddr,
|
|||||||
int make_icmp_sock(void);
|
int make_icmp_sock(void);
|
||||||
int icmp_ping(struct in_addr addr);
|
int icmp_ping(struct in_addr addr);
|
||||||
#endif
|
#endif
|
||||||
void send_event(int fd, int event, int data);
|
void send_event(int fd, int event, int data, char *msg);
|
||||||
void clear_cache_and_reload(time_t now);
|
void clear_cache_and_reload(time_t now);
|
||||||
void poll_resolv(int force, int do_reload, time_t now);
|
void poll_resolv(int force, int do_reload, time_t now);
|
||||||
|
|
||||||
@@ -938,3 +984,15 @@ int helper_buf_empty(void);
|
|||||||
void tftp_request(struct listener *listen, time_t now);
|
void tftp_request(struct listener *listen, time_t now);
|
||||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* conntrack.c */
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
int get_incoming_mark(union mysockaddr *peer_addr, struct all_addr *local_addr,
|
||||||
|
int istcp, unsigned int *markp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* rfc3315.c */
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
void make_duid(time_t now);
|
||||||
|
size_t dhcp6_reply(struct dhcp_context *context, size_t sz);
|
||||||
|
#endif
|
||||||
+77
-48
@@ -26,9 +26,9 @@ static struct randfd *allocate_rfd(int family);
|
|||||||
|
|
||||||
/* Send a UDP packet with its source address set as "source"
|
/* Send a UDP packet with its source address set as "source"
|
||||||
unless nowild is true, when we just send it with the kernel default */
|
unless nowild is true, when we just send it with the kernel default */
|
||||||
static void send_from(int fd, int nowild, char *packet, size_t len,
|
void send_from(int fd, int nowild, char *packet, size_t len,
|
||||||
union mysockaddr *to, struct all_addr *source,
|
union mysockaddr *to, struct all_addr *source,
|
||||||
unsigned int iface)
|
unsigned int iface)
|
||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
@@ -70,7 +70,7 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
p.ipi_spec_dst = source->addr.addr4;
|
p.ipi_spec_dst = source->addr.addr4;
|
||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
cmptr->cmsg_level = SOL_IP;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
#elif defined(IP_SENDSRCADDR)
|
#elif defined(IP_SENDSRCADDR)
|
||||||
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
memcpy(CMSG_DATA(cmptr), &(source->addr.addr4), sizeof(source->addr.addr4));
|
||||||
@@ -88,10 +88,10 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
|||||||
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
memcpy(CMSG_DATA(cmptr), &p, sizeof(p));
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||||
cmptr->cmsg_type = daemon->v6pktinfo;
|
cmptr->cmsg_type = daemon->v6pktinfo;
|
||||||
cmptr->cmsg_level = IPV6_LEVEL;
|
cmptr->cmsg_level = IPPROTO_IPV6;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
iface = 0; /* eliminate warning */
|
(void)iface; /* eliminate warning */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,10 +207,10 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags == 0 && !(qtype & F_NSRR) &&
|
if (flags == 0 && !(qtype & F_QUERY) &&
|
||||||
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||||
flags = F_NXDOMAIN;
|
flags = F_NOERR;
|
||||||
|
|
||||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||||
flags = F_NOERR;
|
flags = F_NOERR;
|
||||||
@@ -243,7 +243,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||||
struct server *start = NULL;
|
struct server *start = NULL;
|
||||||
|
|
||||||
/* RFC 4035: sect 4.6 para 2 */
|
/* RFC 4035: sect 4.6 para 2 */
|
||||||
header->hb4 &= ~HB4_AD;
|
header->hb4 &= ~HB4_AD;
|
||||||
|
|
||||||
@@ -366,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
daemon->rfd_save = forward->rfd4;
|
daemon->rfd_save = forward->rfd4;
|
||||||
fd = forward->rfd4->fd;
|
fd = forward->rfd4->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
{
|
||||||
|
unsigned int mark;
|
||||||
|
if (get_incoming_mark(udpaddr, dst_addr, 0, &mark))
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendto(fd, (char *)header, plen, 0,
|
if (sendto(fd, (char *)header, plen, 0,
|
||||||
@@ -693,7 +703,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -733,7 +743,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -750,7 +760,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
|
||||||
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &if_index))
|
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (listen->family == AF_INET &&
|
if (listen->family == AF_INET &&
|
||||||
@@ -797,7 +807,7 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
about resources for debug mode, when the fork is suppressed: that's
|
about resources for debug mode, when the fork is suppressed: that's
|
||||||
done by the caller. */
|
done by the caller. */
|
||||||
unsigned char *tcp_request(int confd, time_t now,
|
unsigned char *tcp_request(int confd, time_t now,
|
||||||
struct in_addr local_addr, struct in_addr netmask)
|
union mysockaddr *local_addr, struct in_addr netmask)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int norebind = 0;
|
int norebind = 0;
|
||||||
@@ -809,7 +819,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||||
struct dns_header *header;
|
struct dns_header *header;
|
||||||
struct server *last_server;
|
struct server *last_server;
|
||||||
|
struct in_addr dst_addr_4;
|
||||||
|
union mysockaddr peer_addr;
|
||||||
|
socklen_t peer_len = sizeof(union mysockaddr);
|
||||||
|
|
||||||
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||||
|
return packet;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (!packet ||
|
if (!packet ||
|
||||||
@@ -831,29 +847,28 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||||
{
|
{
|
||||||
union mysockaddr peer_addr;
|
char types[20];
|
||||||
socklen_t peer_len = sizeof(union mysockaddr);
|
|
||||||
|
|
||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
querystr(types, qtype);
|
||||||
{
|
|
||||||
char types[20];
|
if (peer_addr.sa.sa_family == AF_INET)
|
||||||
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
querystr(types, qtype);
|
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
||||||
|
|
||||||
if (peer_addr.sa.sa_family == AF_INET)
|
|
||||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
|
||||||
(struct all_addr *)&peer_addr.in.sin_addr, types);
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (local_addr->sa.sa_family == AF_INET)
|
||||||
|
dst_addr_4 = local_addr->in.sin_addr;
|
||||||
|
else
|
||||||
|
dst_addr_4.s_addr = 0;
|
||||||
|
|
||||||
/* m > 0 if answered from cache */
|
/* m > 0 if answered from cache */
|
||||||
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
|
||||||
local_addr, netmask, now);
|
dst_addr_4, netmask, now);
|
||||||
|
|
||||||
/* Do this by steam now we're not in the select() loop */
|
/* Do this by steam now we're not in the select() loop */
|
||||||
check_log_writer(NULL);
|
check_log_writer(NULL);
|
||||||
@@ -866,14 +881,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
|
|
||||||
if (option_bool(OPT_ADD_MAC))
|
if (option_bool(OPT_ADD_MAC))
|
||||||
{
|
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||||
union mysockaddr peer_addr;
|
|
||||||
socklen_t peer_len = sizeof(union mysockaddr);
|
|
||||||
|
|
||||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
|
||||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotname)
|
if (gotname)
|
||||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||||
|
|
||||||
@@ -907,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
if (type != (last_server->flags & SERV_TYPE) ||
|
if (type != (last_server->flags & SERV_TYPE) ||
|
||||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((last_server->tcpfd == -1) &&
|
if (last_server->tcpfd == -1)
|
||||||
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
|
|
||||||
(!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
|
||||||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
|
||||||
{
|
{
|
||||||
close(last_server->tcpfd);
|
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||||
last_server->tcpfd = -1;
|
continue;
|
||||||
|
|
||||||
|
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
|
||||||
|
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
|
||||||
|
{
|
||||||
|
close(last_server->tcpfd);
|
||||||
|
last_server->tcpfd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_CONNTRACK
|
||||||
|
/* Copy connection mark of incoming query to outgoing connection. */
|
||||||
|
if (option_bool(OPT_CONNTRACK))
|
||||||
|
{
|
||||||
|
unsigned int mark;
|
||||||
|
struct all_addr local;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (local_addr->sa.sa_family == AF_INET6)
|
||||||
|
local.addr.addr6 = local_addr->in6.sin6_addr;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
local.addr.addr4 = local_addr->in.sin_addr;
|
||||||
|
|
||||||
|
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
|
||||||
|
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last_server->tcpfd == -1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
c1 = size >> 8;
|
c1 = size >> 8;
|
||||||
c2 = size;
|
c2 = size;
|
||||||
|
|||||||
+240
-53
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_SCRIPT
|
||||||
|
|
||||||
/* This file has code to fork a helper process which recieves data via a pipe
|
/* This file has code to fork a helper process which recieves data via a pipe
|
||||||
shared with the main process and which is responsible for calling a script when
|
shared with the main process and which is responsible for calling a script when
|
||||||
DHCP leases change.
|
DHCP leases change.
|
||||||
@@ -28,11 +30,20 @@
|
|||||||
main process.
|
main process.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(HAVE_DHCP) && defined(HAVE_SCRIPT)
|
|
||||||
|
|
||||||
static void my_setenv(const char *name, const char *value, int *error);
|
static void my_setenv(const char *name, const char *value, int *error);
|
||||||
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
#include <lua.h>
|
||||||
|
#include <lualib.h>
|
||||||
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
lua_State *lua;
|
||||||
|
|
||||||
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct script_data
|
struct script_data
|
||||||
{
|
{
|
||||||
unsigned char action, hwaddr_len, hwaddr_type;
|
unsigned char action, hwaddr_len, hwaddr_type;
|
||||||
@@ -61,7 +72,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
then fork our process. */
|
then fork our process. */
|
||||||
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
|
||||||
{
|
{
|
||||||
send_event(err_fd, EVENT_PIPE_ERR, errno);
|
send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,38 +99,98 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
if (option_bool(OPT_NO_FORK))
|
if (option_bool(OPT_NO_FORK))
|
||||||
/* send error to daemon process if no-fork */
|
/* send error to daemon process if no-fork */
|
||||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* kill daemon */
|
/* kill daemon */
|
||||||
send_event(event_fd, EVENT_DIE, 0);
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
/* return error */
|
/* return error */
|
||||||
send_event(err_fd, EVENT_HUSER_ERR, errno);
|
send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
|
||||||
}
|
}
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close all the sockets etc, we don't need them here. This closes err_fd, so that
|
/* close all the sockets etc, we don't need them here.
|
||||||
main process can return. */
|
Don't close err_fd, in case the lua-init fails.
|
||||||
|
Note that we have to do this before lua init
|
||||||
|
so we don't close any lua fds. */
|
||||||
for (max_fd--; max_fd >= 0; max_fd--)
|
for (max_fd--; max_fd >= 0; max_fd--)
|
||||||
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
|
||||||
max_fd != STDIN_FILENO && max_fd != pipefd[0] && max_fd != event_fd)
|
max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
|
||||||
|
max_fd != event_fd && max_fd != err_fd)
|
||||||
close(max_fd);
|
close(max_fd);
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
const char *lua_err = NULL;
|
||||||
|
lua = lua_open();
|
||||||
|
luaL_openlibs(lua);
|
||||||
|
|
||||||
|
/* get Lua to load our script file */
|
||||||
|
if (luaL_dofile(lua, daemon->luascript) != 0)
|
||||||
|
lua_err = lua_tostring(lua, -1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease");
|
||||||
|
if (lua_type(lua, -1) != LUA_TFUNCTION)
|
||||||
|
lua_err = _("lease() function missing in Lua script");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lua_err)
|
||||||
|
{
|
||||||
|
if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
|
||||||
|
/* send error to daemon process if no-fork */
|
||||||
|
send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* kill daemon */
|
||||||
|
send_event(event_fd, EVENT_DIE, 0, NULL);
|
||||||
|
/* return error */
|
||||||
|
send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
|
||||||
|
}
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
lua_getglobal(lua, "init");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
else
|
||||||
|
lua_pop(lua, 1); /* remove nil from stack */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* All init done, close our copy of the error pipe, so that main process can return */
|
||||||
|
if (err_fd != -1)
|
||||||
|
close(err_fd);
|
||||||
|
|
||||||
/* loop here */
|
/* loop here */
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
struct script_data data;
|
struct script_data data;
|
||||||
char *p, *action_str, *hostname = NULL;
|
char *p, *action_str, *hostname = NULL, *domain = NULL;
|
||||||
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
unsigned char *buf = (unsigned char *)daemon->namebuff;
|
||||||
unsigned char *end, *alloc_buff = NULL;
|
unsigned char *end, *extradata, *alloc_buff = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
free(alloc_buff);
|
||||||
|
|
||||||
/* we read zero bytes when pipe closed: this is our signal to exit */
|
/* we read zero bytes when pipe closed: this is our signal to exit */
|
||||||
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
|
||||||
_exit(0);
|
{
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "shutdown");
|
||||||
|
if (lua_type(lua, -1) == LUA_TFUNCTION)
|
||||||
|
lua_call(lua, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.action == ACTION_DEL)
|
if (data.action == ACTION_DEL)
|
||||||
action_str = "del";
|
action_str = "del";
|
||||||
else if (data.action == ACTION_ADD)
|
else if (data.action == ACTION_ADD)
|
||||||
@@ -139,42 +210,142 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
if (i != data.hwaddr_len - 1)
|
if (i != data.hwaddr_len - 1)
|
||||||
p += sprintf(p, ":");
|
p += sprintf(p, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and CLID into packet, avoid overwrite from bad data */
|
/* expiry or length into dhcp_buff2 */
|
||||||
if ((data.clid_len > daemon->packet_buff_sz) || !read_write(pipefd[0], buf, data.clid_len, 1))
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
||||||
|
#else
|
||||||
|
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* supplied data may just exceed normal buffer (unlikely) */
|
||||||
|
if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
|
||||||
|
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!read_write(pipefd[0], buf,
|
||||||
|
data.hostname_len + data.ed_len + data.clid_len, 1))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* CLID into packet */
|
||||||
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
for (p = daemon->packet, i = 0; i < data.clid_len; i++)
|
||||||
{
|
{
|
||||||
p += sprintf(p, "%.2x", buf[i]);
|
p += sprintf(p, "%.2x", buf[i]);
|
||||||
if (i != data.clid_len - 1)
|
if (i != data.clid_len - 1)
|
||||||
p += sprintf(p, ":");
|
p += sprintf(p, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* and expiry or length into dhcp_buff2 */
|
buf += data.clid_len;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
sprintf(daemon->dhcp_buff2, "%u", data.length);
|
if (data.hostname_len != 0)
|
||||||
|
{
|
||||||
|
char *dot;
|
||||||
|
hostname = (char *)buf;
|
||||||
|
hostname[data.hostname_len - 1] = 0;
|
||||||
|
if (!legal_hostname(hostname))
|
||||||
|
hostname = NULL;
|
||||||
|
else if ((dot = strchr(hostname, '.')))
|
||||||
|
{
|
||||||
|
domain = dot+1;
|
||||||
|
*dot = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extradata = buf + data.hostname_len;
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
if (daemon->luascript)
|
||||||
|
{
|
||||||
|
lua_getglobal(lua, "lease"); /* function to call */
|
||||||
|
lua_pushstring(lua, action_str); /* arg1 - action */
|
||||||
|
lua_newtable(lua); /* arg2 - data table */
|
||||||
|
|
||||||
|
if (data.clid_len != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, daemon->packet);
|
||||||
|
lua_setfield(lua, -2, "client_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(data.interface) != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, data.interface);
|
||||||
|
lua_setfield(lua, -2, "interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
lua_pushnumber(lua, data.length);
|
||||||
|
lua_setfield(lua, -2, "lease_length");
|
||||||
#else
|
#else
|
||||||
sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
|
lua_pushnumber(lua, data.expires);
|
||||||
|
lua_setfield(lua, -2, "lease_expires");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domain)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, domain);
|
||||||
|
lua_setfield(lua, -2, "domain");
|
||||||
|
}
|
||||||
|
|
||||||
|
end = extradata + data.ed_len;
|
||||||
|
buf = extradata;
|
||||||
|
buf = grab_extradata_lua(buf, end, "vendor_class");
|
||||||
|
buf = grab_extradata_lua(buf, end, "supplied_hostname");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_oui");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_serial");
|
||||||
|
buf = grab_extradata_lua(buf, end, "cpewan_class");
|
||||||
|
buf = grab_extradata_lua(buf, end, "tags");
|
||||||
|
|
||||||
/* supplied data may just exceed normal buffer (unlikely) */
|
for (i = 0; buf; i++)
|
||||||
if ((data.hostname_len + data.ed_len) > daemon->packet_buff_sz &&
|
{
|
||||||
!(alloc_buff = buf = malloc(data.hostname_len + data.ed_len)))
|
sprintf(daemon->dhcp_buff2, "user_class%i", i);
|
||||||
|
buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.giaddr.s_addr != 0)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, inet_ntoa(data.giaddr));
|
||||||
|
lua_setfield(lua, -2, "relay_address");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||||
|
{
|
||||||
|
lua_pushnumber(lua, data.remaining_time);
|
||||||
|
lua_setfield(lua, -2, "time_remaining");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action == ACTION_OLD_HOSTNAME && hostname)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, hostname);
|
||||||
|
lua_setfield(lua, -2, "old_hostname");
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushstring(lua, daemon->dhcp_buff);
|
||||||
|
lua_setfield(lua, -2, "mac_address");
|
||||||
|
|
||||||
|
lua_pushstring(lua, inet_ntoa(data.addr));
|
||||||
|
lua_setfield(lua, -2, "ip_address");
|
||||||
|
|
||||||
|
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* no script, just lua */
|
||||||
|
if (!daemon->lease_change_command)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!read_write(pipefd[0], buf,
|
|
||||||
data.hostname_len + data.ed_len, 1))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* possible fork errors are all temporary resource problems */
|
/* possible fork errors are all temporary resource problems */
|
||||||
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
|
||||||
sleep(2);
|
sleep(2);
|
||||||
|
|
||||||
free(alloc_buff);
|
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* wait for child to complete */
|
/* wait for child to complete */
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
@@ -188,9 +359,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
{
|
{
|
||||||
/* On error send event back to main process for logging */
|
/* On error send event back to main process for logging */
|
||||||
if (WIFSIGNALED(status))
|
if (WIFSIGNALED(status))
|
||||||
send_event(event_fd, EVENT_KILLED, WTERMSIG(status));
|
send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
|
||||||
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
|
||||||
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status));
|
send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,22 +384,11 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (data.hostname_len != 0)
|
if (domain)
|
||||||
{
|
my_setenv("DNSMASQ_DOMAIN", domain, &err);
|
||||||
char *dot;
|
|
||||||
hostname = (char *)buf;
|
end = extradata + data.ed_len;
|
||||||
hostname[data.hostname_len - 1] = 0;
|
buf = extradata;
|
||||||
if (!legal_hostname(hostname))
|
|
||||||
hostname = NULL;
|
|
||||||
else if ((dot = strchr(hostname, '.')))
|
|
||||||
{
|
|
||||||
my_setenv("DNSMASQ_DOMAIN", dot+1, &err);
|
|
||||||
*dot = 0;
|
|
||||||
}
|
|
||||||
buf += data.hostname_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
end = buf + data.ed_len;
|
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
|
||||||
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
|
||||||
@@ -245,7 +405,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
if (data.giaddr.s_addr != 0)
|
if (data.giaddr.s_addr != 0)
|
||||||
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
|
||||||
|
|
||||||
if (data.action != ACTION_DEL)
|
if (data.action != ACTION_DEL && data.remaining_time != 0)
|
||||||
{
|
{
|
||||||
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
|
||||||
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
|
||||||
@@ -271,7 +431,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
|||||||
err = errno;
|
err = errno;
|
||||||
}
|
}
|
||||||
/* failed, send event so the main process logs the problem */
|
/* failed, send event so the main process logs the problem */
|
||||||
send_event(event_fd, EVENT_EXEC_ERR, err);
|
send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -305,6 +465,28 @@ static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, ch
|
|||||||
return next + 1;
|
return next + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LUASCRIPT
|
||||||
|
static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
|
||||||
|
{
|
||||||
|
unsigned char *next;
|
||||||
|
|
||||||
|
if (!buf || (buf == end))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (next = buf; *next != 0; next++)
|
||||||
|
if (next == end)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (next != buf)
|
||||||
|
{
|
||||||
|
lua_pushstring(lua, (char *)buf);
|
||||||
|
lua_setfield(lua, -2, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* pack up lease data into a buffer */
|
/* pack up lease data into a buffer */
|
||||||
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
|
||||||
{
|
{
|
||||||
@@ -358,7 +540,11 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
|
|||||||
#else
|
#else
|
||||||
buf->expires = lease->expires;
|
buf->expires = lease->expires;
|
||||||
#endif
|
#endif
|
||||||
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
|
||||||
|
if (lease->expires != 0)
|
||||||
|
buf->remaining_time = (unsigned int)difftime(lease->expires, now);
|
||||||
|
else
|
||||||
|
buf->remaining_time = 0;
|
||||||
|
|
||||||
p = (unsigned char *)(buf+1);
|
p = (unsigned char *)(buf+1);
|
||||||
if (clid_len != 0)
|
if (clid_len != 0)
|
||||||
@@ -408,3 +594,4 @@ void helper_write(void)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+178
-31
@@ -24,10 +24,13 @@ static int dns_dirty, file_dirty, leases_left;
|
|||||||
void lease_init(time_t now)
|
void lease_init(time_t now)
|
||||||
{
|
{
|
||||||
unsigned long ei;
|
unsigned long ei;
|
||||||
struct in_addr addr;
|
struct all_addr addr;
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
int clid_len, hw_len, hw_type;
|
int clid_len, hw_len, hw_type;
|
||||||
FILE *leasestream;
|
FILE *leasestream;
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
int v6pass = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* These each hold a DHCP option max size 255
|
/* These each hold a DHCP option max size 255
|
||||||
and get a terminating zero added */
|
and get a terminating zero added */
|
||||||
@@ -70,26 +73,46 @@ void lease_init(time_t now)
|
|||||||
rewind(leasestream);
|
rewind(leasestream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
again:
|
||||||
|
#endif
|
||||||
|
|
||||||
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
/* client-id max length is 255 which is 255*2 digits + 254 colons
|
||||||
borrow DNS packet buffer which is always larger than 1000 bytes */
|
borrow DNS packet buffer which is always larger than 1000 bytes */
|
||||||
if (leasestream)
|
if (leasestream)
|
||||||
while (fscanf(leasestream, "%lu %255s %16s %255s %764s",
|
while (fscanf(leasestream, "%lu %255s %64s %255s %764s",
|
||||||
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
&ei, daemon->dhcp_buff2, daemon->namebuff,
|
||||||
daemon->dhcp_buff, daemon->packet) == 5)
|
daemon->dhcp_buff, daemon->packet) == 5)
|
||||||
{
|
{
|
||||||
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
#ifdef HAVE_DHCP6
|
||||||
/* For backwards compatibility, no explict MAC address type means ether. */
|
if (!v6pass)
|
||||||
if (hw_type == 0 && hw_len != 0)
|
#endif
|
||||||
hw_type = ARPHRD_ETHER;
|
{
|
||||||
|
hw_len = parse_hex(daemon->dhcp_buff2, (unsigned char *)daemon->dhcp_buff2, DHCP_CHADDR_MAX, NULL, &hw_type);
|
||||||
addr.s_addr = inet_addr(daemon->namebuff);
|
/* For backwards compatibility, no explict MAC address type means ether. */
|
||||||
|
if (hw_type == 0 && hw_len != 0)
|
||||||
/* decode hex in place */
|
hw_type = ARPHRD_ETHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (v6pass)
|
||||||
|
inet_pton(AF_INET6, daemon->namebuff, &addr.addr.addr6);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
inet_pton(AF_INET, daemon->namebuff, &addr.addr.addr4);
|
||||||
|
|
||||||
clid_len = 0;
|
clid_len = 0;
|
||||||
if (strcmp(daemon->packet, "*") != 0)
|
if (strcmp(daemon->packet, "*") != 0)
|
||||||
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
clid_len = parse_hex(daemon->packet, (unsigned char *)daemon->packet, 255, NULL, NULL);
|
||||||
|
|
||||||
if (!(lease = lease_allocate(addr)))
|
#ifdef HAVE_DHCP6
|
||||||
|
if (v6pass)
|
||||||
|
lease = lease_allocate6(&addr.addr.addr6);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
lease = lease_allocate4(addr.addr.addr4);
|
||||||
|
|
||||||
|
if (!lease)
|
||||||
die (_("too many stored leases"), NULL, EC_MISC);
|
die (_("too many stored leases"), NULL, EC_MISC);
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -103,8 +126,11 @@ void lease_init(time_t now)
|
|||||||
even when sizeof(time_t) == 8 */
|
even when sizeof(time_t) == 8 */
|
||||||
lease->expires = (time_t)ei;
|
lease->expires = (time_t)ei;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
#ifdef HAVE_DHCP6
|
||||||
|
if (!v6pass)
|
||||||
|
#endif
|
||||||
|
lease_set_hwaddr(lease, (unsigned char *)daemon->dhcp_buff2, (unsigned char *)daemon->packet, hw_len, hw_type, clid_len);
|
||||||
|
|
||||||
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
if (strcmp(daemon->dhcp_buff, "*") != 0)
|
||||||
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
lease_set_hostname(lease, daemon->dhcp_buff, 0);
|
||||||
@@ -113,6 +139,24 @@ void lease_init(time_t now)
|
|||||||
the startup synthesised SIGHUP. */
|
the startup synthesised SIGHUP. */
|
||||||
lease->new = lease->changed = 0;
|
lease->new = lease->changed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (!v6pass)
|
||||||
|
{
|
||||||
|
if (fscanf(leasestream, "duid %255s", daemon->dhcp_buff) == 1)
|
||||||
|
{
|
||||||
|
daemon->duid_len = parse_hex(daemon->dhcp_buff, (unsigned char *)daemon->dhcp_buff, 130, NULL, NULL);
|
||||||
|
daemon->duid = safe_malloc(daemon->duid_len);
|
||||||
|
memcpy(daemon->duid, daemon->dhcp_buff, daemon->duid_len );
|
||||||
|
v6pass = 1;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we're not doing DHCPv6, and there are not v6 leases, don't add the DUID to the database */
|
||||||
|
if (daemon->dhcp6)
|
||||||
|
make_duid(now);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
if (!daemon->lease_stream)
|
if (!daemon->lease_stream)
|
||||||
@@ -186,11 +230,18 @@ void lease_update_file(time_t now)
|
|||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
ourprintf(&err, "%u ", lease->length);
|
ourprintf(&err, "%u ", lease->length);
|
||||||
#else
|
#else
|
||||||
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
if (lease->hwaddr_type != ARPHRD_ETHER || lease->hwaddr_len == 0)
|
||||||
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
ourprintf(&err, "%.2x-", lease->hwaddr_type);
|
||||||
for (i = 0; i < lease->hwaddr_len; i++)
|
for (i = 0; i < lease->hwaddr_len; i++)
|
||||||
@@ -199,8 +250,10 @@ void lease_update_file(time_t now)
|
|||||||
if (i != lease->hwaddr_len - 1)
|
if (i != lease->hwaddr_len - 1)
|
||||||
ourprintf(&err, ":");
|
ourprintf(&err, ":");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &lease->addr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
ourprintf(&err, " %s ", inet_ntoa(lease->addr));
|
ourprintf(&err, " %s ", daemon->addrbuff);
|
||||||
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||||
|
|
||||||
if (lease->clid && lease->clid_len != 0)
|
if (lease->clid && lease->clid_len != 0)
|
||||||
@@ -213,6 +266,43 @@ void lease_update_file(time_t now)
|
|||||||
ourprintf(&err, "*\n");
|
ourprintf(&err, "*\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (daemon->duid)
|
||||||
|
{
|
||||||
|
ourprintf(&err, "duid ");
|
||||||
|
for (i = 0; i < daemon->duid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", daemon->duid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", daemon->duid[i]);
|
||||||
|
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
ourprintf(&err, "%u ", lease->length);
|
||||||
|
#else
|
||||||
|
ourprintf(&err, "%lu ", (unsigned long)lease->expires);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
|
||||||
|
|
||||||
|
ourprintf(&err, "* %s ", daemon->addrbuff);
|
||||||
|
ourprintf(&err, "%s ", lease->hostname ? lease->hostname : "*");
|
||||||
|
|
||||||
|
if (lease->clid && lease->clid_len != 0)
|
||||||
|
{
|
||||||
|
for (i = 0; i < lease->clid_len - 1; i++)
|
||||||
|
ourprintf(&err, "%.2x:", lease->clid[i]);
|
||||||
|
ourprintf(&err, "%.2x\n", lease->clid[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ourprintf(&err, "*\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fflush(daemon->lease_stream) != 0 ||
|
if (fflush(daemon->lease_stream) != 0 ||
|
||||||
fsync(fileno(daemon->lease_stream)) < 0)
|
fsync(fileno(daemon->lease_stream)) < 0)
|
||||||
err = errno;
|
err = errno;
|
||||||
@@ -275,7 +365,7 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
|||||||
if (lease->hostname)
|
if (lease->hostname)
|
||||||
dns_dirty = 1;
|
dns_dirty = 1;
|
||||||
|
|
||||||
*up = lease->next; /* unlink */
|
*up = lease->next; /* unlink */
|
||||||
|
|
||||||
/* Put on old_leases list 'till we
|
/* Put on old_leases list 'till we
|
||||||
can run the script */
|
can run the script */
|
||||||
@@ -297,18 +387,30 @@ struct dhcp_lease *lease_find_by_client(unsigned char *hwaddr, int hw_len, int h
|
|||||||
|
|
||||||
if (clid)
|
if (clid)
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->clid && clid_len == lease->clid_len &&
|
{
|
||||||
memcmp(clid, lease->clid, clid_len) == 0)
|
#ifdef HAVE_DHCP6
|
||||||
return lease;
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->clid && clid_len == lease->clid_len &&
|
||||||
|
memcmp(clid, lease->clid, clid_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if ((!lease->clid || !clid) &&
|
{
|
||||||
hw_len != 0 &&
|
#ifdef HAVE_DHCP6
|
||||||
lease->hwaddr_len == hw_len &&
|
if (lease->is_ipv6)
|
||||||
lease->hwaddr_type == hw_type &&
|
continue;
|
||||||
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
#endif
|
||||||
return lease;
|
if ((!lease->clid || !clid) &&
|
||||||
|
hw_len != 0 &&
|
||||||
|
lease->hwaddr_len == hw_len &&
|
||||||
|
lease->hwaddr_type == hw_type &&
|
||||||
|
memcmp(hwaddr, lease->hwaddr, hw_len) == 0)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,14 +419,41 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
|||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (lease->addr.s_addr == addr.s_addr)
|
{
|
||||||
return lease;
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (lease->addr.s_addr == addr.s_addr)
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find largest assigned address in context */
|
||||||
|
struct in_addr lease_find_max_addr(struct dhcp_context *context)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease;
|
||||||
|
struct in_addr addr = context->start;
|
||||||
|
|
||||||
|
if (!(context->flags & (CONTEXT_STATIC | CONTEXT_PROXY)))
|
||||||
|
for (lease = leases; lease; lease = lease->next)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
if (lease->is_ipv6)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
if (((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(context->start.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) <= ((unsigned)ntohl(context->end.s_addr)) &&
|
||||||
|
((unsigned)ntohl(lease->addr.s_addr)) > ((unsigned)ntohl(addr.s_addr)))
|
||||||
|
addr = lease->addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
struct dhcp_lease *lease_allocate(struct in_addr addr)
|
static struct dhcp_lease *lease_allocate(void)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
if (!leases_left || !(lease = whine_malloc(sizeof(struct dhcp_lease))))
|
||||||
@@ -332,8 +461,6 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
|||||||
|
|
||||||
memset(lease, 0, sizeof(struct dhcp_lease));
|
memset(lease, 0, sizeof(struct dhcp_lease));
|
||||||
lease->new = 1;
|
lease->new = 1;
|
||||||
lease->addr = addr;
|
|
||||||
lease->hwaddr_len = 256; /* illegal value */
|
|
||||||
lease->expires = 1;
|
lease->expires = 1;
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
lease->length = 0xffffffff; /* illegal value */
|
lease->length = 0xffffffff; /* illegal value */
|
||||||
@@ -347,6 +474,26 @@ struct dhcp_lease *lease_allocate(struct in_addr addr)
|
|||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dhcp_lease *lease_allocate4(struct in_addr addr)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease = lease_allocate();
|
||||||
|
lease->addr = addr;
|
||||||
|
lease->hwaddr_len = 256; /* illegal value */
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
struct dhcp_lease *lease_allocate6(struct in6_addr *addrp)
|
||||||
|
{
|
||||||
|
struct dhcp_lease *lease = lease_allocate();
|
||||||
|
memcpy(lease->hwaddr, addrp, sizeof(*addrp)) ;
|
||||||
|
lease->is_ipv6 = 1;
|
||||||
|
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
void lease_set_expires(struct dhcp_lease *lease, unsigned int len, time_t now)
|
||||||
{
|
{
|
||||||
time_t exp = now + (time_t)len;
|
time_t exp = now + (time_t)len;
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ int log_start(struct passwd *ent_pw, int errfd)
|
|||||||
|
|
||||||
if (!log_reopen(daemon->log_file))
|
if (!log_reopen(daemon->log_file))
|
||||||
{
|
{
|
||||||
send_event(errfd, EVENT_LOG_ERR, errno);
|
send_event(errfd, EVENT_LOG_ERR, errno, daemon->log_file ? daemon->log_file : "");
|
||||||
_exit(0);
|
_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +154,19 @@ static void log_write(void)
|
|||||||
|
|
||||||
while (entries)
|
while (entries)
|
||||||
{
|
{
|
||||||
|
/* The data in the payoad is written with a terminating zero character
|
||||||
|
and the length reflects this. For a stream connection we need to
|
||||||
|
send the zero as a record terminator, but this isn't done for a
|
||||||
|
datagram connection, so treat the length as one less than reality
|
||||||
|
to elide the zero. If we're logging to a file, turn the zero into
|
||||||
|
a newline, and leave the length alone. */
|
||||||
|
int len_adjust = 0;
|
||||||
|
|
||||||
|
if (log_to_file)
|
||||||
|
entries->payload[entries->offset + entries->length - 1] = '\n';
|
||||||
|
else if (connection_type == SOCK_DGRAM)
|
||||||
|
len_adjust = 1;
|
||||||
|
|
||||||
/* Avoid duplicates over a fork() */
|
/* Avoid duplicates over a fork() */
|
||||||
if (entries->pid != getpid())
|
if (entries->pid != getpid())
|
||||||
{
|
{
|
||||||
@@ -163,11 +176,11 @@ static void log_write(void)
|
|||||||
|
|
||||||
connection_good = 1;
|
connection_good = 1;
|
||||||
|
|
||||||
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length)) != -1)
|
if ((rc = write(log_fd, entries->payload + entries->offset, entries->length - len_adjust)) != -1)
|
||||||
{
|
{
|
||||||
entries->length -= rc;
|
entries->length -= rc;
|
||||||
entries->offset += rc;
|
entries->offset += rc;
|
||||||
if (entries->length == 0)
|
if (entries->length == len_adjust)
|
||||||
{
|
{
|
||||||
free_entry();
|
free_entry();
|
||||||
if (entries_lost != 0)
|
if (entries_lost != 0)
|
||||||
@@ -183,7 +196,7 @@ static void log_write(void)
|
|||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
return; /* syslogd busy, go again when select() or poll() says so */
|
return; /* syslogd busy, go again when select() or poll() says so */
|
||||||
|
|
||||||
if (errno == ENOBUFS)
|
if (errno == ENOBUFS)
|
||||||
@@ -231,7 +244,8 @@ static void log_write(void)
|
|||||||
errno == ECONNREFUSED ||
|
errno == ECONNREFUSED ||
|
||||||
errno == EISCONN ||
|
errno == EISCONN ||
|
||||||
errno == EINTR ||
|
errno == EINTR ||
|
||||||
errno == EAGAIN)
|
errno == EAGAIN ||
|
||||||
|
errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
/* try again on next syslog() call */
|
/* try again on next syslog() call */
|
||||||
connection_good = 0;
|
connection_good = 0;
|
||||||
@@ -366,10 +380,6 @@ void my_syslog(int priority, const char *format, ...)
|
|||||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||||
entry->offset = 0;
|
entry->offset = 0;
|
||||||
entry->pid = pid;
|
entry->pid = pid;
|
||||||
|
|
||||||
/* replace terminator with \n */
|
|
||||||
if (log_to_file)
|
|
||||||
entry->payload[entry->length - 1] = '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* almost always, logging won't block, so try and write this now,
|
/* almost always, logging won't block, so try and write this now,
|
||||||
|
|||||||
+39
-6
@@ -34,6 +34,7 @@
|
|||||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static struct iovec iov;
|
static struct iovec iov;
|
||||||
static u32 netlink_pid;
|
static u32 netlink_pid;
|
||||||
|
|
||||||
@@ -127,7 +128,8 @@ static ssize_t netlink_recv(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* family = AF_UNSPEC finds ARP table entries. */
|
/* family = AF_UNSPEC finds ARP table entries.
|
||||||
|
family = AF_LOCAL finds MAC addresses. */
|
||||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||||
{
|
{
|
||||||
struct sockaddr_nl addr;
|
struct sockaddr_nl addr;
|
||||||
@@ -144,10 +146,16 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
addr.nl_pad = 0;
|
addr.nl_pad = 0;
|
||||||
addr.nl_groups = 0;
|
addr.nl_groups = 0;
|
||||||
addr.nl_pid = 0; /* address to kernel */
|
addr.nl_pid = 0; /* address to kernel */
|
||||||
|
|
||||||
|
again:
|
||||||
|
if (family == AF_UNSPEC)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETNEIGH;
|
||||||
|
else if (family == AF_LOCAL)
|
||||||
|
req.nlh.nlmsg_type = RTM_GETLINK;
|
||||||
|
else
|
||||||
|
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||||
|
|
||||||
again:
|
|
||||||
req.nlh.nlmsg_len = sizeof(req);
|
req.nlh.nlmsg_len = sizeof(req);
|
||||||
req.nlh.nlmsg_type = family == AF_UNSPEC ? RTM_GETNEIGH : RTM_GETADDR;
|
|
||||||
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST | NLM_F_ACK;
|
||||||
req.nlh.nlmsg_pid = 0;
|
req.nlh.nlmsg_pid = 0;
|
||||||
req.nlh.nlmsg_seq = ++seq;
|
req.nlh.nlmsg_seq = ++seq;
|
||||||
@@ -179,7 +187,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
nl_err(h);
|
nl_err(h);
|
||||||
else if (h->nlmsg_type == NLMSG_DONE)
|
else if (h->nlmsg_type == NLMSG_DONE)
|
||||||
return 1;
|
return 1;
|
||||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC)
|
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
|
||||||
{
|
{
|
||||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||||
struct rtattr *rta = IFA_RTA(ifa);
|
struct rtattr *rta = IFA_RTA(ifa);
|
||||||
@@ -222,7 +230,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (addrp)
|
if (addrp)
|
||||||
if (!((*callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
if (!((*callback)(addrp, ifa->ifa_prefixlen, ifa->ifa_index,
|
||||||
|
ifa->ifa_index, ifa->ifa_flags & IFA_F_TENTATIVE, parm)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -252,7 +261,31 @@ int iface_enumerate(int family, void *parm, int (*callback)())
|
|||||||
if (inaddr && mac)
|
if (inaddr && mac)
|
||||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
else if (h->nlmsg_type == RTM_NEWLINK && family == AF_LOCAL)
|
||||||
|
{
|
||||||
|
struct ifinfomsg *link = NLMSG_DATA(h);
|
||||||
|
struct rtattr *rta = IFLA_RTA(link);
|
||||||
|
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*link));
|
||||||
|
char *mac = NULL;
|
||||||
|
size_t maclen = 0;
|
||||||
|
|
||||||
|
while (RTA_OK(rta, len1))
|
||||||
|
{
|
||||||
|
if (rta->rta_type == IFLA_ADDRESS)
|
||||||
|
{
|
||||||
|
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||||
|
mac = (char *)(rta+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rta = RTA_NEXT(rta, len1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mac && !((*callback)(link->ifi_type, link->ifi_flags, mac, maclen, parm)))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+120
-129
@@ -107,7 +107,7 @@ int indextoname(int fd, int index, char *name)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
int iface_check(int family, struct all_addr *addr, char *name)
|
||||||
{
|
{
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
@@ -115,7 +115,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
/* Note: have to check all and not bail out early, so that we set the
|
/* Note: have to check all and not bail out early, so that we set the
|
||||||
"used" flags. */
|
"used" flags. */
|
||||||
|
|
||||||
if (daemon->if_names || (addr && daemon->if_addrs))
|
if (daemon->if_names || daemon->if_addrs)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
struct dhcp_context *range;
|
struct dhcp_context *range;
|
||||||
@@ -134,7 +134,7 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
ret = tmp->used = 1;
|
ret = tmp->used = 1;
|
||||||
|
|
||||||
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
|
||||||
if (addr && tmp->addr.sa.sa_family == family)
|
if (tmp->addr.sa.sa_family == family)
|
||||||
{
|
{
|
||||||
if (family == AF_INET &&
|
if (family == AF_INET &&
|
||||||
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
|
||||||
@@ -151,43 +151,12 @@ int iface_check(int family, struct all_addr *addr, char *name, int *indexp)
|
|||||||
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
if (indexp)
|
|
||||||
{
|
|
||||||
/* One form of bridging on BSD has the property that packets
|
|
||||||
can be recieved on bridge interfaces which do not have an IP address.
|
|
||||||
We allow these to be treated as aliases of another interface which does have
|
|
||||||
an IP address with --dhcp-bridge=interface,alias,alias */
|
|
||||||
struct dhcp_bridge *bridge, *alias;
|
|
||||||
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
|
|
||||||
{
|
|
||||||
for (alias = bridge->alias; alias; alias = alias->next)
|
|
||||||
if (strncmp(name, alias->iface, IF_NAMESIZE) == 0)
|
|
||||||
{
|
|
||||||
int newindex;
|
|
||||||
|
|
||||||
if (!(newindex = if_nametoindex(bridge->iface)))
|
|
||||||
{
|
|
||||||
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*indexp = newindex;
|
|
||||||
strncpy(name, bridge->iface, IF_NAMESIZE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (alias)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int iface_allowed(struct irec **irecp, int if_index,
|
static int iface_allowed(struct irec **irecp, int if_index,
|
||||||
union mysockaddr *addr, struct in_addr netmask)
|
union mysockaddr *addr, struct in_addr netmask, int dad)
|
||||||
{
|
{
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int fd, mtu = 0, loopback;
|
int fd, mtu = 0, loopback;
|
||||||
@@ -202,8 +171,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
we call this routine multiple times. */
|
we call this routine multiple times. */
|
||||||
for (iface = *irecp; iface; iface = iface->next)
|
for (iface = *irecp; iface; iface = iface->next)
|
||||||
if (sockaddr_isequal(&iface->addr, addr))
|
if (sockaddr_isequal(&iface->addr, addr))
|
||||||
return 1;
|
{
|
||||||
|
iface->dad = dad;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||||
!indextoname(fd, if_index, ifr.ifr_name) ||
|
!indextoname(fd, if_index, ifr.ifr_name) ||
|
||||||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
|
||||||
@@ -260,7 +232,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
if (!ir)
|
if (!ir)
|
||||||
{
|
{
|
||||||
if (addr->sa.sa_family == AF_INET &&
|
if (addr->sa.sa_family == AF_INET &&
|
||||||
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifdef HAVE_DHCP
|
#ifdef HAVE_DHCP
|
||||||
@@ -271,7 +243,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (addr->sa.sa_family == AF_INET6 &&
|
if (addr->sa.sa_family == AF_INET6 &&
|
||||||
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, NULL))
|
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -283,6 +255,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
iface->netmask = netmask;
|
iface->netmask = netmask;
|
||||||
iface->tftp_ok = tftp_ok;
|
iface->tftp_ok = tftp_ok;
|
||||||
iface->mtu = mtu;
|
iface->mtu = mtu;
|
||||||
|
iface->dad = dad;
|
||||||
|
iface->done = 0;
|
||||||
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
|
||||||
strcpy(iface->name, ifr.ifr_name);
|
strcpy(iface->name, ifr.ifr_name);
|
||||||
iface->next = *irecp;
|
iface->next = *irecp;
|
||||||
@@ -295,12 +269,13 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
static int iface_allowed_v6(struct in6_addr *local,
|
static int iface_allowed_v6(struct in6_addr *local, int prefix,
|
||||||
int scope, int if_index, void *vparam)
|
int scope, int if_index, int dad, void *vparam)
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct in_addr netmask; /* dummy */
|
struct in_addr netmask; /* dummy */
|
||||||
|
|
||||||
|
(void)prefix; /* warning */
|
||||||
netmask.s_addr = 0;
|
netmask.s_addr = 0;
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -312,7 +287,7 @@ static int iface_allowed_v6(struct in6_addr *local,
|
|||||||
addr.in6.sin6_port = htons(daemon->port);
|
addr.in6.sin6_port = htons(daemon->port);
|
||||||
addr.in6.sin6_scope_id = scope;
|
addr.in6.sin6_scope_id = scope;
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, dad);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -330,7 +305,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
|||||||
addr.in.sin_addr = local;
|
addr.in.sin_addr = local;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask);
|
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int enumerate_interfaces(void)
|
int enumerate_interfaces(void)
|
||||||
@@ -355,13 +330,10 @@ int fix_fd(int fd)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_sock(union mysockaddr *addr, int type)
|
static int make_sock(union mysockaddr *addr, int type, int dienow)
|
||||||
{
|
{
|
||||||
int family = addr->sa.sa_family;
|
int family = addr->sa.sa_family;
|
||||||
int fd, rc, opt = 1;
|
int fd, rc, opt = 1;
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
static int dad_count = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((fd = socket(family, type, 0)) == -1)
|
if ((fd = socket(family, type, 0)) == -1)
|
||||||
{
|
{
|
||||||
@@ -374,42 +346,27 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
port = prettyprint_addr(addr, daemon->namebuff);
|
if (dienow)
|
||||||
if (!option_bool(OPT_NOWILD))
|
{
|
||||||
sprintf(daemon->namebuff, "port %d", port);
|
port = prettyprint_addr(addr, daemon->namebuff);
|
||||||
die(_("failed to create listening socket for %s: %s"),
|
if (!option_bool(OPT_NOWILD))
|
||||||
daemon->namebuff, EC_BADNET);
|
sprintf(daemon->namebuff, "port %d", port);
|
||||||
|
die(_("failed to create listening socket for %s: %s"),
|
||||||
|
daemon->namebuff, EC_BADNET);
|
||||||
|
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (family == AF_INET6 && setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
if (family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1)
|
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) == -1)
|
||||||
{
|
|
||||||
if ((rc = bind(fd, (struct sockaddr *)addr, sa_len(addr))) != -1)
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
/* An interface may have an IPv6 address which is still undergoing DAD.
|
|
||||||
If so, the bind will fail until the DAD completes, so we try over 20 seconds
|
|
||||||
before failing. */
|
|
||||||
if (family == AF_INET6 &&
|
|
||||||
(errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
|
||||||
dad_count++ < DAD_WAIT)
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == -1)
|
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (type == SOCK_STREAM)
|
if (type == SOCK_STREAM)
|
||||||
@@ -422,7 +379,7 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
if (family == AF_INET)
|
if (family == AF_INET)
|
||||||
{
|
{
|
||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||||
goto err;
|
goto err;
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
@@ -431,46 +388,52 @@ static int make_sock(union mysockaddr *addr, int type)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else if (!set_ipv6pktinfo(fd))
|
||||||
{
|
goto err;
|
||||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
|
||||||
handle all combinations of headers and kernel.
|
|
||||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
|
||||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
|
||||||
|
|
||||||
# ifdef IPV6_RECVPKTINFO
|
|
||||||
# ifdef IPV6_2292PKTINFO
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
{
|
|
||||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
|
||||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
|
||||||
else
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
|
||||||
goto err;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int set_ipv6pktinfo(int fd)
|
||||||
|
{
|
||||||
|
int opt = 1;
|
||||||
|
|
||||||
|
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||||
|
handle all combinations of headers and kernel.
|
||||||
|
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||||
|
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||||
|
|
||||||
|
#ifdef IPV6_RECVPKTINFO
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
# ifdef IPV6_2292PKTINFO
|
||||||
|
else if (errno == ENOPROTOOPT && setsockopt(fd, IPPROTO_IPV6, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
{
|
||||||
|
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &opt, sizeof(opt)) != -1)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp, int dienow)
|
||||||
{
|
{
|
||||||
struct listener *l = NULL;
|
struct listener *l = NULL;
|
||||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||||
|
|
||||||
if (daemon->port != 0)
|
if (daemon->port != 0)
|
||||||
{
|
{
|
||||||
fd = make_sock(addr, SOCK_DGRAM);
|
fd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
tcpfd = make_sock(addr, SOCK_STREAM, dienow);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_TFTP
|
#ifdef HAVE_TFTP
|
||||||
@@ -481,7 +444,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
/* port must be restored to DNS port for TCP code */
|
/* port must be restored to DNS port for TCP code */
|
||||||
short save = addr->in.sin_port;
|
short save = addr->in.sin_port;
|
||||||
addr->in.sin_port = htons(TFTP_PORT);
|
addr->in.sin_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in.sin_port = save;
|
addr->in.sin_port = save;
|
||||||
}
|
}
|
||||||
# ifdef HAVE_IPV6
|
# ifdef HAVE_IPV6
|
||||||
@@ -489,7 +452,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
{
|
{
|
||||||
short save = addr->in6.sin6_port;
|
short save = addr->in6.sin6_port;
|
||||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
tftpfd = make_sock(addr, SOCK_DGRAM, dienow);
|
||||||
addr->in6.sin6_port = save;
|
addr->in6.sin6_port = save;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
@@ -509,7 +472,7 @@ static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_wildcard_listeners(void)
|
void create_wildcard_listeners(void)
|
||||||
{
|
{
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
struct listener *l;
|
struct listener *l;
|
||||||
@@ -523,7 +486,7 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
addr.in.sin_port = htons(daemon->port);
|
addr.in.sin_port = htons(daemon->port);
|
||||||
|
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
@@ -535,31 +498,41 @@ struct listener *create_wildcard_listeners(void)
|
|||||||
addr.in6.sin6_port = htons(daemon->port);
|
addr.in6.sin6_port = htons(daemon->port);
|
||||||
|
|
||||||
if (l)
|
if (l)
|
||||||
l->next = create_listeners(&addr, tftp_enabled);
|
l->next = create_listeners(&addr, tftp_enabled, 1);
|
||||||
else
|
else
|
||||||
l = create_listeners(&addr, tftp_enabled);
|
l = create_listeners(&addr, tftp_enabled, 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return l;
|
daemon->listeners = l;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_bound_listeners(void)
|
void create_bound_listeners(int dienow)
|
||||||
{
|
{
|
||||||
struct listener *new, *listeners = NULL;
|
struct listener *new;
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
|
|
||||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
if (!iface->done && !iface->dad &&
|
||||||
|
(new = create_listeners(&iface->addr, iface->tftp_ok, dienow)))
|
||||||
{
|
{
|
||||||
new->iface = iface;
|
new->iface = iface;
|
||||||
new->next = listeners;
|
new->next = daemon->listeners;
|
||||||
listeners = new;
|
daemon->listeners = new;
|
||||||
|
iface->done = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return listeners;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_dad_listeners(void)
|
||||||
|
{
|
||||||
|
struct irec *iface;
|
||||||
|
|
||||||
|
if (option_bool(OPT_NOWILD))
|
||||||
|
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||||
|
if (iface->dad && !iface->done)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||||
occupied port nos and reserved ones. */
|
occupied port nos and reserved ones. */
|
||||||
int random_sock(int family)
|
int random_sock(int family)
|
||||||
@@ -896,20 +869,38 @@ int reload_servers(char *fname)
|
|||||||
source_addr.in.sin_port = htons(daemon->query_port);
|
source_addr.in.sin_port = htons(daemon->query_port);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
else
|
||||||
{
|
{
|
||||||
|
int scope_index = 0;
|
||||||
|
char *scope_id = strchr(token, '%');
|
||||||
|
|
||||||
|
if (scope_id)
|
||||||
|
{
|
||||||
|
*(scope_id++) = 0;
|
||||||
|
scope_index = if_nametoindex(scope_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET6, token, &addr.in6.sin6_addr) > 0)
|
||||||
|
{
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
source_addr.in6.sin6_len = addr.in6.sin6_len = sizeof(source_addr.in6);
|
||||||
#endif
|
#endif
|
||||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
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 = 0;
|
||||||
source_addr.in6.sin6_addr = in6addr_any;
|
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
addr.in6.sin6_scope_id = scope_index;
|
||||||
|
source_addr.in6.sin6_addr = in6addr_any;
|
||||||
|
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||||
|
source_addr.in6.sin6_scope_id = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
#endif /* IPV6 */
|
#else /* IPV6 */
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (old_servers)
|
if (old_servers)
|
||||||
{
|
{
|
||||||
serv = old_servers;
|
serv = old_servers;
|
||||||
|
|||||||
+60
-13
@@ -110,6 +110,10 @@ struct myoption {
|
|||||||
#define LOPT_LOC_REBND 299
|
#define LOPT_LOC_REBND 299
|
||||||
#define LOPT_ADD_MAC 300
|
#define LOPT_ADD_MAC 300
|
||||||
#define LOPT_DNSSEC 301
|
#define LOPT_DNSSEC 301
|
||||||
|
#define LOPT_INCR_ADDR 302
|
||||||
|
#define LOPT_CONNTRACK 303
|
||||||
|
#define LOPT_FQDN 304
|
||||||
|
#define LOPT_LUASCRIPT 305
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static const struct option opts[] =
|
static const struct option opts[] =
|
||||||
@@ -225,6 +229,10 @@ static const struct myoption opts[] =
|
|||||||
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
|
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
|
||||||
{ "add-mac", 0, 0, LOPT_ADD_MAC },
|
{ "add-mac", 0, 0, LOPT_ADD_MAC },
|
||||||
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
|
||||||
|
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
|
||||||
|
{ "conntrack", 0, 0, LOPT_CONNTRACK },
|
||||||
|
{ "dhcp-client-update", 0, 0, LOPT_FQDN },
|
||||||
|
{ "dhcp-luascript", 1, 0, LOPT_LUASCRIPT },
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -345,8 +353,12 @@ static struct {
|
|||||||
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
|
||||||
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
|
||||||
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
|
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
|
||||||
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries"), NULL },
|
{ LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
|
||||||
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers"), NULL },
|
{ LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
|
||||||
|
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
|
||||||
|
{ LOPT_CONNTRACK, OPT_CONNTRACK, NULL, gettext_noop("Copy connection-track mark from queries to upstream connections."), NULL },
|
||||||
|
{ LOPT_FQDN, OPT_FQDN_UPDATE, NULL, gettext_noop("Allow DHCP clients to do their own DDNS updates."), NULL },
|
||||||
|
{ LOPT_LUASCRIPT, ARG_DUP, "luascript", gettext_noop("Specify path to Lua script (no default)."), NULL },
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
{ 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1289,16 +1301,25 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
daemon->lease_file = opt_string_alloc(arg);
|
daemon->lease_file = opt_string_alloc(arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '6': /* --dhcp-script */
|
/* Sorry about the gross pre-processor abuse */
|
||||||
|
case '6': /* --dhcp-script */
|
||||||
|
case LOPT_LUASCRIPT: /* --dhcp-luascript */
|
||||||
# if defined(NO_FORK)
|
# if defined(NO_FORK)
|
||||||
problem = _("cannot run scripts under uClinux");
|
problem = _("cannot run scripts under uClinux");
|
||||||
# elif !defined(HAVE_SCRIPT)
|
# elif !defined(HAVE_SCRIPT)
|
||||||
problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
|
problem = _("recompile with HAVE_SCRIPT defined to enable lease-change scripts");
|
||||||
# else
|
# else
|
||||||
daemon->lease_change_command = opt_string_alloc(arg);
|
if (option == LOPT_LUASCRIPT)
|
||||||
|
# if !defined(HAVE_LUASCRIPT)
|
||||||
|
problem = _("recompile with HAVE_LUASCRIPT defined to enable Lua scripts");
|
||||||
|
# else
|
||||||
|
daemon->luascript = opt_string_alloc(arg);
|
||||||
|
# endif
|
||||||
|
else
|
||||||
|
daemon->lease_change_command = opt_string_alloc(arg);
|
||||||
# endif
|
# endif
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif /* HAVE_DHCP */
|
||||||
|
|
||||||
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
case LOPT_DHCP_HOST: /* --dhcp-hostfile */
|
||||||
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
|
||||||
@@ -1590,6 +1611,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
{
|
{
|
||||||
int source_port = 0, serv_port = NAMESERVER_PORT;
|
int source_port = 0, serv_port = NAMESERVER_PORT;
|
||||||
char *portno, *source;
|
char *portno, *source;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int scope_index = 0;
|
||||||
|
char *scope_id;
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
if ((source = split_chr(arg, '@')) && /* is there a source. */
|
||||||
(portno = split_chr(source, '#')) &&
|
(portno = split_chr(source, '#')) &&
|
||||||
@@ -1600,6 +1625,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
!atoi_check16(portno, &serv_port))
|
!atoi_check16(portno, &serv_port))
|
||||||
problem = _("bad port");
|
problem = _("bad port");
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
scope_id = split_chr(arg, '%');
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
if ((newlist->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
|
||||||
{
|
{
|
||||||
newlist->addr.in.sin_port = htons(serv_port);
|
newlist->addr.in.sin_port = htons(serv_port);
|
||||||
@@ -1627,16 +1656,22 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
|
else if (inet_pton(AF_INET6, arg, &newlist->addr.in6.sin6_addr) > 0)
|
||||||
{
|
{
|
||||||
|
if (scope_id && (scope_index = if_nametoindex(scope_id)) == 0)
|
||||||
|
problem = _("bad interface name");
|
||||||
|
|
||||||
newlist->addr.in6.sin6_port = htons(serv_port);
|
newlist->addr.in6.sin6_port = htons(serv_port);
|
||||||
|
newlist->addr.in6.sin6_scope_id = scope_index;
|
||||||
newlist->source_addr.in6.sin6_port = htons(source_port);
|
newlist->source_addr.in6.sin6_port = htons(source_port);
|
||||||
|
newlist->source_addr.in6.sin6_scope_id = 0;
|
||||||
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
|
newlist->addr.sa.sa_family = newlist->source_addr.sa.sa_family = AF_INET6;
|
||||||
|
newlist->addr.in6.sin6_flowinfo = newlist->source_addr.in6.sin6_flowinfo = 0;
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
|
newlist->addr.in6.sin6_len = newlist->source_addr.in6.sin6_len = sizeof(newlist->addr.in6);
|
||||||
#endif
|
#endif
|
||||||
if (source)
|
if (source)
|
||||||
{
|
{
|
||||||
newlist->flags |= SERV_HAS_SOURCE;
|
newlist->flags |= SERV_HAS_SOURCE;
|
||||||
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
|
if (inet_pton(AF_INET6, source, &newlist->source_addr.in6.sin6_addr) == 0)
|
||||||
{
|
{
|
||||||
#if defined(SO_BINDTODEVICE)
|
#if defined(SO_BINDTODEVICE)
|
||||||
newlist->source_addr.in6.sin6_addr = in6addr_any;
|
newlist->source_addr.in6.sin6_addr = in6addr_any;
|
||||||
@@ -1652,7 +1687,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
option = '?'; /* error */
|
option = '?'; /* error */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serv = newlist;
|
serv = newlist;
|
||||||
@@ -1842,6 +1876,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
new->netmask.s_addr = 0;
|
new->netmask.s_addr = 0;
|
||||||
new->broadcast.s_addr = 0;
|
new->broadcast.s_addr = 0;
|
||||||
new->router.s_addr = 0;
|
new->router.s_addr = 0;
|
||||||
|
new->local.s_addr = 0;
|
||||||
new->netid.net = NULL;
|
new->netid.net = NULL;
|
||||||
new->filter = NULL;
|
new->filter = NULL;
|
||||||
new->flags = 0;
|
new->flags = 0;
|
||||||
@@ -2037,7 +2072,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
strcpy(newtag->net, arg+4);
|
strcpy(newtag->net, arg+4);
|
||||||
unhide_metas(newtag->net);
|
unhide_metas(newtag->net);
|
||||||
}
|
}
|
||||||
else
|
else if (strstr(arg, "tag:") == arg)
|
||||||
|
problem = _("cannot match tags in --dhcp-host");
|
||||||
|
else
|
||||||
{
|
{
|
||||||
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
|
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
|
||||||
if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
|
if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
|
||||||
@@ -2218,7 +2255,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
option = '?';
|
option = '?';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *dhcp_file, *dhcp_sname = NULL;
|
char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
|
||||||
struct in_addr dhcp_next_server;
|
struct in_addr dhcp_next_server;
|
||||||
comma = split(arg);
|
comma = split(arg);
|
||||||
dhcp_file = opt_string_alloc(arg);
|
dhcp_file = opt_string_alloc(arg);
|
||||||
@@ -2231,8 +2268,17 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
if (comma)
|
if (comma)
|
||||||
{
|
{
|
||||||
unhide_metas(comma);
|
unhide_metas(comma);
|
||||||
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
|
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
|
||||||
option = '?';
|
|
||||||
|
/*
|
||||||
|
* The user may have specified the tftp hostname here.
|
||||||
|
* save it so that it can be resolved/looked up during
|
||||||
|
* actual dhcp_reply().
|
||||||
|
*/
|
||||||
|
|
||||||
|
tftp_sname = opt_string_alloc(comma);
|
||||||
|
dhcp_next_server.s_addr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (option != '?')
|
if (option != '?')
|
||||||
@@ -2240,6 +2286,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
|
|||||||
struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
|
struct dhcp_boot *new = opt_malloc(sizeof(struct dhcp_boot));
|
||||||
new->file = dhcp_file;
|
new->file = dhcp_file;
|
||||||
new->sname = dhcp_sname;
|
new->sname = dhcp_sname;
|
||||||
|
new->tftp_sname = tftp_sname;
|
||||||
new->next_server = dhcp_next_server;
|
new->next_server = dhcp_next_server;
|
||||||
new->netid = id;
|
new->netid = id;
|
||||||
new->next = daemon->boot_config;
|
new->next = daemon->boot_config;
|
||||||
@@ -3267,7 +3314,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
|
|||||||
else if (option == 'v')
|
else if (option == 'v')
|
||||||
{
|
{
|
||||||
printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
|
printf(_("Dnsmasq version %s %s\n"), VERSION, COPYRIGHT);
|
||||||
printf(_("Compile time options %s\n\n"), compile_opts);
|
printf(_("Compile time options: %s\n\n"), compile_opts);
|
||||||
printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
|
printf(_("This software comes with ABSOLUTELY NO WARRANTY.\n"));
|
||||||
printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
|
printf(_("Dnsmasq is free software, and you are welcome to redistribute it\n"));
|
||||||
printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
|
printf(_("under the terms of the GNU General Public License, version 2 or 3.\n"));
|
||||||
|
|||||||
+11
-9
@@ -642,7 +642,6 @@ static int private_net(struct in_addr addr, int ban_localhost)
|
|||||||
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
|
static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *header, size_t qlen, char *name)
|
||||||
{
|
{
|
||||||
int i, qtype, qclass, rdlen;
|
int i, qtype, qclass, rdlen;
|
||||||
unsigned long ttl;
|
|
||||||
|
|
||||||
for (i = count; i != 0; i--)
|
for (i = count; i != 0; i--)
|
||||||
{
|
{
|
||||||
@@ -656,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, struct dns_header *
|
|||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
GETLONG(ttl, p);
|
p += 4; /* ttl */
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
if (qclass == C_IN && qtype == T_A)
|
if (qclass == C_IN && qtype == T_A)
|
||||||
@@ -1044,8 +1043,6 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
return F_IPV6;
|
return F_IPV6;
|
||||||
if (qtype == T_ANY)
|
if (qtype == T_ANY)
|
||||||
return F_IPV4 | F_IPV6;
|
return F_IPV4 | F_IPV6;
|
||||||
if (qtype == T_NS || qtype == T_SOA)
|
|
||||||
return F_QUERY | F_NSRR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return F_QUERY;
|
return F_QUERY;
|
||||||
@@ -1101,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
|
|||||||
struct txt_record *txt;
|
struct txt_record *txt;
|
||||||
struct interface_name *intr;
|
struct interface_name *intr;
|
||||||
struct ptr_record *ptr;
|
struct ptr_record *ptr;
|
||||||
|
struct naptr *naptr;
|
||||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
|
||||||
|
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (mx = daemon->mxnames; mx; mx = mx->next)
|
for (naptr = daemon->naptr; naptr; naptr = naptr->next)
|
||||||
|
if (hostname_isequal(name, naptr->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (mx = daemon->mxnames; mx; mx = mx->next)
|
||||||
if (hostname_isequal(name, mx->name))
|
if (hostname_isequal(name, mx->name))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -1309,11 +1311,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
|||||||
|
|
||||||
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
||||||
{
|
{
|
||||||
unsigned short udpsz, ext_rcode, flags;
|
unsigned short udpsz, flags;
|
||||||
unsigned char *psave = pheader;
|
unsigned char *psave = pheader;
|
||||||
|
|
||||||
GETSHORT(udpsz, pheader);
|
GETSHORT(udpsz, pheader);
|
||||||
GETSHORT(ext_rcode, pheader);
|
pheader += 2; /* ext_rcode */
|
||||||
GETSHORT(flags, pheader);
|
GETSHORT(flags, pheader);
|
||||||
|
|
||||||
sec_reqd = flags & 0x8000; /* do bit */
|
sec_reqd = flags & 0x8000; /* do bit */
|
||||||
|
|||||||
+204
-111
@@ -41,8 +41,8 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
|||||||
int mac_len, char *interface, char *string, u32 xid);
|
int mac_len, char *interface, char *string, u32 xid);
|
||||||
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
static unsigned char *option_find(struct dhcp_packet *mess, size_t size, int opt_type, int minsize);
|
||||||
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt, int minsize);
|
||||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
|
||||||
unsigned char *agent_id, unsigned char *real_end);
|
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||||
static void do_options(struct dhcp_context *context,
|
static void do_options(struct dhcp_context *context,
|
||||||
struct dhcp_packet *mess,
|
struct dhcp_packet *mess,
|
||||||
@@ -51,11 +51,12 @@ static void do_options(struct dhcp_context *context,
|
|||||||
char *hostname,
|
char *hostname,
|
||||||
char *domain, char *config_domain,
|
char *domain, char *config_domain,
|
||||||
struct dhcp_netid *netid,
|
struct dhcp_netid *netid,
|
||||||
struct in_addr subnet_addr,
|
struct in_addr subnet_addr,
|
||||||
unsigned char fqdn_flags,
|
unsigned char fqdn_flags,
|
||||||
int null_term, int pxearch,
|
int null_term, int pxearch,
|
||||||
unsigned char *uuid,
|
unsigned char *uuid,
|
||||||
int vendor_class_len);
|
int vendor_class_len,
|
||||||
|
time_t now);
|
||||||
|
|
||||||
|
|
||||||
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
static void match_vendor_opts(unsigned char *opt, struct dhcp_opt *dopt);
|
||||||
@@ -67,7 +68,7 @@ struct dhcp_boot *find_boot(struct dhcp_netid *netid);
|
|||||||
|
|
||||||
|
|
||||||
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||||
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe)
|
size_t sz, time_t now, int unicast_dest, int *is_inform, int pxe, struct in_addr fallback)
|
||||||
{
|
{
|
||||||
unsigned char *opt, *clid = NULL;
|
unsigned char *opt, *clid = NULL;
|
||||||
struct dhcp_lease *ltmp, *lease = NULL;
|
struct dhcp_lease *ltmp, *lease = NULL;
|
||||||
@@ -85,7 +86,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
unsigned int time;
|
unsigned int time;
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
struct dhcp_netid *netid, *tagif_netid;
|
struct dhcp_netid *netid, *tagif_netid;
|
||||||
struct in_addr subnet_addr, fallback, override;
|
struct in_addr subnet_addr, override;
|
||||||
unsigned short fuzz = 0;
|
unsigned short fuzz = 0;
|
||||||
unsigned int mess_type = 0;
|
unsigned int mess_type = 0;
|
||||||
unsigned char fqdn_flags = 0;
|
unsigned char fqdn_flags = 0;
|
||||||
@@ -297,17 +298,43 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!context_new)
|
if (!context_new)
|
||||||
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
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) &&
|
struct in_addr netmask = context_tmp->netmask;
|
||||||
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
|
||||||
{
|
/* guess the netmask for relayed networks */
|
||||||
context_tmp->current = context_new;
|
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
|
||||||
context_new = context_tmp;
|
{
|
||||||
}
|
if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xff000000);
|
||||||
|
else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xffff0000);
|
||||||
|
else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr)))
|
||||||
|
netmask.s_addr = htonl(0xffffff00);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This section fills in context mainly when a client which is on a remote (relayed)
|
||||||
|
network renews a lease without using the relay, after dnsmasq has restarted. */
|
||||||
|
if (netmask.s_addr != 0 &&
|
||||||
|
is_same_net(addr, context_tmp->start, netmask) &&
|
||||||
|
is_same_net(addr, context_tmp->end, netmask))
|
||||||
|
{
|
||||||
|
context_tmp->netmask = netmask;
|
||||||
|
if (context_tmp->local.s_addr == 0)
|
||||||
|
context_tmp->local = fallback;
|
||||||
|
if (context_tmp->router.s_addr == 0)
|
||||||
|
context_tmp->router = mess->giaddr;
|
||||||
|
|
||||||
|
/* fill in missing broadcast addresses for relayed ranges */
|
||||||
|
if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 )
|
||||||
|
context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr;
|
||||||
|
|
||||||
|
context_tmp->current = context_new;
|
||||||
|
context_new = context_tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (context_new || force)
|
if (context_new || force)
|
||||||
context = context_new;
|
context = context_new;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
@@ -318,9 +345,6 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keep _a_ local address available. */
|
|
||||||
fallback = context->local;
|
|
||||||
|
|
||||||
if (option_bool(OPT_LOG_OPTS))
|
if (option_bool(OPT_LOG_OPTS))
|
||||||
{
|
{
|
||||||
struct dhcp_context *context_tmp;
|
struct dhcp_context *context_tmp;
|
||||||
@@ -441,9 +465,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
else if (context->netid.net)
|
else if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if(&context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, mess);
|
||||||
|
|
||||||
if (!message && !nailed)
|
if (!message && !nailed)
|
||||||
{
|
{
|
||||||
@@ -456,7 +481,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!message &&
|
if (!message &&
|
||||||
!lease &&
|
!lease &&
|
||||||
(!(lease = lease_allocate(mess->yiaddr))))
|
(!(lease = lease_allocate4(mess->yiaddr))))
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
@@ -474,13 +499,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, NULL, hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, 0, 0, 0, NULL, 0);
|
domain, netid, subnet_addr, 0, 0, 0, NULL, 0, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
log_packet("BOOTP", logaddr, mess->chaddr, mess->hlen, iface_name, message, mess->xid);
|
||||||
|
|
||||||
return message ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return message ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
if ((opt = option_find(mess, sz, OPTION_CLIENT_FQDN, 4)))
|
||||||
@@ -496,11 +521,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
pp = op;
|
pp = op;
|
||||||
|
|
||||||
/* Always force update, since the client has no way to do it itself. */
|
/* Always force update, since the client has no way to do it itself. */
|
||||||
if (!(fqdn_flags & 0x01))
|
if (!option_bool(OPT_FQDN_UPDATE) && !(fqdn_flags & 0x01))
|
||||||
fqdn_flags |= 0x02;
|
fqdn_flags |= 0x03;
|
||||||
|
|
||||||
fqdn_flags &= ~0x08;
|
fqdn_flags &= ~0x08;
|
||||||
fqdn_flags |= 0x01;
|
|
||||||
|
|
||||||
if (fqdn_flags & 0x04)
|
if (fqdn_flags & 0x04)
|
||||||
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
while (*op != 0 && ((op + (*op) + 1) - pp) < len)
|
||||||
@@ -795,7 +819,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
do_encap_opts(&opt71, OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||||
|
|
||||||
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
log_packet("PXE", &mess->yiaddr, emac, emac_len, iface_name, (char *)mess->file, mess->xid);
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
log_tags(tagif_netid, mess);
|
||||||
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
|
if ((opt = option_find(mess, sz, OPTION_ARCH, 2)))
|
||||||
@@ -829,8 +854,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
and set discovery_control = 8 */
|
and set discovery_control = 8 */
|
||||||
if (boot)
|
if (boot)
|
||||||
{
|
{
|
||||||
if (boot->next_server.s_addr)
|
if (boot->next_server.s_addr)
|
||||||
mess->siaddr = boot->next_server;
|
mess->siaddr = boot->next_server;
|
||||||
|
else if (boot->tftp_sname)
|
||||||
|
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||||
|
|
||||||
if (boot->file)
|
if (boot->file)
|
||||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||||
@@ -844,7 +871,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||||
|
|
||||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||||
return ignore ? 0 : dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
log_tags(tagif_netid, mess);
|
||||||
|
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -975,15 +1003,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
if (message || !(context = narrow_context(context, mess->yiaddr, tagif_netid)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
|
||||||
|
|
||||||
if (context->netid.net)
|
if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if(&context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, mess);
|
||||||
|
|
||||||
|
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||||
|
|
||||||
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
time = calc_time(context, config, option_find(mess, sz, OPTION_LEASE_TIME, 4));
|
||||||
clear_packet(mess, end);
|
clear_packet(mess, end);
|
||||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||||
@@ -996,9 +1025,9 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
option_put(mess, end, OPTION_T2, 4, (time*7)/8);
|
||||||
}
|
}
|
||||||
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, offer_hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
|
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
|
|
||||||
case DHCPREQUEST:
|
case DHCPREQUEST:
|
||||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
@@ -1029,12 +1058,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
/* In auth mode, a REQUEST sent to the wrong server
|
/* Handle very strange configs where clients have more than one route to the server.
|
||||||
should be faulted, so that the client establishes
|
If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
|
||||||
communication with us, otherwise, silently ignore. */
|
Have to set override to make sure we echo back the correct server-id */
|
||||||
if (!option_bool(OPT_AUTHORITATIVE))
|
struct irec *intr;
|
||||||
return 0;
|
|
||||||
message = _("wrong server-ID");
|
enumerate_interfaces();
|
||||||
|
|
||||||
|
for (intr = daemon->interfaces; intr; intr = intr->next)
|
||||||
|
if (intr->addr.sa.sa_family == AF_INET &&
|
||||||
|
intr->addr.in.sin_addr.s_addr == option_addr(opt).s_addr &&
|
||||||
|
intr->tftp_ok)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (intr)
|
||||||
|
override = intr->addr.in.sin_addr;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* In auth mode, a REQUEST sent to the wrong server
|
||||||
|
should be faulted, so that the client establishes
|
||||||
|
communication with us, otherwise, silently ignore. */
|
||||||
|
if (!option_bool(OPT_AUTHORITATIVE))
|
||||||
|
return 0;
|
||||||
|
message = _("wrong server-ID");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1142,7 +1189,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
else if (!lease)
|
else if (!lease)
|
||||||
{
|
{
|
||||||
if ((lease = lease_allocate(mess->yiaddr)))
|
if ((lease = lease_allocate4(mess->yiaddr)))
|
||||||
do_classes = 1;
|
do_classes = 1;
|
||||||
else
|
else
|
||||||
message = _("no leases left");
|
message = _("no leases left");
|
||||||
@@ -1173,9 +1220,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
if (context->netid.net)
|
if (context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if( &context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, mess);
|
||||||
|
|
||||||
#ifdef HAVE_SCRIPT
|
#ifdef HAVE_SCRIPT
|
||||||
if (do_classes && daemon->lease_change_command)
|
if (do_classes && daemon->lease_change_command)
|
||||||
@@ -1278,10 +1326,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
option_put(mess, end, OPTION_T2, 4, ((time/8)*7) - fuzz);
|
||||||
}
|
}
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->yiaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
|
|
||||||
case DHCPINFORM:
|
case DHCPINFORM:
|
||||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
@@ -1304,15 +1352,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
|
|
||||||
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
if (!hostname && (hostname = host_from_dns(mess->ciaddr)))
|
||||||
domain = get_domain(mess->ciaddr);
|
domain = get_domain(mess->ciaddr);
|
||||||
|
|
||||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
|
||||||
|
|
||||||
if (context && context->netid.net)
|
if (context && context->netid.net)
|
||||||
{
|
{
|
||||||
context->netid.next = netid;
|
context->netid.next = netid;
|
||||||
netid = &context->netid;
|
tagif_netid = run_tag_if( &context->netid);
|
||||||
tagif_netid = run_tag_if(netid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_tags(tagif_netid, mess);
|
||||||
|
|
||||||
|
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||||
|
|
||||||
if (lease)
|
if (lease)
|
||||||
{
|
{
|
||||||
@@ -1337,10 +1386,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
do_options(context, mess, end, req_options, hostname, get_domain(mess->ciaddr),
|
||||||
domain, tagif_netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len);
|
domain, netid, subnet_addr, fqdn_flags, borken_opt, pxearch, uuid, vendor_class_len, now);
|
||||||
|
|
||||||
*is_inform = 1; /* handle reply differently */
|
*is_inform = 1; /* handle reply differently */
|
||||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
return dhcp_packet_size(mess, agent_id, real_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1432,7 +1481,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
|||||||
{
|
{
|
||||||
if (override.s_addr != 0)
|
if (override.s_addr != 0)
|
||||||
return override;
|
return override;
|
||||||
else if (context)
|
else if (context && context->local.s_addr != 0)
|
||||||
return context->local;
|
return context->local;
|
||||||
else
|
else
|
||||||
return fallback;
|
return fallback;
|
||||||
@@ -1672,30 +1721,16 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
|
||||||
unsigned char *agent_id, unsigned char *real_end)
|
|
||||||
{
|
{
|
||||||
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
|
||||||
unsigned char *overload;
|
|
||||||
size_t ret;
|
|
||||||
struct dhcp_netid_list *id_list;
|
|
||||||
struct dhcp_netid *n;
|
|
||||||
|
|
||||||
/* move agent_id back down to the end of the packet */
|
|
||||||
if (agent_id)
|
|
||||||
{
|
|
||||||
memmove(p, agent_id, real_end - agent_id);
|
|
||||||
p += real_end - agent_id;
|
|
||||||
memset(p, 0, real_end - p); /* in case of overlap */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We do logging too */
|
|
||||||
if (netid && option_bool(OPT_LOG_OPTS))
|
if (netid && option_bool(OPT_LOG_OPTS))
|
||||||
{
|
{
|
||||||
char *s = daemon->namebuff;
|
char *s = daemon->namebuff;
|
||||||
for (*s = 0; netid; netid = netid->next)
|
for (*s = 0; netid; netid = netid->next)
|
||||||
{
|
{
|
||||||
/* kill dupes. */
|
/* kill dupes. */
|
||||||
|
struct dhcp_netid *n;
|
||||||
|
|
||||||
for (n = netid->next; n; n = n->next)
|
for (n = netid->next; n; n = n->next)
|
||||||
if (strcmp(netid->net, n->net) == 0)
|
if (strcmp(netid->net, n->net) == 0)
|
||||||
break;
|
break;
|
||||||
@@ -1709,7 +1744,22 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
|||||||
}
|
}
|
||||||
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
|
my_syslog(MS_DHCP | LOG_INFO, _("%u tags: %s"), ntohl(mess->xid), s);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end)
|
||||||
|
{
|
||||||
|
unsigned char *p = dhcp_skip_opts(&mess->options[0] + sizeof(u32));
|
||||||
|
unsigned char *overload;
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
/* move agent_id back down to the end of the packet */
|
||||||
|
if (agent_id)
|
||||||
|
{
|
||||||
|
memmove(p, agent_id, real_end - agent_id);
|
||||||
|
p += real_end - agent_id;
|
||||||
|
memset(p, 0, real_end - p); /* in case of overlap */
|
||||||
|
}
|
||||||
|
|
||||||
/* add END options to the regions. */
|
/* add END options to the regions. */
|
||||||
overload = find_overload(mess);
|
overload = find_overload(mess);
|
||||||
|
|
||||||
@@ -1734,12 +1784,6 @@ static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *neti
|
|||||||
|
|
||||||
*p++ = OPTION_END;
|
*p++ = OPTION_END;
|
||||||
|
|
||||||
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
|
||||||
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
|
||||||
break;
|
|
||||||
if (id_list)
|
|
||||||
mess->flags |= htons(0x8000); /* force broadcast */
|
|
||||||
|
|
||||||
if (option_bool(OPT_LOG_OPTS))
|
if (option_bool(OPT_LOG_OPTS))
|
||||||
{
|
{
|
||||||
if (mess->siaddr.s_addr != 0)
|
if (mess->siaddr.s_addr != 0)
|
||||||
@@ -1889,20 +1933,14 @@ static int in_list(unsigned char *list, int opt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
static struct dhcp_opt *option_find2(int opt)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *tmp;
|
struct dhcp_opt *opts;
|
||||||
for (tmp = opts; tmp; tmp = tmp->next)
|
|
||||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
for (opts = daemon->dhcp_opts; opts; opts = opts->next)
|
||||||
if (match_netid(tmp->netid, netid, 0))
|
if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
|
||||||
return tmp;
|
return opts;
|
||||||
|
|
||||||
/* No match, look for one without a netid */
|
|
||||||
for (tmp = opts; tmp; tmp = tmp->next)
|
|
||||||
if (tmp->opt == opt && !(tmp->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)))
|
|
||||||
if (match_netid(tmp->netid, netid, 1))
|
|
||||||
return tmp;
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2157,7 +2195,8 @@ static void do_options(struct dhcp_context *context,
|
|||||||
unsigned char fqdn_flags,
|
unsigned char fqdn_flags,
|
||||||
int null_term, int pxe_arch,
|
int null_term, int pxe_arch,
|
||||||
unsigned char *uuid,
|
unsigned char *uuid,
|
||||||
int vendor_class_len)
|
int vendor_class_len,
|
||||||
|
time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
struct dhcp_opt *opt, *config_opts = daemon->dhcp_opts;
|
||||||
struct dhcp_boot *boot;
|
struct dhcp_boot *boot;
|
||||||
@@ -2166,7 +2205,53 @@ static void do_options(struct dhcp_context *context,
|
|||||||
unsigned char f0 = 0, s0 = 0;
|
unsigned char f0 = 0, s0 = 0;
|
||||||
int done_file = 0, done_server = 0;
|
int done_file = 0, done_server = 0;
|
||||||
int done_vendor_class = 0;
|
int done_vendor_class = 0;
|
||||||
|
struct dhcp_netid *tagif;
|
||||||
|
struct dhcp_netid_list *id_list;
|
||||||
|
|
||||||
|
/* flag options which are valid with the current tag set (sans context tags) */
|
||||||
|
tagif = run_tag_if(netid);
|
||||||
|
for (opt = config_opts; opt; opt = opt->next)
|
||||||
|
{
|
||||||
|
opt->flags &= ~DHOPT_TAGOK;
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925)) &&
|
||||||
|
match_netid(opt->netid, tagif, 0))
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now flag options which are valid, including the context tags,
|
||||||
|
otherwise valid options are inhibited if we found a higher priotity one above */
|
||||||
|
if (context && context->netid.net)
|
||||||
|
{
|
||||||
|
context->netid.next = netid;
|
||||||
|
tagif = run_tag_if(&context->netid);
|
||||||
|
|
||||||
|
for (opt = config_opts; opt; opt = opt->next)
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) &&
|
||||||
|
match_netid(opt->netid, tagif, 0))
|
||||||
|
{
|
||||||
|
struct dhcp_opt *tmp;
|
||||||
|
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->opt == opt->opt && opt->netid && (tmp->flags & DHOPT_TAGOK))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now flag untagged options which are not overridden by tagged ones */
|
||||||
|
for (opt = config_opts; opt; opt = opt->next)
|
||||||
|
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
|
||||||
|
{
|
||||||
|
struct dhcp_opt *tmp;
|
||||||
|
for (tmp = config_opts; tmp; tmp = tmp->next)
|
||||||
|
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
opt->flags |= DHOPT_TAGOK;
|
||||||
|
else if (!tmp->netid)
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
|
||||||
|
}
|
||||||
|
|
||||||
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
if (config_domain && (!domain || !hostname_isequal(domain, config_domain)))
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
||||||
|
|
||||||
@@ -2191,6 +2276,12 @@ static void do_options(struct dhcp_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (id_list = daemon->force_broadcast; id_list; id_list = id_list->next)
|
||||||
|
if ((!id_list->list) || match_netid(id_list->list, netid, 0))
|
||||||
|
break;
|
||||||
|
if (id_list)
|
||||||
|
mess->flags |= htons(0x8000); /* force broadcast */
|
||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
mess->siaddr = context->local;
|
mess->siaddr = context->local;
|
||||||
|
|
||||||
@@ -2200,7 +2291,7 @@ static void do_options(struct dhcp_context *context,
|
|||||||
provide an manual option to disable it.
|
provide an manual option to disable it.
|
||||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||||
names, so we always send those. */
|
names, so we always send those. */
|
||||||
if ((boot = find_boot(netid)))
|
if ((boot = find_boot(tagif)))
|
||||||
{
|
{
|
||||||
if (boot->sname)
|
if (boot->sname)
|
||||||
{
|
{
|
||||||
@@ -2222,8 +2313,10 @@ static void do_options(struct dhcp_context *context,
|
|||||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boot->next_server.s_addr)
|
if (boot->next_server.s_addr)
|
||||||
mess->siaddr = boot->next_server;
|
mess->siaddr = boot->next_server;
|
||||||
|
else if (boot->tftp_sname)
|
||||||
|
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* Use the values of the relevant options if no dhcp-boot given and
|
/* Use the values of the relevant options if no dhcp-boot given and
|
||||||
@@ -2232,20 +2325,20 @@ static void do_options(struct dhcp_context *context,
|
|||||||
dhcp-optsfile. */
|
dhcp-optsfile. */
|
||||||
{
|
{
|
||||||
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
|
||||||
(opt = option_find2(netid, config_opts, OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
(opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
|
||||||
{
|
{
|
||||||
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
|
||||||
done_file = 1;
|
done_file = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
|
||||||
(opt = option_find2(netid, config_opts, OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
(opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
|
||||||
{
|
{
|
||||||
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
|
||||||
done_server = 1;
|
done_server = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opt = option_find2(netid, config_opts, OPTION_END)))
|
if ((opt = option_find2(OPTION_END)))
|
||||||
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
|
mess->siaddr.s_addr = ((struct in_addr *)opt->val)->s_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2273,36 +2366,36 @@ static void do_options(struct dhcp_context *context,
|
|||||||
/* replies to DHCPINFORM may not have a valid context */
|
/* replies to DHCPINFORM may not have a valid context */
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
if (!option_find2(netid, config_opts, OPTION_NETMASK))
|
if (!option_find2(OPTION_NETMASK))
|
||||||
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
option_put(mess, end, OPTION_NETMASK, INADDRSZ, ntohl(context->netmask.s_addr));
|
||||||
|
|
||||||
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
/* May not have a "guessed" broadcast address if we got no packets via a relay
|
||||||
from this net yet (ie just unicast renewals after a restart */
|
from this net yet (ie just unicast renewals after a restart */
|
||||||
if (context->broadcast.s_addr &&
|
if (context->broadcast.s_addr &&
|
||||||
!option_find2(netid, config_opts, OPTION_BROADCAST))
|
!option_find2(OPTION_BROADCAST))
|
||||||
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
option_put(mess, end, OPTION_BROADCAST, INADDRSZ, ntohl(context->broadcast.s_addr));
|
||||||
|
|
||||||
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
/* Same comments as broadcast apply, and also may not be able to get a sensible
|
||||||
default when using subnet select. User must configure by steam in that case. */
|
default when using subnet select. User must configure by steam in that case. */
|
||||||
if (context->router.s_addr &&
|
if (context->router.s_addr &&
|
||||||
in_list(req_options, OPTION_ROUTER) &&
|
in_list(req_options, OPTION_ROUTER) &&
|
||||||
!option_find2(netid, config_opts, OPTION_ROUTER))
|
!option_find2(OPTION_ROUTER))
|
||||||
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
option_put(mess, end, OPTION_ROUTER, INADDRSZ, ntohl(context->router.s_addr));
|
||||||
|
|
||||||
if (in_list(req_options, OPTION_DNSSERVER) &&
|
if (in_list(req_options, OPTION_DNSSERVER) &&
|
||||||
!option_find2(netid, config_opts, OPTION_DNSSERVER))
|
!option_find2(OPTION_DNSSERVER))
|
||||||
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
option_put(mess, end, OPTION_DNSSERVER, INADDRSZ, ntohl(context->local.s_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
|
if (domain && in_list(req_options, OPTION_DOMAINNAME) &&
|
||||||
!option_find2(netid, config_opts, OPTION_DOMAINNAME))
|
!option_find2(OPTION_DOMAINNAME))
|
||||||
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
|
option_put_string(mess, end, OPTION_DOMAINNAME, domain, null_term);
|
||||||
|
|
||||||
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
||||||
if (hostname)
|
if (hostname)
|
||||||
{
|
{
|
||||||
if (in_list(req_options, OPTION_HOSTNAME) &&
|
if (in_list(req_options, OPTION_HOSTNAME) &&
|
||||||
!option_find2(netid, config_opts, OPTION_HOSTNAME))
|
!option_find2(OPTION_HOSTNAME))
|
||||||
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
option_put_string(mess, end, OPTION_HOSTNAME, hostname, null_term);
|
||||||
|
|
||||||
if (fqdn_flags != 0)
|
if (fqdn_flags != 0)
|
||||||
@@ -2351,6 +2444,10 @@ static void do_options(struct dhcp_context *context,
|
|||||||
{
|
{
|
||||||
int optno = opt->opt;
|
int optno = opt->opt;
|
||||||
|
|
||||||
|
/* netids match and not encapsulated? */
|
||||||
|
if (!(opt->flags & DHOPT_TAGOK))
|
||||||
|
continue;
|
||||||
|
|
||||||
/* was it asked for, or are we sending it anyway? */
|
/* was it asked for, or are we sending it anyway? */
|
||||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||||
continue;
|
continue;
|
||||||
@@ -2369,10 +2466,6 @@ static void do_options(struct dhcp_context *context,
|
|||||||
if (optno == OPTION_FILENAME && done_file)
|
if (optno == OPTION_FILENAME && done_file)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* netids match and not encapsulated? */
|
|
||||||
if (opt != option_find2(netid, config_opts, optno))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* For the options we have default values on
|
/* For the options we have default values on
|
||||||
dhc-option=<optionno> means "don't include this option"
|
dhc-option=<optionno> means "don't include this option"
|
||||||
not "include a zero-length option" */
|
not "include a zero-length option" */
|
||||||
@@ -2439,7 +2532,7 @@ static void do_options(struct dhcp_context *context,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
o->flags |= DHOPT_ENCAP_DONE;
|
o->flags |= DHOPT_ENCAP_DONE;
|
||||||
if (match_netid(o->netid, netid, 1) &&
|
if (match_netid(o->netid, tagif, 1) &&
|
||||||
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
((o->flags & DHOPT_FORCE) || in_list(req_options, outer)))
|
||||||
{
|
{
|
||||||
o->flags |= DHOPT_ENCAP_MATCH;
|
o->flags |= DHOPT_ENCAP_MATCH;
|
||||||
@@ -2473,12 +2566,12 @@ static void do_options(struct dhcp_context *context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
force_encap = prune_vendor_opts(netid);
|
force_encap = prune_vendor_opts(tagif);
|
||||||
|
|
||||||
if (context && pxe_arch != -1)
|
if (context && pxe_arch != -1)
|
||||||
{
|
{
|
||||||
pxe_misc(mess, end, uuid);
|
pxe_misc(mess, end, uuid);
|
||||||
config_opts = pxe_opts(pxe_arch, netid, context->local);
|
config_opts = pxe_opts(pxe_arch, tagif, context->local);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
if ((force_encap || in_list(req_options, OPTION_VENDOR_CLASS_OPT)) &&
|
||||||
|
|||||||
+298
@@ -0,0 +1,298 @@
|
|||||||
|
/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; version 2 dated June, 1991, or
|
||||||
|
(at your option) version 3 dated 29 June, 2007.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_DHCP6
|
||||||
|
|
||||||
|
static size_t outpacket_counter;
|
||||||
|
|
||||||
|
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||||
|
size_t maclen, void *parm);
|
||||||
|
|
||||||
|
void make_duid(time_t now)
|
||||||
|
{
|
||||||
|
iface_enumerate(AF_LOCAL, &now, make_duid1);
|
||||||
|
|
||||||
|
if (!daemon->duid)
|
||||||
|
die("Cannot create DHCPv6 server DUID", NULL, EC_MISC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int make_duid1(unsigned short type, unsigned int flags, char *mac,
|
||||||
|
size_t maclen, void *parm)
|
||||||
|
{
|
||||||
|
/* create DUID as specified in RFC3315. We use the MAC of the
|
||||||
|
first interface we find that isn't loopback or P-to-P */
|
||||||
|
|
||||||
|
unsigned char *p;
|
||||||
|
|
||||||
|
if (flags & (IFF_LOOPBACK | IFF_POINTOPOINT))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
daemon->duid = p = safe_malloc(maclen + 8);
|
||||||
|
daemon->duid_len = maclen + 8;
|
||||||
|
PUTSHORT(1, p); /* DUID_LLT */
|
||||||
|
PUTSHORT(type, p); /* address type */
|
||||||
|
PUTLONG(*((time_t *)parm), p); /* time */
|
||||||
|
memcpy(p, mac, maclen);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
|
||||||
|
{
|
||||||
|
u16 opt, opt_len;
|
||||||
|
void *start;
|
||||||
|
|
||||||
|
if (!opts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (end - opts < 4)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = opts;
|
||||||
|
GETSHORT(opt, opts);
|
||||||
|
GETSHORT(opt_len, opts);
|
||||||
|
|
||||||
|
if (opt_len > (end - opts))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (opt == search && (opt_len >= minsize))
|
||||||
|
return start;
|
||||||
|
|
||||||
|
opts += opt_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *opt6_next(void *opts, void *end)
|
||||||
|
{
|
||||||
|
u16 opt_len;
|
||||||
|
|
||||||
|
if (end - opts < 4)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
opts += 2;
|
||||||
|
GETSHORT(opt_len, opts);
|
||||||
|
|
||||||
|
if (opt_len >= (end - opts))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return opts + opt_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define opt6_len(opt) ((int)(((unsigned short *)(opt))[1]))
|
||||||
|
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4u+(unsigned int)(i)]))
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
|
||||||
|
{
|
||||||
|
/* this worries about unaligned data and byte order */
|
||||||
|
unsigned int ret = 0;
|
||||||
|
int i;
|
||||||
|
unsigned char *p = opt6_ptr(opt, offset);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
ret = (ret << 8) | *p++;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
daemon->outpacket_counter = 4; message type and ID
|
||||||
|
|
||||||
|
elapsed time:
|
||||||
|
int o = new_opt(OPTION_ELAPSED_TIME);
|
||||||
|
put_opt_short(o, 100)
|
||||||
|
finalise_opt(o);
|
||||||
|
|
||||||
|
IA_NA
|
||||||
|
|
||||||
|
int o = new_opt(OPTION_IA_NA);
|
||||||
|
put_opt_long(o, IAID);
|
||||||
|
put_opt_long(o, T1);
|
||||||
|
put_opt_long(0, T2);
|
||||||
|
int o1 = new_opt(OPTION_IAADDR);
|
||||||
|
put_opt(o1, &addr, sizeof(addr));
|
||||||
|
put_opt_long(o1, preferred_lifetime);
|
||||||
|
put_opt_long(o1, valid_lifetime);
|
||||||
|
finalise_opt(o1);
|
||||||
|
finalise_opt(o);
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void end_opt6(int container)
|
||||||
|
{
|
||||||
|
void *p = daemon->outpacket.iov_base + container + 2;
|
||||||
|
u16 len = outpacket_counter - container - 4 ;
|
||||||
|
|
||||||
|
PUTSHORT(len, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *expand(size_t headroom)
|
||||||
|
{
|
||||||
|
void *ret;
|
||||||
|
|
||||||
|
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
|
||||||
|
{
|
||||||
|
ret = daemon->outpacket.iov_base + outpacket_counter;
|
||||||
|
outpacket_counter += headroom;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int new_opt6(int opt)
|
||||||
|
{
|
||||||
|
int ret = outpacket_counter;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(4)))
|
||||||
|
{
|
||||||
|
PUTSHORT(opt, p);
|
||||||
|
PUTSHORT(0, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void *put_opt6(void *data, size_t len)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (data && (p = expand(len)))
|
||||||
|
memcpy(p, data, len);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_long(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (( p = expand(4)))
|
||||||
|
PUTLONG(p, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_short(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(2)))
|
||||||
|
PUTSHORT(val, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_opt6_byte(unsigned int val)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if ((p = expand(1)))
|
||||||
|
*((unsigned char *)p) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dhcp6_reply(struct dhcp_context *context, size_t sz)
|
||||||
|
{
|
||||||
|
void *packet_options = ((void *)daemon->dhcp_packet.iov_base) + 4;
|
||||||
|
void *end = ((void *)daemon->dhcp_packet.iov_base) + sz;
|
||||||
|
void *na_option, *na_end;
|
||||||
|
void *opt, *p;
|
||||||
|
int o;
|
||||||
|
|
||||||
|
outpacket_counter = 4; /* skip message type and transaction-id */
|
||||||
|
|
||||||
|
if (!(opt = opt6_find(packet_options, end, OPTION6_CLIENT_ID, 1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
o = new_opt6(OPTION6_CLIENT_ID);
|
||||||
|
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
|
||||||
|
end_opt6(o);
|
||||||
|
|
||||||
|
o = new_opt6(OPTION6_SERVER_ID);
|
||||||
|
put_opt6(daemon->duid, daemon->duid_len);
|
||||||
|
end_opt6(o);
|
||||||
|
|
||||||
|
if ((opt = opt6_find(packet_options, end, OPTION6_IA_NA, 12)))
|
||||||
|
{
|
||||||
|
while (opt = opt6_find(opt, end, OPTION6_IA_NA, 12))
|
||||||
|
{
|
||||||
|
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||||
|
void *ia_option = opt6_find(opt6_ptr(opt, 12), ia_end, OPTION6_IAADDR, 24);
|
||||||
|
|
||||||
|
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||||
|
unsigned int t1 = opt6_uint(opt, 4, 4);
|
||||||
|
unsigned int t2 = opt6_uint(opt, 8, 4);
|
||||||
|
|
||||||
|
|
||||||
|
if (ia_option)
|
||||||
|
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||||
|
{
|
||||||
|
/* do address option */
|
||||||
|
|
||||||
|
ia_option = opt6_next(ia_option, ia_end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no preferred address call address allocate */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = opt6_next(opt, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((opt = opt6_find(packet_options, end, OPTION6_IA_TA, 4)))
|
||||||
|
while (opt = opt6_find(opt, end, OPTION6_IA_TA, 4))
|
||||||
|
{
|
||||||
|
void *ia_end = opt6_ptr(opt, opt6_len(opt));
|
||||||
|
void *ia_option = opt6_find(opt6_ptr(opt, 4), ia_end, OPTION6_IAADDR, 24);
|
||||||
|
|
||||||
|
unsigned int iaid = opt6_uint(opt, 0, 4);
|
||||||
|
|
||||||
|
if (ia_option)
|
||||||
|
while ((ia_option = ia_option, ia_end, OPTION6_IAADDR, 24))
|
||||||
|
{
|
||||||
|
/* do address option */
|
||||||
|
|
||||||
|
ia_option = opt6_next(ia_option, ia_end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* no preferred address */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
opt = opt6_next(opt, end);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return; /* no IA_NA and no IA_TA */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+29
-28
@@ -57,7 +57,6 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
int mtuflag = IP_PMTUDISC_DONT;
|
int mtuflag = IP_PMTUDISC_DONT;
|
||||||
#endif
|
#endif
|
||||||
char namebuff[IF_NAMESIZE];
|
char namebuff[IF_NAMESIZE];
|
||||||
char pretty_addr[ADDRSTRLEN];
|
|
||||||
char *name;
|
char *name;
|
||||||
char *prefix = daemon->tftp_prefix;
|
char *prefix = daemon->tftp_prefix;
|
||||||
struct tftp_prefix *pref;
|
struct tftp_prefix *pref;
|
||||||
@@ -114,7 +113,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
#if defined(HAVE_LINUX_NETWORK)
|
#if defined(HAVE_LINUX_NETWORK)
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -163,7 +162,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
unsigned char *c;
|
unsigned char *c;
|
||||||
@@ -184,10 +183,10 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, &if_index);
|
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, &if_index);
|
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name);
|
||||||
|
|
||||||
/* wierd TFTP service override */
|
/* wierd TFTP service override */
|
||||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||||
@@ -222,17 +221,22 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
if (strcmp(ir->interface, name) == 0)
|
if (strcmp(ir->interface, name) == 0)
|
||||||
special = 1;
|
special = 1;
|
||||||
|
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
|
||||||
addr.sa.sa_len = sa_len(&addr);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
addr.in.sin_port = htons(port);
|
{
|
||||||
|
addr.in.sin_port = htons(port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in.sin_len = sizeof(addr.in);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
addr.in6.sin6_port = htons(port);
|
addr.in6.sin6_port = htons(port);
|
||||||
addr.in6.sin6_flowinfo = 0;
|
addr.in6.sin6_flowinfo = 0;
|
||||||
|
addr.in6.sin6_scope_id = 0;
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in6.sin6_len = sizeof(addr.in6);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -255,14 +259,14 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||||
transfer->netascii = transfer->carrylf = 0;
|
transfer->netascii = transfer->carrylf = 0;
|
||||||
|
|
||||||
prettyprint_addr(&peer, pretty_addr);
|
prettyprint_addr(&peer, daemon->addrbuff);
|
||||||
|
|
||||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (bind(transfer->sockfd, &addr.sa, sizeof(addr)) == -1 ||
|
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
||||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
setsockopt(transfer->sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||||
#endif
|
#endif
|
||||||
!fix_fd(transfer->sockfd))
|
!fix_fd(transfer->sockfd))
|
||||||
{
|
{
|
||||||
@@ -293,7 +297,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
!(filename = next(&p, end)) ||
|
!(filename = next(&p, end)) ||
|
||||||
!(mode = next(&p, end)) ||
|
!(mode = next(&p, end)) ||
|
||||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), pretty_addr);
|
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (strcasecmp(mode, "netascii") == 0)
|
if (strcasecmp(mode, "netascii") == 0)
|
||||||
@@ -343,7 +347,7 @@ void tftp_request(struct listener *listen, time_t now)
|
|||||||
size_t oldlen = strlen(daemon->namebuff);
|
size_t oldlen = strlen(daemon->namebuff);
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
strncat(daemon->namebuff, pretty_addr, (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, daemon->addrbuff, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||||
|
|
||||||
/* remove unique-directory if it doesn't exist */
|
/* remove unique-directory if it doesn't exist */
|
||||||
@@ -473,7 +477,6 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
{
|
{
|
||||||
struct tftp_transfer *transfer, *tmp, **up;
|
struct tftp_transfer *transfer, *tmp, **up;
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
char pretty_addr[ADDRSTRLEN];
|
|
||||||
|
|
||||||
struct ack {
|
struct ack {
|
||||||
unsigned short op, block;
|
unsigned short op, block;
|
||||||
@@ -489,7 +492,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
/* we overwrote the buffer... */
|
/* we overwrote the buffer... */
|
||||||
daemon->srv_save = NULL;
|
daemon->srv_save = NULL;
|
||||||
|
|
||||||
prettyprint_addr(&transfer->peer, pretty_addr);
|
prettyprint_addr(&transfer->peer, daemon->addrbuff);
|
||||||
|
|
||||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||||
{
|
{
|
||||||
@@ -521,7 +524,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
|
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||||
(int)ntohs(mess->block), err,
|
(int)ntohs(mess->block), err,
|
||||||
pretty_addr);
|
daemon->addrbuff);
|
||||||
|
|
||||||
/* Got err, ensure we take abort */
|
/* Got err, ensure we take abort */
|
||||||
transfer->timeout = now;
|
transfer->timeout = now;
|
||||||
@@ -552,7 +555,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (len != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||||
transfer->file->filename, pretty_addr);
|
transfer->file->filename, daemon->addrbuff);
|
||||||
len = 0;
|
len = 0;
|
||||||
endcon = 1;
|
endcon = 1;
|
||||||
}
|
}
|
||||||
@@ -565,7 +568,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
|||||||
if (endcon || len == 0)
|
if (endcon || len == 0)
|
||||||
{
|
{
|
||||||
if (!endcon)
|
if (!endcon)
|
||||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, pretty_addr);
|
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, daemon->addrbuff);
|
||||||
/* unlink */
|
/* unlink */
|
||||||
*up = tmp;
|
*up = tmp;
|
||||||
free_transfer(transfer);
|
free_transfer(transfer);
|
||||||
@@ -685,15 +688,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
|||||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||||
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
||||||
{
|
{
|
||||||
if (size == transfer->blocksize)
|
transfer->expansion++;
|
||||||
{
|
|
||||||
transfer->expansion++;
|
if (size != transfer->blocksize)
|
||||||
if (i == size - 1)
|
|
||||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
size++; /* room in this block */
|
size++; /* room in this block */
|
||||||
|
else if (i == size - 1)
|
||||||
|
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||||
|
|
||||||
/* make space and insert CR */
|
/* make space and insert CR */
|
||||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||||
mess->data[i] = '\r';
|
mess->data[i] = '\r';
|
||||||
|
|||||||
+28
-1
@@ -320,6 +320,25 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int is_same_net6(struct in6_addr *a, struct in6_addr *b, int prefixlen)
|
||||||
|
{
|
||||||
|
int pfbytes = prefixlen >> 3;
|
||||||
|
int pfbits = prefixlen & 7;
|
||||||
|
|
||||||
|
if (memcmp(&a->s6_addr, &b->s6_addr, pfbytes) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (pfbits == 0 ||
|
||||||
|
(a->s6_addr[pfbytes] >> (8 - pfbits) != b->s6_addr[pfbytes] >> (8 - pfbits)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* returns port number from address */
|
/* returns port number from address */
|
||||||
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||||
{
|
{
|
||||||
@@ -333,7 +352,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
|
|||||||
}
|
}
|
||||||
else if (addr->sa.sa_family == AF_INET6)
|
else if (addr->sa.sa_family == AF_INET6)
|
||||||
{
|
{
|
||||||
|
char name[IF_NAMESIZE];
|
||||||
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &addr->in6.sin6_addr, buf, ADDRSTRLEN);
|
||||||
|
if (addr->in6.sin6_scope_id != 0 &&
|
||||||
|
if_indextoname(addr->in6.sin6_scope_id, name) &&
|
||||||
|
strlen(buf) + strlen(name) + 2 <= ADDRSTRLEN)
|
||||||
|
{
|
||||||
|
strcat(buf, "%");
|
||||||
|
strcat(buf, name);
|
||||||
|
}
|
||||||
port = ntohs(addr->in6.sin6_port);
|
port = ntohs(addr->in6.sin6_port);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -475,7 +502,7 @@ void bump_maxfd(int fd, int *max)
|
|||||||
int retry_send(void)
|
int retry_send(void)
|
||||||
{
|
{
|
||||||
struct timespec waiter;
|
struct timespec waiter;
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
{
|
{
|
||||||
waiter.tv_sec = 0;
|
waiter.tv_sec = 0;
|
||||||
waiter.tv_nsec = 10000;
|
waiter.tv_nsec = 10000;
|
||||||
|
|||||||
Reference in new issue
Block a user