Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7de060b08d | ||
|
|
572b41eb50 | ||
|
|
28866e9567 | ||
|
|
c52e189734 |
3
Android.mk
Normal file
3
Android.mk
Normal file
@@ -0,0 +1,3 @@
|
||||
ifneq ($(TARGET_SIMULATOR),true)
|
||||
include $(call all-subdir-makefiles)
|
||||
endif
|
||||
258
CHANGELOG
258
CHANGELOG
@@ -1,3 +1,261 @@
|
||||
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
|
||||
Add patches to allow build under Android.
|
||||
|
||||
Provide our own header for the DNS protocol, rather than
|
||||
relying on arpa/nameser.h. This has proved more or less
|
||||
defective over the years and the final straw is that it's
|
||||
effectively empty on Android.
|
||||
|
||||
Fix regression in 2.56 which caused hex constants in
|
||||
configuration to be rejected if they contain the '*'
|
||||
wildcard.
|
||||
|
||||
Correct wrong casts of arguments to ctype.h functions,
|
||||
isdigit(), isxdigit() etc. Thanks to Matthias Andree for
|
||||
spotting this.
|
||||
|
||||
Allow build with IDN support independently from i18n.
|
||||
IDN support continues to be included automatically
|
||||
when i18n is included.
|
||||
'make COPTS=-DHAVE_IDN' is the magic incantation.
|
||||
|
||||
Modify check on extraneous command line junk (added in
|
||||
2.56) so that it doesn't complain about extra _empty_
|
||||
arguments. Otherwise this breaks libvirt.
|
||||
|
||||
|
||||
version 2.56
|
||||
Add a patch to allow dnsmasq to get interface names right in a
|
||||
Solaris zone. Thanks to Dj Padzensky for this.
|
||||
|
||||
Improve data-type parsing heuristics so that
|
||||
--dhcp-option=option:domain-search,.
|
||||
treats the value as a string and not an IP address.
|
||||
Thanks to Clemens Fischer for spotting that.
|
||||
|
||||
Add IPv6 support to the TFTP server. Many thanks to Jan
|
||||
'RedBully' Seiffert for the patches.
|
||||
|
||||
Log DNS queries at level LOG_INFO, rather then
|
||||
LOG_DEBUG. This makes things consistent with DHCP
|
||||
logging. Thanks to Adam Pribyl for spotting the problem.
|
||||
|
||||
Ensure that dnsmasq terminates cleanly when using
|
||||
--syslog-async even if it cannot make a connection to the
|
||||
syslogd.
|
||||
|
||||
Add --add-mac option. This is to support currently
|
||||
experimental DNS filtering facilities. Thanks to Benjamin
|
||||
Petrin for the orignal patch.
|
||||
|
||||
Fix bug which meant that tags were ignored in dhcp-range
|
||||
configuration specifying PXE-proxy service. Thanks to
|
||||
Cristiano Cumer for spotting this.
|
||||
|
||||
Raise an error if there is extra junk, not part of an
|
||||
option, on the command line.
|
||||
|
||||
Flag a couple of log messages in cache.c as coming from
|
||||
the DHCP subsystem. Thanks to Olaf Westrik for the patch.
|
||||
|
||||
Omit timestamps from logs when a) logging to stderr and
|
||||
b) --keep-in-forground is set. The logging facility on the
|
||||
other end of stderr can be assumned to supply them. Thanks
|
||||
to John Hallam for the patch.
|
||||
|
||||
Don't complain about strings longer than 255 characters in
|
||||
--txt-record, just split the long strings into 255
|
||||
character chunks instead.
|
||||
|
||||
Fix crash on double-free. This bug can only happen when
|
||||
dhcp-script is in use and then only in rare circumstances
|
||||
triggered by high DHCP transaction rate and a slow
|
||||
script. Thanks to Ferenc Wagner for finding the problem.
|
||||
|
||||
Only log that a file has been sent by TFTP after the
|
||||
transfer has completed succesfully.
|
||||
|
||||
A good suggestion from Ferenc Wagner: extend
|
||||
the --domain option to allow this sort of thing:
|
||||
--domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
which automatically creates
|
||||
--local=/thekelleys.org.uk/
|
||||
--local=/0.168.192.in-addr.arpa/
|
||||
|
||||
Tighten up syntax checking of hex contants in the config
|
||||
file. Thanks to Fred Damen for spotting this.
|
||||
|
||||
Add dnsmasq logo/icon, contributed by Justin Swift. Many
|
||||
thanks for that.
|
||||
|
||||
Never cache DNS replies which have the 'cd' bit set, or
|
||||
which result from queries forwarded with the 'cd' bit
|
||||
set. The 'cd' bit instructs a DNSSEC validating server
|
||||
upstream to ignore signature failures and return replies
|
||||
anyway. Without this change it's possible to pollute the
|
||||
dnsmasq cache with bad data by making a query with the
|
||||
'cd' bit set and subsequent queries would return this data
|
||||
without its being marked as suspect. Thanks to Anders
|
||||
Kaseorg for pointing out this problem.
|
||||
|
||||
Add --proxy-dnssec flag, for compliance with RFC
|
||||
4035. Dnsmasq will now clear the 'ad' bit in answers returned
|
||||
from upstream validating nameservers unless this option is
|
||||
set.
|
||||
|
||||
Allow a filename of "-" for --conf-file to read
|
||||
stdin. Suggestion from Timothy Redaelli.
|
||||
|
||||
Rotate the order of SRV records in replies, to provide
|
||||
round-robin load balancing when all the priorities are
|
||||
equal. Thanks to Peter McKinney for the suggestion.
|
||||
|
||||
Edit
|
||||
contrib/MacOSX-launchd/uk.org.thekelleys.dnsmasq.plist
|
||||
so that it doesn't log all queries to a file by
|
||||
default. Thanks again to Peter McKinney.
|
||||
|
||||
By default, setting an IPv4 address for a domain but not
|
||||
an IPv6 address causes dnsmasq to return
|
||||
an NODATA reply for IPv6 (or vice-versa). So
|
||||
--address=/google.com/1.2.3.4 stops IPv6 queries for
|
||||
*google.com from being forwarded. Make it possible to
|
||||
override this behaviour by defining the sematics if the
|
||||
same domain appears in both --server and --address.
|
||||
In that case, the --address has priority for the address
|
||||
family in which is appears, but the --server has priority
|
||||
of the address family which doesn't appear in --adddress
|
||||
So:
|
||||
--address=/google.com/1.2.3.4
|
||||
--server=/google.com/#
|
||||
will return 1.2.3.4 for IPv4 queries for *.google.com but
|
||||
forward IPv6 queries to the normal upstream nameserver.
|
||||
Similarly when setting an IPv6 address
|
||||
only this will allow forwarding of IPv4 queries. Thanks to
|
||||
William for pointing out the need for this.
|
||||
|
||||
Allow more than one --dhcp-optsfile and --dhcp-hostsfile
|
||||
and make them understand directories as arguments in the
|
||||
same way as --addn-hosts. Suggestion from John Hanks.
|
||||
|
||||
Ignore rebinding requests for leases we don't know
|
||||
about. Rebind is broadcast, so we might get to overhear a
|
||||
request meant for another DHCP server. NAKing this is
|
||||
wrong. Thanks to Brad D'Hondt for assistance with this.
|
||||
|
||||
Fix cosmetic bug which produced strange output when
|
||||
dumping cache statistics with some configurations. Thanks
|
||||
to Fedor Kozhevnikov for spotting this.
|
||||
|
||||
|
||||
version 2.55
|
||||
Fix crash when /etc/ethers is in use. Thanks to
|
||||
Gianluigi Tiesi for finding this.
|
||||
|
||||
Fix crash in netlink_multicast(). Thanks to Arno Wald for
|
||||
finding this one.
|
||||
|
||||
Allow the empty domain "." in dhcp domain-search (119)
|
||||
options.
|
||||
|
||||
|
||||
version 2.54
|
||||
There is no version 2.54 to avoid confusion with 2.53,
|
||||
which incorrectly identifies itself as 2.54.
|
||||
|
||||
|
||||
version 2.53
|
||||
Fix failure to compile on Debian/kFreeBSD. Thanks to
|
||||
Axel Beckert and Petr Salinger.
|
||||
|
||||
13
FAQ
13
FAQ
@@ -303,7 +303,7 @@ A: Yes, new releases of dnsmasq are always announced through
|
||||
|
||||
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.
|
||||
|
||||
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||
@@ -354,7 +354,7 @@ A: Yes, from version-2.21. The support is only available running under
|
||||
If a physical interface has more than one IP address or aliases
|
||||
with extra IP addresses, then any dhcp-ranges corresponding to
|
||||
these addresses can be used for address allocation. So if an
|
||||
interface has addresses 192.168.1.0/24 and 192.68.2.0/24 and there
|
||||
interface has addresses 192.168.1.0/24 and 192.168.2.0/24 and there
|
||||
are DHCP ranges 192.168.1.100-192.168.1.200 and
|
||||
192.168.2.100-192.168.2.200 then both ranges would be used for host
|
||||
connected to the physical interface. A more typical use might be to
|
||||
@@ -381,7 +381,7 @@ A: Probably the nameserver is an authoritative nameserver for a
|
||||
Q: Does the dnsmasq DHCP server probe addresses before allocating
|
||||
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
|
||||
assumes that the address is in use, and attempts to allocate an
|
||||
different address. The wait for a reply is between two and three
|
||||
@@ -413,10 +413,11 @@ A: Change your kernel configuration: either deselect CONFIG_SECURITY
|
||||
_or_ select CONFIG_SECURITY_CAPABILITIES. Alternatively, you can
|
||||
remove the need to set capabilities by running dnsmasq as root.
|
||||
|
||||
Q: Where can I get .rpms Suitable for Suse?
|
||||
|
||||
A: Dnsmasq is in Suse itself, and the latest releases are also
|
||||
available at ftp://ftp.suse.com/pub/people/ug/
|
||||
Q: Where can I get .rpms Suitable for openSUSE/SLES?
|
||||
|
||||
A: Dnsmasq is in openSUSE itself, and the latest releases are also
|
||||
available at http://download.opensuse.org/repositories/network/
|
||||
|
||||
|
||||
Q: Can I run dnsmasq in a Linux vserver?
|
||||
|
||||
20
Makefile
20
Makefile
@@ -1,4 +1,4 @@
|
||||
# dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
# 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
|
||||
@@ -32,18 +32,22 @@ SRC = src
|
||||
PO = po
|
||||
MAN = man
|
||||
|
||||
DNSMASQ_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_CFLAGS=`echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
|
||||
DBUS_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
|
||||
IDN_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
|
||||
IDN_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
|
||||
CT_CFLAGS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
|
||||
CT_LIBS= `echo $(COPTS) | ../bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
|
||||
SUNOS_LIBS= `if uname | grep SunOS 2>&1 >/dev/null; then echo -lsocket -lnsl -lposix4; fi`
|
||||
|
||||
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 \
|
||||
helper.o tftp.o log.o
|
||||
helper.o tftp.o log.o conntrack.o
|
||||
|
||||
all :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS)" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS)" \
|
||||
BUILD_CFLAGS="$(DBUS_CFLAGS) $(IDN_CFLAGS) $(CT_CFLAGS)" \
|
||||
BUILD_LIBS="$(DBUS_LIBS) $(IDN_LIBS) $(CT_LIBS) $(SUNOS_LIBS)" \
|
||||
-f ../Makefile dnsmasq
|
||||
|
||||
clean :
|
||||
@@ -60,8 +64,8 @@ install-common :
|
||||
all-i18n :
|
||||
@cd $(SRC) && $(MAKE) \
|
||||
I18N=-DLOCALEDIR='\"$(LOCALEDIR)\"' \
|
||||
BUILD_CFLAGS="$(DNSMASQ_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
BUILD_LIBS="$(DNSMASQ_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||
BUILD_CFLAGS="$(DBUS_CFLAGS) $(CT_CFLAGS) `$(PKG_CONFIG) --cflags libidn`" \
|
||||
BUILD_LIBS="$(DBUS_LIBS) $(CT_LIBS) $(SUNOS_LIBS) `$(PKG_CONFIG) --libs libidn`" \
|
||||
-f ../Makefile dnsmasq
|
||||
@cd $(PO); for f in *.po; do \
|
||||
cd ../$(SRC) && $(MAKE) \
|
||||
|
||||
18
bld/Android.mk
Normal file
18
bld/Android.mk
Normal file
@@ -0,0 +1,18 @@
|
||||
LOCAL_PATH := external/dnsmasq/src
|
||||
|
||||
#########################
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
|
||||
forward.c helper.c lease.c log.c \
|
||||
netlink.c network.c option.c rfc1035.c \
|
||||
rfc2131.c tftp.c util.c conntrack.c
|
||||
|
||||
LOCAL_MODULE := dnsmasq
|
||||
|
||||
LOCAL_C_INCLUDES := external/dnsmasq/src
|
||||
|
||||
LOCAL_CFLAGS := -O2 -g -W -Wall -D__ANDROID__ -DNO_IPV6 -DNO_TFTP -DNO_SCRIPT
|
||||
LOCAL_SYSTEM_SHARED_LIBRARIES := libc libcutils
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@@ -8,8 +8,6 @@
|
||||
<array>
|
||||
<string>/usr/local/sbin/dnsmasq</string>
|
||||
<string>--keep-in-foreground</string>
|
||||
<string>--log-queries</string>
|
||||
<string>--log-facility=/var/log/dnsmasq.log</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
54
contrib/conntrack/README
Normal file
54
contrib/conntrack/README
Normal file
@@ -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/
|
||||
|
||||
16
contrib/systemd/README
Normal file
16
contrib/systemd/README
Normal file
@@ -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
|
||||
|
||||
|
||||
12
contrib/systemd/dnsmasq.service
Normal file
12
contrib/systemd/dnsmasq.service
Normal file
@@ -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
|
||||
23
contrib/wrt/dhcp_lease_time.1
Normal file
23
contrib/wrt/dhcp_lease_time.1
Normal file
@@ -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>.
|
||||
|
||||
|
||||
35
contrib/wrt/dhcp_release.1
Normal file
35
contrib/wrt/dhcp_release.1
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
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 nlmsghdr *h;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# uneccessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link uneccessarily.
|
||||
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link unnecessarily.
|
||||
|
||||
# Never forward plain names (without a dot or domain part)
|
||||
#domain-needed
|
||||
@@ -48,7 +48,7 @@
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
@@ -57,14 +57,14 @@
|
||||
#local=/localnet/
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in doubleclick.net to a local
|
||||
# webserver.
|
||||
#address=/doubleclick.net/127.0.0.1
|
||||
# The example below send any host in double-click.net to a local
|
||||
# web-server.
|
||||
#address=/double-click.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
#listen-address=
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP on it.
|
||||
# disable DHCP and TFTP on it.
|
||||
#no-dhcp-interface=
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
@@ -145,7 +145,7 @@
|
||||
# some DHCP options may be set only for this network.
|
||||
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# Specify a subnet which can't be used for dynamic address allocation,
|
||||
@@ -153,17 +153,18 @@
|
||||
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||
# of some type for the subnet in question.
|
||||
# In this case the netmask is implied (it comes from the network
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explict netmask instead.
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
# need to be on the same network. The order of the parameters in these
|
||||
# do not matter, it's permissble to give name,adddress and MAC in any order
|
||||
# do not matter, it's permissible to give name, address and MAC in any
|
||||
# order.
|
||||
|
||||
# Always allocate the host with ethernet address 11:22:33:44:55:66
|
||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||
# The IP address 192.168.0.60
|
||||
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||
|
||||
@@ -171,13 +172,13 @@
|
||||
# 11:22:33:44:55:66 to be "fred"
|
||||
#dhcp-host=11:22:33:44:55:66,fred
|
||||
|
||||
# Always give the host with ethernet address 11:22:33:44:55:66
|
||||
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give a host with ethernet address 11:22:33:44:55:66 or
|
||||
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||
# that these two ethernet interfaces will never be in use at the same
|
||||
# that these two Ethernet interfaces will never be in use at the same
|
||||
# time, and give the IP address to the second, even if it is already
|
||||
# in use by the first. Useful for laptops with wired and wireless
|
||||
# addresses.
|
||||
@@ -200,27 +201,27 @@
|
||||
# it asks for a DHCP lease.
|
||||
#dhcp-host=judge
|
||||
|
||||
# Never offer DHCP service to a machine whose ethernet
|
||||
# Never offer DHCP service to a machine whose Ethernet
|
||||
# address is 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,ignore
|
||||
|
||||
# Ignore any client-id presented by the machine with ethernet
|
||||
# Ignore any client-id presented by the machine with Ethernet
|
||||
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||
# being treated differently when running under different OS's or
|
||||
# between PXE boot and OS boot.
|
||||
#dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# the machine with ethernet address 11:22:33:44:55:66
|
||||
# the machine with Ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,set:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with ethernet address starting 11:22:33:
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Ignore any clients which are specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unkown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=tag:!known
|
||||
|
||||
@@ -244,11 +245,11 @@
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
@@ -262,7 +263,7 @@
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# for all other option numbers.
|
||||
#dhcp-option=3
|
||||
|
||||
@@ -296,7 +297,7 @@
|
||||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# Windows clients and Samba.
|
||||
#dhcp-option=19,0 # option ip-forwarding off
|
||||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||
@@ -310,10 +311,10 @@
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
@@ -330,7 +331,7 @@
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
@@ -341,24 +342,27 @@
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this is you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#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
|
||||
# filenames, the first loads gPXE, and the second tells gPXE what to
|
||||
# load. The dhcp-match sets the gpxe tag for requests from gPXE.
|
||||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option.
|
||||
#dhcp-boot=tag:!gpxe,undionly.kpxe
|
||||
#dhcp-boot=mybootimage
|
||||
|
||||
|
||||
# Encapsulated options for Etherboot gPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||
@@ -368,7 +372,7 @@
|
||||
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
|
||||
# Do real PXE, rather than just booting a single file, this is an
|
||||
# alternative to dhcp-boot.
|
||||
@@ -380,11 +384,11 @@
|
||||
#pxe-service=x86PC, "Boot from local disk"
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||
# Beware this fails on old PXE ROMS.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
|
||||
# Use bootserver on network, found my multicast or broadcast.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||
@@ -395,20 +399,20 @@
|
||||
# If you have multicast-FTP available,
|
||||
# information for that can be passed in a similar way using options 1
|
||||
# to 5. See page 19 of
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
|
||||
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
# Set the root directory for files availble via FTP.
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||
# clients.
|
||||
#tftp-no-blocksize
|
||||
@@ -421,6 +425,14 @@
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#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
|
||||
#dhcp-lease-max=150
|
||||
|
||||
@@ -433,16 +445,16 @@
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slighest chance that you might end up accidentally configuring a DHCP
|
||||
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
# if there is one.
|
||||
# if there is one.
|
||||
#dhcp-script=/bin/echo
|
||||
|
||||
# Set the cachesize here.
|
||||
|
||||
10
doc.html
10
doc.html
@@ -1,9 +1,17 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE> Dnsmasq - a DNS forwarder for NAT firewalls.</TITLE>
|
||||
<link rel="icon"
|
||||
href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
|
||||
</HEAD>
|
||||
<BODY BGCOLOR="WHITE">
|
||||
<H1 ALIGN=center>Dnsmasq</H1>
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td align="left" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td>
|
||||
<td align="middle" valign="middle"><h1>Dnsmasq</h1></td>
|
||||
<td align="right" valign="middle"><img border="0" src="http://www.thekelleys.org.uk/dnsmasq/images/icon.png" /></td></tr>
|
||||
</table>
|
||||
|
||||
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
|
||||
|
||||
12
logo/README
Normal file
12
logo/README
Normal file
@@ -0,0 +1,12 @@
|
||||
Dnsmasq logo, contributed by Justin Clift.
|
||||
|
||||
The source format is Inkscape SVG vector format, which is scalable and
|
||||
easy to export to other formats. For convenience I've included a 56x31
|
||||
png export and a 16x16 ico suitable for use as a web favicon.
|
||||
|
||||
Simon Kelley, 22/10/2010
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
logo/favicon.ico
Normal file
BIN
logo/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
logo/icon.png
Normal file
BIN
logo/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
157
logo/icon.svg
Normal file
157
logo/icon.svg
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="56"
|
||||
height="31"
|
||||
viewBox="0 0 56 31"
|
||||
enable-background="new 0 0 72.833 46.667"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="dnsmasq_icon.svg"
|
||||
inkscape:export-filename="/x/centos_home/jc/workspace/git_repos/libvirt-media/libvirt-media/png/dnsmasq_icon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><metadata
|
||||
id="metadata27"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs25"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 23.3335 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="72.833 : 23.3335 : 1"
|
||||
inkscape:persp3d-origin="36.4165 : 15.555667 : 1"
|
||||
id="perspective4857" />
|
||||
<filter
|
||||
id="filter3802"
|
||||
inkscape:label="filter1"
|
||||
color-interpolation-filters="sRGB" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient4929"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient5798"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#SVGID_3_"
|
||||
id="linearGradient5812"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="30.564501"
|
||||
y1="-8.8144999"
|
||||
x2="32.937"
|
||||
y2="32.715599" /><filter
|
||||
id="filter6262"
|
||||
inkscape:label="Drop shadow"
|
||||
width="1.5"
|
||||
height="1.5"
|
||||
x="-0.25"
|
||||
y="-0.25"
|
||||
color-interpolation-filters="sRGB"><feGaussianBlur
|
||||
id="feGaussianBlur6264"
|
||||
in="SourceAlpha"
|
||||
stdDeviation="2.500000"
|
||||
result="blur" /><feColorMatrix
|
||||
id="feColorMatrix6266"
|
||||
result="bluralpha"
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.500000 0 " /><feOffset
|
||||
id="feOffset6268"
|
||||
in="bluralpha"
|
||||
dx="2.700000"
|
||||
dy="2.600000"
|
||||
result="offsetBlur" /><feMerge
|
||||
id="feMerge6270"><feMergeNode
|
||||
id="feMergeNode6272"
|
||||
in="offsetBlur" /><feMergeNode
|
||||
id="feMergeNode6274"
|
||||
in="SourceGraphic" /></feMerge></filter></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1568"
|
||||
inkscape:window-height="1076"
|
||||
id="namedview23"
|
||||
showgrid="false"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="31.966768"
|
||||
inkscape:cy="21.211869"
|
||||
inkscape:window-x="567"
|
||||
inkscape:window-y="328"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:showpageshadow="false"
|
||||
showborder="true" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="dnsmasq"
|
||||
style="display:inline"
|
||||
transform="translate(5.2838057,-15.545371)"><g
|
||||
id="g3790"
|
||||
transform="matrix(0.8183832,0,0,0.8183832,65.304897,9.8747678)"
|
||||
style="filter:url(#filter6262)"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><g
|
||||
transform="translate(-91.018462,1.0687099)"
|
||||
id="g9">
|
||||
<path
|
||||
style="fill:#6700ad"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path11"
|
||||
d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffb616;stroke-width:1.85353255"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path13"
|
||||
d="M 54.997,12.151 C 50.083,9.132 43.29,7.266 35.791,7.266 c -7.5,0 -14.29,1.866 -19.204,4.885 -4.915,3.016 -7.956,7.184 -7.956,11.789 0,4.604 3.041,8.772 7.956,11.788 4.914,3.02 11.704,-4.271 19.204,-4.271 7.499,0 14.292,7.291 19.206,4.271 4.914,-3.016 7.955,-7.185 7.955,-11.788 0,-4.606 -3.041,-8.773 -7.955,-11.789 z M 24.996,24.318 c -2.698,0 -4.885,-0.922 -4.885,-2.061 0,-1.14 2.187,-2.063 4.885,-2.063 2.697,0 4.885,0.924 4.885,2.063 0,1.139 -2.188,2.061 -4.885,2.061 z m 21.501,0.191 c -2.686,0 -4.861,-0.856 -4.861,-1.912 0,-1.054 2.176,-1.911 4.861,-1.911 2.685,0 4.863,0.857 4.863,1.911 0,1.056 -2.178,1.912 -4.863,1.912 z" />
|
||||
</g><g
|
||||
transform="translate(-91.018462,1.0687099)"
|
||||
id="Layer_2">
|
||||
<linearGradient
|
||||
y2="32.715599"
|
||||
x2="32.937"
|
||||
y1="-8.8144999"
|
||||
x1="30.564501"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="SVGID_3_">
|
||||
<stop
|
||||
id="stop17"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0.73"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop19"
|
||||
style="stop-color:#FFFFFF;stop-opacity:0"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:url(#linearGradient5812)"
|
||||
id="path21"
|
||||
d="m 54.1,15.361 c -0.924,1.078 -2.782,1.265 -3.857,1.06 C 38,14.083 22.75,12.75 16.027,23.031 14.858,24.819 11.992,25.39 10.293,23.887 8.631,22.417 13.105,15.804 17.646,13.033 22.194,10.252 28.474,8.53 35.41,8.53 c 6.936,0 13.215,1.722 17.756,4.502 0.731,0.442 1.627,1.52 0.934,2.329 z" />
|
||||
</g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
119
man/dnsmasq.8
119
man/dnsmasq.8
@@ -23,7 +23,7 @@ options. It includes a secure, read-only,
|
||||
TFTP server to allow net/PXE boot of DHCP hosts and also supports BOOTP.
|
||||
.PP
|
||||
Dnsmasq
|
||||
supports IPv6 for DNS, but not DHCP.
|
||||
supports IPv6 for DNS and TFTP, but not DHCP.
|
||||
.SH OPTIONS
|
||||
Note that in general missing parameters are allowed and switch off
|
||||
functions, for instance "--pid-file" disables writing a PID file. On
|
||||
@@ -249,8 +249,8 @@ requested name has underscores, to catch LDAP requests.
|
||||
.B \-r, --resolv-file=<file>
|
||||
Read the IP addresses of the upstream nameservers from <file>, instead of
|
||||
/etc/resolv.conf. For the format of this file see
|
||||
.BR resolv.conf (5)
|
||||
the only lines relevant to dnsmasq are nameserver ones. Dnsmasq can
|
||||
.BR resolv.conf (5).
|
||||
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
|
||||
overrides the default, subsequent ones add to the list. This is only
|
||||
allowed when polling; the file with the currently latest modification
|
||||
@@ -303,7 +303,7 @@ This is useful when new nameservers may have different
|
||||
data than that held in cache.
|
||||
.TP
|
||||
.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
|
||||
from /etc/hosts or DHCP then a "not found" answer is returned.
|
||||
.TP
|
||||
@@ -350,6 +350,9 @@ is a synonym for
|
||||
.B server
|
||||
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
|
||||
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
|
||||
@@ -415,7 +418,9 @@ all that match are returned.
|
||||
.TP
|
||||
.B \-Y, --txt-record=<name>[[,<text>],<text>]
|
||||
Return a TXT DNS record. The value of TXT record is a set of strings,
|
||||
so any number may be included, split by commas.
|
||||
so any number may be included, delimited by commas; use quotes to put
|
||||
commas into a string. Note that the maximum length of a single string
|
||||
is 255 characters, longer strings are split into 255 character chunks.
|
||||
.TP
|
||||
.B --ptr-record=<name>[,<target>]
|
||||
Return a PTR DNS record.
|
||||
@@ -442,6 +447,15 @@ the name. More than one name may be associated with an interface
|
||||
address by repeating the flag; in that case the first instance is used
|
||||
for the reverse address-to-name mapping.
|
||||
.TP
|
||||
.B --add-mac
|
||||
Add the MAC address of the requestor to DNS queries which are
|
||||
forwarded upstream. This may be used to DNS filtering by the upstream
|
||||
server. The MAC address can only be added if the requestor is on the same
|
||||
subnet as the dnsmasq server. Note that the mechanism used to achieve this (an EDNS0 option)
|
||||
is not yet standardised, so this should be considered
|
||||
experimental. Also note that exposing MAC addresses in this way may
|
||||
have security and privacy implications.
|
||||
.TP
|
||||
.B \-c, --cache-size=<cachesize>
|
||||
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching.
|
||||
.TP
|
||||
@@ -456,6 +470,30 @@ Set the maximum number of concurrent DNS queries. The default value is
|
||||
where this needs to be increased is when using web-server log file
|
||||
resolvers, which can generate large numbers of concurrent queries.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
A resolver on a client machine can do DNSSEC validation in two ways: it
|
||||
can perform the cryptograhic operations on the reply it receives, or
|
||||
it can rely on the upstream recursive nameserver to do the validation
|
||||
and set a bit in the reply if it succeeds. Dnsmasq is not a DNSSEC
|
||||
validator, so it cannot perform the validation role of the recursive nameserver,
|
||||
but it can pass through the validation results from its own upstream
|
||||
nameservers. This option enables this behaviour. You should only do
|
||||
this if you trust all the configured upstream nameservers
|
||||
.I and the network between you and them.
|
||||
If you use the first DNSSEC mode, validating resolvers in clients,
|
||||
this option is not required. Dnsmasq always returns all the data
|
||||
needed for a client to do validation itself.
|
||||
.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>]
|
||||
Enable the DHCP server. Addresses will be given out from the range
|
||||
<start-addr> to <end-addr> and from statically defined addresses given
|
||||
@@ -469,8 +507,11 @@ minimum lease time is two minutes. This
|
||||
option may be repeated, with different addresses, to enable DHCP
|
||||
service to more than one network. For directly connected networks (ie,
|
||||
networks on which the machine running dnsmasq has an interface) the
|
||||
netmask is optional. It is, however, required for networks which
|
||||
receive DHCP service via a relay agent. The broadcast address is
|
||||
netmask is optional: dnsmasq will determine it from the interface
|
||||
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
|
||||
allowed to have more than one dhcp-range in a single subnet.
|
||||
|
||||
@@ -588,15 +629,17 @@ time and there is no way for dnsmasq to enforce this. It is, for instance,
|
||||
useful to allocate a stable IP address to a laptop which
|
||||
has both wired and wireless interfaces.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<file>
|
||||
Read DHCP host information from the specified file. The file contains
|
||||
.B --dhcp-hostsfile=<path>
|
||||
Read DHCP host information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The file contains
|
||||
information about one host per line. The format of a line is the same
|
||||
as text to the right of '=' in --dhcp-host. The advantage of storing DHCP host information
|
||||
in this file is that it can be changed without re-starting dnsmasq:
|
||||
the file will be re-read when dnsmasq receives SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<file>
|
||||
Read DHCP option information from the specified file. The advantage of
|
||||
.B --dhcp-optsfile=<path>
|
||||
Read DHCP option information from the specified file. If a directory
|
||||
is given, then read all the files contained in that directory. The advantage of
|
||||
using this option is the same as for --dhcp-hostsfile: the
|
||||
dhcp-optsfile will be re-read when dnsmasq receives SIGHUP. Note that
|
||||
it is possible to encode the information in a
|
||||
@@ -818,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
|
||||
happens automatically, some old BOOTP clients do not.
|
||||
.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
|
||||
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
|
||||
@@ -827,6 +870,23 @@ is providing a TFTP service (see
|
||||
) then only the filename is required here to enable network booting.
|
||||
If the optional tag(s) are given,
|
||||
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
|
||||
.B --pxe-service=[tag:<tag>,]<CSA>,<menu text>[,<basename>|<bootservicetype>][,<server address>]
|
||||
Most uses of PXE boot-ROMS simply allow the PXE
|
||||
@@ -946,7 +1006,8 @@ all of the following variables added.
|
||||
DNSMASQ_CLIENT_ID if the host provided a client-id.
|
||||
|
||||
DNSMASQ_DOMAIN if the fully-qualified domain name of the host is
|
||||
known, this is set to the domain part.
|
||||
known, this is set to the domain part. (Note that the hostname passed
|
||||
to the script as an argument is never fully-qualified.)
|
||||
|
||||
If the client provides vendor-class, hostname or user-class,
|
||||
these are provided in DNSMASQ_VENDOR_CLASS
|
||||
@@ -1020,7 +1081,7 @@ as if they had arrived at <interface>. This option is necessary when
|
||||
using "old style" bridging on BSD platforms, since
|
||||
packets arrive at tap interfaces which don't have an IP address.
|
||||
.TP
|
||||
.B \-s, --domain=<domain>[,<address range>]
|
||||
.B \-s, --domain=<domain>[,<address range>[,local]]
|
||||
Specifies DNS domains for the DHCP server. Domains may be be given
|
||||
unconditionally (without the IP range) or for limited IP ranges. This has two effects;
|
||||
firstly it causes the DHCP server to return the domain to any hosts
|
||||
@@ -1039,11 +1100,22 @@ and have a machine whose DHCP hostname is "laptop". The IP address for that mach
|
||||
.B dnsmasq
|
||||
both as "laptop" and "laptop.thekelleys.org.uk". If the domain is
|
||||
given as "#" then the domain is read from the first "search" directive
|
||||
in /etc/resolv.conf (or equivalent). The address range can be of the form
|
||||
in /etc/resolv.conf (or equivalent).
|
||||
|
||||
The address range can be of the form
|
||||
<ip address>,<ip address> or <ip address>/<netmask> or just a single
|
||||
<ip address>. See
|
||||
.B --dhcp-fqdn
|
||||
which can change the behaviour of dnsmasq with domains.
|
||||
|
||||
If the address range is given as ip-address/network-size, then a
|
||||
additional flag "local" may be supplied which has the effect of adding
|
||||
--local declarations for forward and reverse DNS queries. Eg.
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
is identical to
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
The network size must be 8, 16 or 24 for this to be legal.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
In the default mode, dnsmasq inserts the unqualified names of
|
||||
@@ -1123,7 +1195,8 @@ of concurrent TFTP connections is limited by the size of the port range.
|
||||
.TP
|
||||
.B \-C, --conf-file=<file>
|
||||
Specify a different configuration file. The conf-file option is also allowed in
|
||||
configuration files, to include multiple configuration files.
|
||||
configuration files, to include multiple configuration files. A
|
||||
filename of "-" causes dnsmasq to read configuration from stdin.
|
||||
.TP
|
||||
.B \-7, --conf-dir=<directory>[,<file-extension>......]
|
||||
Read all the files in the given directory as configuration
|
||||
@@ -1284,6 +1357,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
|
||||
command line rather than a configuration file, be sure to escape !,
|
||||
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
|
||||
Note that for
|
||||
.B dhcp-range
|
||||
@@ -1445,6 +1529,9 @@ assume that it is the system default.
|
||||
.IR /usr/local/etc/dnsmasq.conf
|
||||
|
||||
.IR /etc/resolv.conf
|
||||
.IR /var/run/dnsmasq/resolv.conf
|
||||
.IR /etc/ppp/resolv.conf
|
||||
.IR /etc/dhcpc/resolv.conf
|
||||
|
||||
.IR /etc/hosts
|
||||
|
||||
|
||||
150
man/fr/dnsmasq.8
150
man/fr/dnsmasq.8
@@ -22,7 +22,7 @@ peut être configuré pour envoyer n'importe quel option DHCP.
|
||||
Il inclut un serveur TFTP sécurisé en lecture seule permettant le démarrage via
|
||||
le réseau/PXE de clients DHCP et supporte également le protocole BOOTP.
|
||||
.PP
|
||||
Dnsmasq supporte IPv6 pour le DNS mais pas pour le DHCP.
|
||||
Dnsmasq supporte IPv6 pour le DNS et TFTP mais pas pour le DHCP.
|
||||
.SH OPTIONS
|
||||
Notes : Il est possible d'utiliser des options sans leur donner de paramètre.
|
||||
Dans ce cas, la fonction correspondante sera désactivée. Par exemple
|
||||
@@ -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.
|
||||
.TP
|
||||
.B \-D, --domain-needed
|
||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes pour des noms
|
||||
simples, ne comprenant donc ni points ni nom de domaine. Si un nom n'est pas
|
||||
dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse de type
|
||||
"non trouvé" est renvoyée.
|
||||
Indique à Dnsmasq de ne jamais transmettre en amont de requêtes A ou AAAA pour
|
||||
des noms simples, c'est à dire ne comprenant ni points ni nom de domaine. Si un
|
||||
nom n'est pas dans /etc/hosts ou dans la liste des baux DHCP, alors une réponse
|
||||
de type "non trouvé" est renvoyée.
|
||||
.TP
|
||||
.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
|
||||
@@ -402,6 +402,10 @@ est synonyme de
|
||||
("serveur") afin de rendre plus claire l'utilisation de cette option pour cet
|
||||
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 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
|
||||
@@ -491,7 +495,10 @@ retournés dans la réponse.
|
||||
.B \-Y, --txt-record=<nom>[[,<texte>],<texte>]
|
||||
Définit un enregistrement DNS de type TXT. La valeur de l'enregistrement TXT est
|
||||
un ensemble de chaînes de caractères, donc un nombre variable de chaînes de
|
||||
caractères peuvent être spécifiées, séparées par des virgules.
|
||||
caractères peuvent être spécifiées, séparées par des virgules. Utilisez des
|
||||
guillemets pour mettre une virgule dans une chaîne de caractères. Notez que la
|
||||
longueur maximale pour une chaîne est de 255 caractères, les chaînes plus
|
||||
longues étant découpées en morceaux de 255 caractères de longs.
|
||||
.TP
|
||||
.B --ptr-record=<nom>[,<cible>]
|
||||
Définit un enregistrement DNS de type PTR.
|
||||
@@ -519,6 +526,16 @@ Plus d'un nom peut être associé à une interface donnée en répétant cette o
|
||||
plusieurs fois; dans ce cas, l'enregistrement inverse pointe vers le nom fourni
|
||||
dans la première instance de cette option.
|
||||
.TP
|
||||
.B --add-mac
|
||||
Ajoute l'adresse MAC du requêteur aux requêtes DNS transmises aux serveurs
|
||||
amonts. Cela peut être utilisé dans un but de filtrage DNS par les serveurs
|
||||
amonts. L'adresse MAC peut uniquement être ajoutée si le requêteur est sur le
|
||||
même sous-réseau que le serveur dnsmasq. Veuillez noter que le mécanisme
|
||||
utilisé pour effectuer cela (une option EDNS0) n'est pas encore standardisée,
|
||||
aussi cette fonctionalité doit être considérée comme expérimentale. Notez
|
||||
également qu'exposer les adresses MAC de la sorte peut avoir des implications
|
||||
en termes de sécurité et de vie privée.
|
||||
.TP
|
||||
.B \-c, --cache-size=<taille>
|
||||
Définit la taille du cache de Dnsmasq. La valeur par défaut est de 150 noms.
|
||||
Définir une valeur de zéro désactive le cache.
|
||||
@@ -537,6 +554,31 @@ lorsqu'un serveur web a la résolution de nom activée pour l'enregistrement de
|
||||
son journal des requêtes, ce qui peut générer un nombre important de requêtes
|
||||
simultanées.
|
||||
.TP
|
||||
.B --proxy-dnssec
|
||||
Un resolveur sur une machine cliente peut effectuer la validation DNSSEC de
|
||||
deux façons : il peut effectuer lui-même les opérations de chiffrements sur
|
||||
la réponse reçue, ou il peut laisser le serveur récursif amont faire la
|
||||
validation et positionner un drapeau dans la réponse au cas où celle-ci est
|
||||
correcte. Dnsmasq n'est pas un validateur DNSSEC, aussi il ne peut effectuer
|
||||
la validation comme un serveur de nom récursif, cependant il peut retransmettre
|
||||
les résultats de validation de ses serveurs amonts. Cette option permet
|
||||
l'activation de cette fonctionalité. Vous ne devriez utiliser cela que si vous
|
||||
faites confiance aux serveurs amonts
|
||||
.I ainsi que le réseau entre vous et eux.
|
||||
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
|
||||
données nécessaires par un client pour effectuer la validation lui-même.
|
||||
.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>]
|
||||
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
|
||||
@@ -551,9 +593,14 @@ minutes.
|
||||
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
|
||||
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
|
||||
contre requis pour les réseaux pour lesquels le service DHCP se fait via un
|
||||
relais DHCP ("relay agent"). L'adresse de broadcast est toujours optionnelle.
|
||||
Dnsmasq possède une interface), le masque de réseau est optionnel : Dnsmasq la
|
||||
déterminera à partir de la configuration des interfaces.
|
||||
|
||||
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
|
||||
sous-réseau.
|
||||
@@ -674,20 +721,24 @@ donné et dnsmasq n'a aucun moyen de s'assurer de cela. Cela est utile,
|
||||
par exemple, pour allouer une adresse IP stable à un laptop qui
|
||||
aurait à la fois une connexion filaire et sans-fil.
|
||||
.TP
|
||||
.B --dhcp-hostsfile=<fichier>
|
||||
Lis les informations d'hôtes DHCP dans le fichier spécifié. Le fichier contient
|
||||
des informations à raison d'un hôte par ligne. Le format d'une ligne est la même
|
||||
que le texte fourni à la droite sur caractère "=" dans l'option
|
||||
.B --dhcp-hostsfile=<chemin>
|
||||
Lis les informations d'hôtes DHCP dans le fichier spécifié. Si l'argument est
|
||||
un chemin vers un répertoire, lis tous les fichiers de ce répertoire. Le
|
||||
fichier contient des informations à raison d'un hôte par ligne. Le format
|
||||
d'une ligne est la même que le texte fourni à la droite sur caractère "=" dans
|
||||
l'option
|
||||
.B --dhcp-host.
|
||||
L'avantage de stocker les informations sur les hôtes DHCP dans ce fichier est
|
||||
que celles-ci peuvent être modifiées sans recharger Dnsmasq; le fichier sera
|
||||
relu lorsque Dnsmasq reçoit un signal SIGHUP.
|
||||
.TP
|
||||
.B --dhcp-optsfile=<fichier>
|
||||
Lis les informations relatives aux options DHCP dans le fichier spécifié.
|
||||
L'intérêt d'utiliser cette option est le même que pour --dhcp-hostsfile : le
|
||||
fichier spécifié sera rechargé à la réception par dnsmasq d'un signal SIGHUP.
|
||||
Notez qu'il est possible d'encoder l'information via
|
||||
.B --dhcp-optsfile=<chemin>
|
||||
Lis les informations relatives aux options DHCP dans le fichier spécifié. Si
|
||||
l'argument est un chemin vers un répertoire, lis tous les fichiers de ce
|
||||
répertoire. L'intérêt d'utiliser cette option est le même que pour
|
||||
--dhcp-hostsfile : le fichier spécifié sera rechargé à la réception par
|
||||
dnsmasq d'un signal SIGHUP. Notez qu'il est possible d'encoder l'information
|
||||
via
|
||||
.B --dhcp-boot
|
||||
en utilisant les noms optionnels bootfile-name, server-ip-address et
|
||||
tftp-server. Ceci permet d'inclure ces options dans un fichier "dhcp-optsfile".DNSMASQ_SUPPLIED_HOSTNAME
|
||||
@@ -937,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
|
||||
se fait automatiquement, mais ce n'est pas la cas de certains vieux clients BOOTP.
|
||||
.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
|
||||
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
|
||||
@@ -947,6 +998,25 @@ s'exécute Dnsmasq. Si Dnsmasq founit un service TFTP (voir
|
||||
le réseau.
|
||||
Si d'éventuels labels sont fournis, ils doivent coïncider avec
|
||||
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
|
||||
.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
|
||||
@@ -1074,7 +1144,8 @@ auquel se rajoute quelques unes ou toutes les variables décrites ci-dessous :
|
||||
DNSMASQ_CLIENT_ID, si l'hôte a fourni un identifiant de client.
|
||||
|
||||
DNSMASQ_DOMAIN si le nom de domaine pleinement qualifié de l'hôte est connu, la
|
||||
part relative au domaine y est stockée.
|
||||
part relative au domaine y est stockée. (Notez que le nom d'hôte transmis comme
|
||||
argument au script n'est jamais pleinement qualifié).
|
||||
|
||||
Si le client fournit une information de classe de vendeur, un nom d'hôte, ou
|
||||
des classes d'utilisateur, celles-ci sont fournies dans les
|
||||
@@ -1151,7 +1222,7 @@ nécessaire lors de l'utilisation de pont ethernet "ancien mode" sur plate-forme
|
||||
BSD, puisque dans ce cas les paquets arrivent sur des interfaces "tap" n'ont
|
||||
pas d'adresse IP.
|
||||
.TP
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>]
|
||||
.B \-s, --domain=<domaine>[,<gamme d'adresses>[,local]]
|
||||
Spécifie le domaine du serveur DHCP. Le domaine peut être donné de manière
|
||||
inconditionnelle (sans spécifier de gamme d'adresses IP) ou pour des gammes
|
||||
d'adresses IP limitées. Cela a deux effets; tout d'abord, le
|
||||
@@ -1173,11 +1244,23 @@ et avoir une machine dont le nom DHCP serait "laptop". L'adresse IP de cette
|
||||
machine sera disponible à la fois pour "laptop" et "laptop.thekelleys.org.uk".
|
||||
Si la valeur fournie pour <domaine> est "#", alors le nom de domaine est
|
||||
positionné à la première valeur de la directive "search" du fichier
|
||||
/etc/resolv.conf (ou équivalent). La gamme d'adresses peut être de la forme
|
||||
/etc/resolv.conf (ou équivalent).
|
||||
|
||||
La gamme d'adresses peut être de la forme
|
||||
<adresse ip>,<adresse ip> ou <adresse ip>/<masque de réseau> voire une simple
|
||||
<adresse ip>. Voir
|
||||
.B --dhcp-fqdn
|
||||
qui peut changer le comportement de dnsmasq relatif aux domaines.
|
||||
|
||||
Si la gamme d'adresse est fournie sous la forme
|
||||
<adresse ip>/<taille de réseau>, alors le drapeau "local" peut-être rajouté
|
||||
qui a pour effect d'ajouter --local-declarations aux requêtes DNS directes et
|
||||
inverses. C-à-d
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24,local
|
||||
est indentique à
|
||||
.B --domain=thekelleys.org.uk,192.168.0.0/24
|
||||
--local=/thekelleys.org.uk/ --local=/0.168.192.in-addr.arpa/
|
||||
La taille de réseau doit-être de 8, 16 ou 24 pour être valide.
|
||||
.TP
|
||||
.B --dhcp-fqdn
|
||||
Dans le mode par défaut, dnsmasq insère les noms non-qualifiés des clients
|
||||
@@ -1284,7 +1367,9 @@ est limitée par la taille de la plage de ports ainsi définie.
|
||||
.B \-C, --conf-file=<fichier>
|
||||
Spécifie un fichier de configuration différent. L'option "conf-file" est
|
||||
également autorisée dans des fichiers de configuration, ce qui permet
|
||||
l'inclusion de multiples fichiers de configuration.
|
||||
l'inclusion de multiples fichiers de configuration. L'utilisation de "-" comme
|
||||
nom de fichier permet la lecture par dnsmasq de sa configuration sur l'entrée standard
|
||||
stdin.
|
||||
.TP
|
||||
.B \-7, --conf-dir=<répertoire>[,<extension de fichier>...]
|
||||
Lis tous les fichiers du répertoire spécifié et les traite comme des fichiers de
|
||||
@@ -1370,7 +1455,6 @@ Dans le cas de l'utilisation du logiciel logrotate, les options requises sont
|
||||
.B create
|
||||
et
|
||||
.B delaycompress.
|
||||
|
||||
|
||||
.PP
|
||||
Dnsmasq est un logiciel de transmission de requêtes DNS : il n'est pas capable
|
||||
@@ -1462,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
|
||||
d'échapper le caractère !, qui est un méta-caractère d'interpréteur de commande
|
||||
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
|
||||
Veuillez noter que pour
|
||||
.B dhcp-range
|
||||
@@ -1621,6 +1720,9 @@ et assume de ce fait qu'il s'agit de la valeur par défaut du système.
|
||||
.IR /etc/dnsmasq.conf
|
||||
|
||||
.IR /usr/local/etc/dnsmasq.conf
|
||||
.IR /var/run/dnsmasq/resolv.conf
|
||||
.IR /etc/ppp/resolv.conf
|
||||
.IR /etc/dhcpc/resolv.conf
|
||||
|
||||
.IR /etc/resolv.conf
|
||||
|
||||
|
||||
934
po/pt_BR.po
934
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
@@ -221,7 +221,7 @@ triggering dial-on-demand internet links.
|
||||
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>.
|
||||
<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>.
|
||||
<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
|
||||
|
||||
136
src/bpf.c
136
src/bpf.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -28,7 +28,71 @@ static struct iovec ifreq = {
|
||||
.iov_len = 0
|
||||
};
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_dl.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 mib[6];
|
||||
size_t needed;
|
||||
char *next;
|
||||
struct rt_msghdr *rtm;
|
||||
struct sockaddr_inarp *sin2;
|
||||
struct sockaddr_dl *sdl;
|
||||
int rc;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = PF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_INET;
|
||||
mib[4] = NET_RT_FLAGS;
|
||||
#ifdef RTF_LLINFO
|
||||
mib[5] = RTF_LLINFO;
|
||||
#else
|
||||
mib[5] = 0;
|
||||
#endif
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1 || needed == 0)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (!expand_buf(&ifconf, needed))
|
||||
return 0;
|
||||
if ((rc = sysctl(mib, 6, ifconf.iov_base, &needed, NULL, 0)) == 0 ||
|
||||
errno != ENOMEM)
|
||||
break;
|
||||
needed += needed / 8;
|
||||
}
|
||||
if (rc == -1)
|
||||
return 0;
|
||||
|
||||
for (next = ifconf.iov_base ; next < (char *)ifconf.iov_base + needed; next += rtm->rtm_msglen)
|
||||
{
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
sin2 = (struct sockaddr_inarp *)(rtm + 1);
|
||||
sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
|
||||
if (!(*callback)(AF_INET, &sin2->sin_addr, LLADDR(sdl), sdl->sdl_alen, parm))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
char *ptr;
|
||||
struct ifreq *ifr;
|
||||
@@ -37,6 +101,13 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
int lastlen = 0;
|
||||
size_t len = 0;
|
||||
|
||||
if (family == AF_UNSPEC)
|
||||
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
|
||||
return arp_enumerate(parm, callback);
|
||||
#else
|
||||
return 0; /* need code for Solaris and MacOS*/
|
||||
#endif
|
||||
|
||||
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
@@ -83,39 +154,42 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
ifr = (struct ifreq *)ifreq.iov_base;
|
||||
memcpy(ifr, ptr, len);
|
||||
|
||||
if (ifr->ifr_addr.sa_family == AF_INET && ipv4_callback)
|
||||
if (ifr->ifr_addr.sa_family == family)
|
||||
{
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*ipv4_callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifr->ifr_addr.sa_family == AF_INET6 && ipv6_callback)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!(daemon->options & OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
if (family == AF_INET)
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
struct in_addr addr, netmask, broadcast;
|
||||
broadcast.s_addr = 0;
|
||||
addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFNETMASK, ifr) == -1)
|
||||
continue;
|
||||
netmask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (ioctl(fd, SIOCGIFBRDADDR, ifr) != -1)
|
||||
broadcast = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
|
||||
if (!((*callback)(addr,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
netmask, broadcast,
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addr = &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr;
|
||||
/* voodoo to clear interface field in address */
|
||||
if (!option_bool(OPT_NOWILD) && IN6_IS_ADDR_LINKLOCAL(addr))
|
||||
{
|
||||
addr->s6_addr[2] = 0;
|
||||
addr->s6_addr[3] = 0;
|
||||
}
|
||||
if (!((*callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
if (!((*ipv6_callback)(addr,
|
||||
(int)((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_scope_id,
|
||||
(int)if_nametoindex(ifr->ifr_name),
|
||||
parm)))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
165
src/cache.c
165
src/cache.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -75,7 +75,7 @@ void cache_init(void)
|
||||
struct crec *crecp;
|
||||
int i;
|
||||
|
||||
if (daemon->options & OPT_LOG)
|
||||
if (option_bool(OPT_LOG))
|
||||
addrbuff = safe_malloc(ADDRSTRLEN);
|
||||
|
||||
bignames_left = daemon->cachesize/10;
|
||||
@@ -226,7 +226,7 @@ char *cache_get_name(struct crec *crecp)
|
||||
{
|
||||
if (crecp->flags & F_BIGNAME)
|
||||
return crecp->name.bname->name;
|
||||
else if (crecp->flags & (F_DHCP | F_CONFIG))
|
||||
else if (crecp->flags & F_NAMEP)
|
||||
return crecp->name.namep;
|
||||
|
||||
return crecp->name.sname;
|
||||
@@ -366,9 +366,6 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
|
||||
log_query(flags | F_UPSTREAM, name, addr, NULL);
|
||||
|
||||
/* CONFIG bit means something else when stored in cache entries */
|
||||
flags &= ~F_CONFIG;
|
||||
|
||||
/* if previous insertion failed give up now. */
|
||||
if (insert_error)
|
||||
return NULL;
|
||||
@@ -503,7 +500,7 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
||||
/* first search, look for relevant entries and push to top of list
|
||||
also free anything which has expired */
|
||||
struct crec *next, **up, **insert = NULL, **chainp = &ans;
|
||||
int ins_flags = 0;
|
||||
unsigned short ins_flags = 0;
|
||||
|
||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = next)
|
||||
{
|
||||
@@ -695,7 +692,7 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
||||
if (hostname_isequal(cache->name.sname, a->target) &&
|
||||
(lookup = whine_malloc(sizeof(struct crec))))
|
||||
{
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_CONFIG | F_HOSTS | F_CNAME;
|
||||
lookup->flags = F_FORWARD | F_IMMORTAL | F_NAMEP | F_HOSTS | F_CNAME;
|
||||
lookup->name.namep = a->alias;
|
||||
lookup->addr.cname.cache = cache;
|
||||
lookup->addr.cname.uid = index;
|
||||
@@ -832,7 +829,7 @@ static int read_hostsfile(char *filename, int index, int cache_size)
|
||||
if ((canon = canonicalise(token, &nomem)))
|
||||
{
|
||||
/* If set, add a version of the name with a default domain appended */
|
||||
if ((daemon->options & OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
if (option_bool(OPT_EXPAND) && domain_suffix && !fqdn &&
|
||||
(cache = whine_malloc(sizeof(struct crec) +
|
||||
strlen(canon)+2+strlen(domain_suffix)-SMALLDNAME)))
|
||||
{
|
||||
@@ -896,107 +893,17 @@ void cache_reload(void)
|
||||
up = &cache->hash_next;
|
||||
}
|
||||
|
||||
if ((daemon->options & OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
if (option_bool(OPT_NO_HOSTS) && !daemon->addn_hosts)
|
||||
{
|
||||
if (daemon->cachesize > 0)
|
||||
my_syslog(LOG_INFO, _("cleared cache"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(daemon->options & OPT_NO_HOSTS))
|
||||
if (!option_bool(OPT_NO_HOSTS))
|
||||
total_size = read_hostsfile(HOSTSFILE, 0, total_size);
|
||||
|
||||
for (i = 0, ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
{
|
||||
if (i <= ah->index)
|
||||
i = ah->index + 1;
|
||||
|
||||
if (ah->flags & AH_DIR)
|
||||
ah->flags |= AH_INACTIVE;
|
||||
else
|
||||
ah->flags &= ~AH_INACTIVE;
|
||||
}
|
||||
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
|
||||
{
|
||||
DIR *dir_stream;
|
||||
struct dirent *ent;
|
||||
|
||||
/* don't read this as a file */
|
||||
ah->flags |= AH_INACTIVE;
|
||||
|
||||
if (!(dir_stream = opendir(ah->fname)))
|
||||
my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
|
||||
ah->fname, strerror(errno));
|
||||
else
|
||||
{
|
||||
while ((ent = readdir(dir_stream)))
|
||||
{
|
||||
size_t lendir = strlen(ah->fname);
|
||||
size_t lenfile = strlen(ent->d_name);
|
||||
struct hostsfile *ah1;
|
||||
char *path;
|
||||
|
||||
/* ignore emacs backups and dotfiles */
|
||||
if (lenfile == 0 ||
|
||||
ent->d_name[lenfile - 1] == '~' ||
|
||||
(ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
|
||||
ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* see if we have an existing record.
|
||||
dir is ah->fname
|
||||
file is ent->d_name
|
||||
path to match is ah1->fname */
|
||||
|
||||
for (ah1 = daemon->addn_hosts; ah1; ah1 = ah1->next)
|
||||
{
|
||||
if (lendir < strlen(ah1->fname) &&
|
||||
strstr(ah1->fname, ah->fname) == ah1->fname &&
|
||||
ah1->fname[lendir] == '/' &&
|
||||
strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
|
||||
{
|
||||
ah1->flags &= ~AH_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* make new record */
|
||||
if (!ah1)
|
||||
{
|
||||
if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
|
||||
continue;
|
||||
|
||||
if (!(path = whine_malloc(lendir + lenfile + 2)))
|
||||
{
|
||||
free(ah1);
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(path, ah->fname);
|
||||
strcat(path, "/");
|
||||
strcat(path, ent->d_name);
|
||||
ah1->fname = path;
|
||||
ah1->index = i++;
|
||||
ah1->flags = AH_DIR;
|
||||
ah1->next = daemon->addn_hosts;
|
||||
daemon->addn_hosts = ah1;
|
||||
}
|
||||
|
||||
/* inactivate record if not regular file */
|
||||
if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
|
||||
ah1->flags |= AH_INACTIVE;
|
||||
|
||||
}
|
||||
closedir(dir_stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
daemon->addn_hosts = expand_filelist(daemon->addn_hosts);
|
||||
for (ah = daemon->addn_hosts; ah; ah = ah->next)
|
||||
if (!(ah->flags & AH_INACTIVE))
|
||||
total_size = read_hostsfile(ah->fname, ah->index, total_size);
|
||||
@@ -1015,6 +922,21 @@ char *get_domain(struct in_addr addr)
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
struct crec *cache, **up;
|
||||
@@ -1036,7 +958,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
struct in_addr *host_address, time_t ttd)
|
||||
{
|
||||
struct crec *crec = NULL, *aliasc;
|
||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
unsigned short flags = F_NAMEP | F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||
int in_hosts = 0;
|
||||
struct cname *a;
|
||||
|
||||
@@ -1049,13 +971,13 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
in_hosts = 1;
|
||||
|
||||
if (crec->flags & F_CNAME)
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("%s is a CNAME, not giving it to the DHCP lease of %s"),
|
||||
host_name, inet_ntoa(*host_address));
|
||||
else if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||
{
|
||||
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||
my_syslog(LOG_WARNING,
|
||||
my_syslog(MS_DHCP | LOG_WARNING,
|
||||
_("not giving name %s to the DHCP lease of %s because "
|
||||
"the name exists in %s with address %s"),
|
||||
host_name, inet_ntoa(*host_address),
|
||||
@@ -1109,7 +1031,7 @@ void cache_add_dhcp_entry(char *host_name,
|
||||
|
||||
if (aliasc)
|
||||
{
|
||||
aliasc->flags = F_FORWARD | F_CONFIG | F_DHCP | F_CNAME;
|
||||
aliasc->flags = F_FORWARD | F_NAMEP | F_DHCP | F_CNAME;
|
||||
if (ttd == 0)
|
||||
aliasc->flags |= F_IMMORTAL;
|
||||
else
|
||||
@@ -1143,12 +1065,15 @@ void dump_cache(time_t now)
|
||||
serv->flags &= ~SERV_COUNTED;
|
||||
|
||||
for (serv = daemon->servers; serv; serv = serv->next)
|
||||
if (!(serv->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)))
|
||||
if (!(serv->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)))
|
||||
{
|
||||
int port;
|
||||
unsigned int queries = 0, failed_queries = 0;
|
||||
for (serv1 = serv; serv1; serv1 = serv1->next)
|
||||
if (!(serv1->flags & (SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED)) && sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
if (!(serv1->flags &
|
||||
(SERV_NO_ADDR | SERV_LITERAL_ADDRESS | SERV_COUNTED | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
sockaddr_isequal(&serv->addr, &serv1->addr))
|
||||
{
|
||||
serv1->flags |= SERV_COUNTED;
|
||||
queries += serv1->queries;
|
||||
@@ -1158,11 +1083,11 @@ void dump_cache(time_t now)
|
||||
my_syslog(LOG_INFO, _("server %s#%d: queries sent %u, retried or failed %u"), addrbuff, port, queries, failed_queries);
|
||||
}
|
||||
|
||||
if ((daemon->options & (OPT_DEBUG | OPT_LOG)))
|
||||
if (option_bool(OPT_DEBUG) || option_bool(OPT_LOG))
|
||||
{
|
||||
struct crec *cache ;
|
||||
int i;
|
||||
my_syslog(LOG_DEBUG, "Host Address Flags Expires");
|
||||
my_syslog(LOG_INFO, "Host Address Flags Expires");
|
||||
|
||||
for (i=0; i<hash_size; i++)
|
||||
for (cache = hash_table[i]; cache; cache = cache->hash_next)
|
||||
@@ -1208,7 +1133,7 @@ void dump_cache(time_t now)
|
||||
/* ctime includes trailing \n - eat it */
|
||||
*(p-1) = 0;
|
||||
#endif
|
||||
my_syslog(LOG_DEBUG, daemon->namebuff);
|
||||
my_syslog(LOG_INFO, daemon->namebuff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1237,12 +1162,12 @@ void querystr(char *str, unsigned short type)
|
||||
sprintf(str,"query[%s]", typestr[i].name);
|
||||
}
|
||||
|
||||
void log_query(unsigned short 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 *verb = "is";
|
||||
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
if (addr)
|
||||
@@ -1283,13 +1208,9 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
}
|
||||
}
|
||||
else if (flags & F_CNAME)
|
||||
{
|
||||
/* nasty abuse of NXDOMAIN and CNAME flags */
|
||||
if (flags & F_NXDOMAIN)
|
||||
dest = arg;
|
||||
else
|
||||
dest = "<CNAME>";
|
||||
}
|
||||
dest = "<CNAME>";
|
||||
else if (flags & F_RRNAME)
|
||||
dest = arg;
|
||||
|
||||
if (flags & F_CONFIG)
|
||||
source = "config";
|
||||
@@ -1315,6 +1236,6 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, char *ar
|
||||
if (strlen(name) == 0)
|
||||
name = ".";
|
||||
|
||||
my_syslog(LOG_DEBUG, "%s %s %s %s", source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%s %s %s %s", source, name, verb, dest);
|
||||
}
|
||||
|
||||
|
||||
51
src/config.h
51
src/config.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define VERSION "2.54"
|
||||
#define VERSION "2.58"
|
||||
|
||||
#define FTABSIZ 150 /* max number of outstanding requests (default) */
|
||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||
@@ -22,7 +22,7 @@
|
||||
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
|
||||
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
|
||||
#define FORWARD_TEST 50 /* try all servers every 50 queries */
|
||||
#define FORWARD_TIME 20 /* or 10 seconds */
|
||||
#define FORWARD_TIME 20 /* or 20 seconds */
|
||||
#define RANDOM_SOCKS 64 /* max simultaneous random ports */
|
||||
#define LEASE_RETRY 60 /* on error, retry writing leasefile after LEASE_RETRY seconds */
|
||||
#define CACHESIZ 150 /* default cache size */
|
||||
@@ -46,6 +46,8 @@
|
||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||
# elif defined(__sun__) || defined (__sun)
|
||||
# define LEASEFILE "/var/cache/dnsmasq.leases"
|
||||
# elif defined(__ANDROID__)
|
||||
# define LEASEFILE "/data/misc/dhcp/dnsmasq.leases"
|
||||
# else
|
||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||
# endif
|
||||
@@ -62,6 +64,7 @@
|
||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||
#define CHUSER "nobody"
|
||||
#define CHGRP "dip"
|
||||
#define NAMESERVER_PORT 53
|
||||
#define DHCP_SERVER_PORT 67
|
||||
#define DHCP_CLIENT_PORT 68
|
||||
#define DHCP_SERVER_ALTPORT 1067
|
||||
@@ -72,34 +75,12 @@
|
||||
#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"
|
||||
|
||||
/* A small collection of RR-types which are missing on some platforms */
|
||||
|
||||
#ifndef T_SIG
|
||||
# define T_SIG 24
|
||||
#endif
|
||||
|
||||
#ifndef T_SRV
|
||||
# define T_SRV 33
|
||||
#endif
|
||||
|
||||
#ifndef T_OPT
|
||||
# define T_OPT 41
|
||||
#endif
|
||||
|
||||
#ifndef T_TKEY
|
||||
# define T_TKEY 249
|
||||
#endif
|
||||
|
||||
#ifndef T_TSIG
|
||||
# define T_TSIG 250
|
||||
#endif
|
||||
|
||||
|
||||
/* Follows system specific switches. If you run on a
|
||||
new system, you may want to edit these.
|
||||
May replace this with Autoconf one day.
|
||||
@@ -143,10 +124,22 @@ HAVE_SOCKADDR_SA_LEN
|
||||
define this if struct sockaddr has sa_len field (*BSD)
|
||||
|
||||
HAVE_DBUS
|
||||
Define this if you want to link against libdbus, and have dnsmasq
|
||||
define some methods to allow (re)configuration of the upstream DNS
|
||||
define this if you want to link against libdbus, and have dnsmasq
|
||||
support some methods to allow (re)configuration of the upstream DNS
|
||||
servers via DBus.
|
||||
|
||||
HAVE_IDN
|
||||
define this if you want international domain name support.
|
||||
NOTE: for backwards compatibility, IDN support is automatically
|
||||
included when internationalisation support is built, using the
|
||||
*-i18n makefile targets, even if HAVE_IDN is not explicitly set.
|
||||
|
||||
HAVE_CONNTRACK
|
||||
define this to include code which propogates conntrack marks from
|
||||
incoming DNS queries to the corresponding upstream queries. This adds
|
||||
a build-dependency on libnetfilter_conntrack, but the resulting binary will
|
||||
still run happily on a kernel without conntrack support.
|
||||
|
||||
NOTES:
|
||||
For Linux you should define
|
||||
HAVE_LINUX_NETWORK
|
||||
@@ -171,6 +164,8 @@ NOTES:
|
||||
#define HAVE_SCRIPT
|
||||
/* #define HAVE_BROKEN_RTC */
|
||||
/* #define HAVE_DBUS */
|
||||
/* #define HAVE_IDN */
|
||||
/* #define HAVE_CONNTRACK */
|
||||
|
||||
/* Allow TFTP to be disabled with COPTS=-DNO_TFTP */
|
||||
#ifdef NO_TFTP
|
||||
|
||||
90
src/conntrack.c
Normal file
90
src/conntrack.c
Normal file
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
|
||||
144
src/dhcp.c
144
src/dhcp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -19,7 +19,6 @@
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
struct iface_param {
|
||||
struct in_addr relay, primary;
|
||||
struct dhcp_context *current;
|
||||
int ind;
|
||||
};
|
||||
@@ -54,7 +53,7 @@ static int make_fd(int port)
|
||||
/* When bind-interfaces is set, there might be more than one dnmsasq
|
||||
instance binding port 67. That's OK if they serve different networks.
|
||||
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
#ifdef SO_REUSEPORT
|
||||
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
|
||||
@@ -96,7 +95,7 @@ void dhcp_init(void)
|
||||
we drop root. Also, set buffer size small, to avoid wasting
|
||||
kernel buffers */
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
if (option_bool(OPT_NO_PING))
|
||||
daemon->dhcp_icmp_fd = -1;
|
||||
else if ((daemon->dhcp_icmp_fd = make_icmp_sock()) == -1 ||
|
||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) == -1 )
|
||||
@@ -269,8 +268,6 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
for (context = daemon->dhcp; context; context = context->next)
|
||||
context->current = context;
|
||||
|
||||
parm.relay = mess->giaddr;
|
||||
parm.primary = iface_addr;
|
||||
parm.current = NULL;
|
||||
parm.ind = iface_index;
|
||||
|
||||
@@ -295,11 +292,11 @@ void dhcp_packet(time_t now, int pxe_fd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!iface_enumerate(&parm, complete_context, NULL))
|
||||
if (!iface_enumerate(AF_INET, &parm, complete_context))
|
||||
return;
|
||||
lease_prune(NULL, now); /* lose any expired leases */
|
||||
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_dns();
|
||||
|
||||
@@ -448,38 +445,27 @@ static int complete_context(struct in_addr local, int if_index,
|
||||
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) &&
|
||||
is_same_net(local, context->end, context->netmask))
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
/* link it onto the current chain if we've not seen it before */
|
||||
if (if_index == param->ind && context->current == context)
|
||||
{
|
||||
context->router = local;
|
||||
context->local = local;
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
}
|
||||
|
||||
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 = local;
|
||||
context->local = local;
|
||||
context->current = param->current;
|
||||
param->current = context;
|
||||
}
|
||||
|
||||
if (!(context->flags & CONTEXT_BRDCAST))
|
||||
{
|
||||
context->router = param->relay;
|
||||
context->local = param->primary;
|
||||
/* fill in missing broadcast addresses for relayed ranges */
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -505,7 +491,7 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
||||
start = ntohl(tmp->start.s_addr);
|
||||
end = ntohl(tmp->end.s_addr);
|
||||
|
||||
if (!(tmp->flags & CONTEXT_STATIC) &&
|
||||
if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
|
||||
addr >= start &&
|
||||
addr <= end &&
|
||||
match_netid(tmp->filter, netids, 1))
|
||||
@@ -540,7 +526,8 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||
if (!tmp)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -626,16 +613,22 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
for (pass = 0; pass <= 1; pass++)
|
||||
for (c = context; c; c = c->current)
|
||||
if (c->flags & CONTEXT_STATIC)
|
||||
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||
continue;
|
||||
else if (!match_netid(c->filter, netids, pass))
|
||||
continue;
|
||||
else
|
||||
{
|
||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||
start.s_addr = addr.s_addr =
|
||||
htonl(ntohl(c->start.s_addr) +
|
||||
((j + c->addr_epoch) % (1 + ntohl(c->end.s_addr) - ntohl(c->start.s_addr))));
|
||||
if (option_bool(OPT_CONSEC_ADDR))
|
||||
/* seed is largest extant lease addr in this context */
|
||||
start = lease_find_max_addr(c);
|
||||
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 {
|
||||
/* eliminate addresses in use by the server. */
|
||||
@@ -660,9 +653,6 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
*addrp = addr;
|
||||
|
||||
if (daemon->options & OPT_NO_PING)
|
||||
return 1;
|
||||
|
||||
/* check if we failed to ping addr sometime in the last
|
||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||
This avoids problems when a stupid client bangs
|
||||
@@ -672,33 +662,51 @@ int address_allocate(struct dhcp_context *context,
|
||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||
victim = r; /* old record */
|
||||
else if (++count == max || r->addr.s_addr == addr.s_addr)
|
||||
return 1;
|
||||
|
||||
if (icmp_ping(addr))
|
||||
/* address in use: perturb address selection so that we are
|
||||
less likely to try this address again. */
|
||||
c->addr_epoch++;
|
||||
else
|
||||
else
|
||||
{
|
||||
count++;
|
||||
if (r->addr.s_addr == addr.s_addr)
|
||||
{
|
||||
/* consec-ip mode: we offered this address for another client
|
||||
(different hash) recently, don't offer it to this one. */
|
||||
if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
|
||||
break;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!r)
|
||||
{
|
||||
/* at this point victim may hold an expired record */
|
||||
if (!victim)
|
||||
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
||||
{
|
||||
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;
|
||||
daemon->ping_results = victim;
|
||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||
{
|
||||
victim->next = daemon->ping_results;
|
||||
daemon->ping_results = victim;
|
||||
}
|
||||
}
|
||||
|
||||
/* record that this address is OK for 30s
|
||||
without more ping checks */
|
||||
if (victim)
|
||||
{
|
||||
victim->addr = addr;
|
||||
victim->time = now;
|
||||
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 +717,7 @@ int address_allocate(struct dhcp_context *context,
|
||||
|
||||
} while (addr.s_addr != start.s_addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -917,6 +926,7 @@ void dhcp_read_ethers(void)
|
||||
config->flags = CONFIG_FROM_ETHERS;
|
||||
config->hwaddr = NULL;
|
||||
config->domain = NULL;
|
||||
config->netid = NULL;
|
||||
config->next = daemon->dhcp_conf;
|
||||
daemon->dhcp_conf = config;
|
||||
}
|
||||
|
||||
91
src/dhcp_protocol.h
Normal file
91
src/dhcp_protocol.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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 BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
/* The Linux in-kernel DHCP client silently ignores any packet
|
||||
smaller than this. Sigh........... */
|
||||
#define MIN_PACKETSZ 300
|
||||
|
||||
#define OPTION_PAD 0
|
||||
#define OPTION_NETMASK 1
|
||||
#define OPTION_ROUTER 3
|
||||
#define OPTION_DNSSERVER 6
|
||||
#define OPTION_HOSTNAME 12
|
||||
#define OPTION_DOMAINNAME 15
|
||||
#define OPTION_BROADCAST 28
|
||||
#define OPTION_VENDOR_CLASS_OPT 43
|
||||
#define OPTION_REQUESTED_IP 50
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_SERVER_IDENTIFIER 54
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_MESSAGE 56
|
||||
#define OPTION_MAXMESSAGE 57
|
||||
#define OPTION_T1 58
|
||||
#define OPTION_T2 59
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_DOMAIN_SEARCH 119
|
||||
#define OPTION_SIP_SERVER 120
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
#define SUBOPT_PXE_DISCOVERY 6
|
||||
#define SUBOPT_PXE_SERVERS 8
|
||||
#define SUBOPT_PXE_MENU 9
|
||||
#define SUBOPT_PXE_MENU_PROMPT 10
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPDECLINE 4
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
|
||||
struct dhcp_packet {
|
||||
u8 op, htype, hlen, hops;
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u8 options[312];
|
||||
};
|
||||
111
src/dns_protocol.h
Normal file
111
src/dns_protocol.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/* 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 IN6ADDRSZ 16
|
||||
#define INADDRSZ 4
|
||||
|
||||
#define PACKETSZ 512 /* maximum packet size */
|
||||
#define MAXDNAME 1025 /* maximum presentation domain name */
|
||||
#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */
|
||||
#define MAXLABEL 63 /* maximum length of domain label */
|
||||
|
||||
#define NOERROR 0 /* no error */
|
||||
#define FORMERR 1 /* format error */
|
||||
#define SERVFAIL 2 /* server failure */
|
||||
#define NXDOMAIN 3 /* non existent domain */
|
||||
#define NOTIMP 4 /* not implemented */
|
||||
#define REFUSED 5 /* query refused */
|
||||
|
||||
#define QUERY 0 /* opcode */
|
||||
|
||||
#define C_IN 1 /* the arpa internet */
|
||||
#define C_CHAOS 3 /* for chaos net (MIT) */
|
||||
#define C_ANY 255 /* wildcard match */
|
||||
|
||||
#define T_A 1
|
||||
#define T_NS 2
|
||||
#define T_CNAME 5
|
||||
#define T_SOA 6
|
||||
#define T_PTR 12
|
||||
#define T_MX 15
|
||||
#define T_TXT 16
|
||||
#define T_SIG 24
|
||||
#define T_AAAA 28
|
||||
#define T_SRV 33
|
||||
#define T_NAPTR 35
|
||||
#define T_OPT 41
|
||||
#define T_TKEY 249
|
||||
#define T_TSIG 250
|
||||
#define T_MAILB 253
|
||||
#define T_ANY 255
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
u16 qdcount,ancount,nscount,arcount;
|
||||
};
|
||||
|
||||
#define HB3_QR 0x80
|
||||
#define HB3_OPCODE 0x78
|
||||
#define HB3_AA 0x04
|
||||
#define HB3_TC 0x02
|
||||
#define HB3_RD 0x01
|
||||
|
||||
#define HB4_RA 0x80
|
||||
#define HB4_AD 0x20
|
||||
#define HB4_CD 0x10
|
||||
#define HB4_RCODE 0x0f
|
||||
|
||||
#define OPCODE(x) (((x)->hb3 & HB3_OPCODE) >> 3)
|
||||
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
|
||||
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
|
||||
|
||||
#define GETSHORT(s, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(s) = ((u16)t_cp[0] << 8) \
|
||||
| ((u16)t_cp[1]) \
|
||||
; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define GETLONG(l, cp) { \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
(l) = ((u32)t_cp[0] << 24) \
|
||||
| ((u32)t_cp[1] << 16) \
|
||||
| ((u32)t_cp[2] << 8) \
|
||||
| ((u32)t_cp[3]) \
|
||||
; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
#define PUTSHORT(s, cp) { \
|
||||
u16 t_s = (u16)(s); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_s >> 8; \
|
||||
*t_cp = t_s; \
|
||||
(cp) += 2; \
|
||||
}
|
||||
|
||||
#define PUTLONG(l, cp) { \
|
||||
u32 t_l = (u32)(l); \
|
||||
unsigned char *t_cp = (unsigned char *)(cp); \
|
||||
*t_cp++ = t_l >> 24; \
|
||||
*t_cp++ = t_l >> 16; \
|
||||
*t_cp++ = t_l >> 8; \
|
||||
*t_cp = t_l; \
|
||||
(cp) += 4; \
|
||||
}
|
||||
|
||||
101
src/dnsmasq.c
101
src/dnsmasq.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -40,7 +40,7 @@ static char *compile_opts =
|
||||
#ifndef LOCALEDIR
|
||||
"no-"
|
||||
#endif
|
||||
"I18N "
|
||||
"i18n "
|
||||
#ifndef HAVE_DHCP
|
||||
"no-"
|
||||
#endif
|
||||
@@ -51,8 +51,15 @@ static char *compile_opts =
|
||||
#ifndef HAVE_TFTP
|
||||
"no-"
|
||||
#endif
|
||||
"TFTP";
|
||||
|
||||
"TFTP "
|
||||
#ifndef HAVE_CONNTRACK
|
||||
"no-"
|
||||
#endif
|
||||
"conntrack "
|
||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||
"no-"
|
||||
#endif
|
||||
"IDN";
|
||||
|
||||
|
||||
static volatile pid_t pid = 0;
|
||||
@@ -133,10 +140,10 @@ int main (int argc, char **argv)
|
||||
#elif !(defined(IP_RECVDSTADDR) && \
|
||||
defined(IP_RECVIF) && \
|
||||
defined(IP_SENDSRCADDR))
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
bind_fallback = 1;
|
||||
daemon->options |= OPT_NOWILD;
|
||||
set_option_bool(OPT_NOWILD);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -145,11 +152,24 @@ int main (int argc, char **argv)
|
||||
die(_("TFTP server not available: set HAVE_TFTP in src/config.h"), NULL, EC_BADCONF);
|
||||
#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
|
||||
if (daemon->max_logs != 0)
|
||||
die(_("asychronous logging is not available under Solaris"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (daemon->max_logs != 0)
|
||||
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
|
||||
#endif
|
||||
|
||||
rand_init();
|
||||
|
||||
now = dnsmasq_time();
|
||||
@@ -168,7 +188,7 @@ int main (int argc, char **argv)
|
||||
if (!enumerate_interfaces())
|
||||
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
daemon->listeners = create_bound_listeners();
|
||||
|
||||
@@ -183,14 +203,13 @@ int main (int argc, char **argv)
|
||||
die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
}
|
||||
else if ((daemon->port != 0 || daemon->tftp_interfaces || daemon->tftp_unlimited) &&
|
||||
!(daemon->listeners = create_wildcard_listeners()))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
else
|
||||
daemon->listeners = create_wildcard_listeners();
|
||||
|
||||
if (daemon->port != 0)
|
||||
cache_init();
|
||||
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
#ifdef HAVE_DBUS
|
||||
{
|
||||
char *err;
|
||||
@@ -275,7 +294,7 @@ int main (int argc, char **argv)
|
||||
|
||||
err_pipe[1] = -1;
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* The following code "daemonizes" the process.
|
||||
See Stevens section 12.4 */
|
||||
@@ -284,7 +303,7 @@ int main (int argc, char **argv)
|
||||
die(_("cannot chdir to filesystem root: %s"), NULL, EC_MISC);
|
||||
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_NO_FORK))
|
||||
if (!option_bool(OPT_NO_FORK))
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
@@ -345,7 +364,7 @@ int main (int argc, char **argv)
|
||||
|
||||
log_err = log_start(ent_pw, err_pipe[1]);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* open stdout etc to /dev/null */
|
||||
int nullfd = open("/dev/null", O_RDWR);
|
||||
@@ -362,7 +381,7 @@ int main (int argc, char **argv)
|
||||
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && getuid() == 0)
|
||||
if (!option_bool(OPT_DEBUG) && getuid() == 0)
|
||||
{
|
||||
int bad_capabilities = 0;
|
||||
gid_t dummy;
|
||||
@@ -385,7 +404,7 @@ int main (int argc, char **argv)
|
||||
(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW) | (1 << CAP_SETUID);
|
||||
|
||||
/* Tell kernel to not clear capabilities when dropping root */
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1) == -1)
|
||||
if (capset(hdr, data) == -1 || prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
|
||||
bad_capabilities = errno;
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
@@ -440,8 +459,8 @@ int main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (daemon->options & OPT_DEBUG)
|
||||
prctl(PR_SET_DUMPABLE, 1);
|
||||
if (option_bool(OPT_DEBUG))
|
||||
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
|
||||
#endif
|
||||
|
||||
if (daemon->port == 0)
|
||||
@@ -454,7 +473,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
if (daemon->options & OPT_DBUS)
|
||||
if (option_bool(OPT_DBUS))
|
||||
{
|
||||
if (daemon->dbus)
|
||||
my_syslog(LOG_INFO, _("DBus support enabled: connected to system bus"));
|
||||
@@ -470,12 +489,12 @@ int main (int argc, char **argv)
|
||||
if (bind_fallback)
|
||||
my_syslog(LOG_WARNING, _("setting --bind-interfaces option because of OS limitations"));
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
my_syslog(LOG_WARNING, _("warning: interface %s does not currently exist"), if_tmp->name);
|
||||
|
||||
if (daemon->port != 0 && (daemon->options & OPT_NO_RESOLV))
|
||||
if (daemon->port != 0 && option_bool(OPT_NO_RESOLV))
|
||||
{
|
||||
if (daemon->resolv_files && !daemon->resolv_files->is_default)
|
||||
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
|
||||
@@ -518,7 +537,7 @@ int main (int argc, char **argv)
|
||||
my_syslog(MS_TFTP | LOG_INFO, "TFTP %s%s %s",
|
||||
daemon->tftp_prefix ? _("root is ") : _("enabled"),
|
||||
daemon->tftp_prefix ? daemon->tftp_prefix: "",
|
||||
daemon->options & OPT_TFTP_SECURE ? _("secure mode") : "");
|
||||
option_bool(OPT_TFTP_SECURE) ? _("secure mode") : "");
|
||||
|
||||
/* This is a guess, it assumes that for small limits,
|
||||
disjoint files might be served, but for large limits,
|
||||
@@ -580,7 +599,7 @@ int main (int argc, char **argv)
|
||||
|
||||
/* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */
|
||||
if (daemon->tftp_trans ||
|
||||
((daemon->options & OPT_DBUS) && !daemon->dbus))
|
||||
(option_bool(OPT_DBUS) && !daemon->dbus))
|
||||
{
|
||||
t.tv_sec = 0;
|
||||
t.tv_usec = 250000;
|
||||
@@ -641,6 +660,11 @@ int main (int argc, char **argv)
|
||||
|
||||
check_log_writer(&wset);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
#endif
|
||||
|
||||
/* Check for changes to resolv files once per second max. */
|
||||
/* Don't go silent for long periods if the clock goes backwards. */
|
||||
if (daemon->last_resolv == 0 ||
|
||||
@@ -657,14 +681,9 @@ int main (int argc, char **argv)
|
||||
if (FD_ISSET(piperead, &rset))
|
||||
async_event(piperead, now);
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
if (FD_ISSET(daemon->netlinkfd, &rset))
|
||||
netlink_multicast();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DBUS
|
||||
/* if we didn't create a DBus connection, retry now. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
{
|
||||
char *err;
|
||||
if ((err = dbus_init()))
|
||||
@@ -801,7 +820,7 @@ static void async_event(int pipe, time_t now)
|
||||
{
|
||||
case EVENT_RELOAD:
|
||||
clear_cache_and_reload(now);
|
||||
if (daemon->port != 0 && daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port != 0 && daemon->resolv_files && option_bool(OPT_NO_POLL))
|
||||
{
|
||||
reload_servers(daemon->resolv_files->name);
|
||||
check_servers();
|
||||
@@ -908,7 +927,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
Go through and find the one which changed _last_.
|
||||
Warn of any which can't be read. */
|
||||
|
||||
if (daemon->port == 0 || (daemon->options & OPT_NO_POLL))
|
||||
if (daemon->port == 0 || option_bool(OPT_NO_POLL))
|
||||
return;
|
||||
|
||||
for (latest = NULL, res = daemon->resolv_files; res; res = res->next)
|
||||
@@ -954,7 +973,7 @@ void poll_resolv(int force, int do_reload, time_t now)
|
||||
my_syslog(LOG_INFO, _("reading %s"), latest->name);
|
||||
warned = 0;
|
||||
check_servers();
|
||||
if ((daemon->options & OPT_RELOAD) && do_reload)
|
||||
if (option_bool(OPT_RELOAD) && do_reload)
|
||||
clear_cache_and_reload(now);
|
||||
}
|
||||
else
|
||||
@@ -977,7 +996,7 @@ void clear_cache_and_reload(time_t now)
|
||||
#ifdef HAVE_DHCP
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
if (daemon->options & OPT_ETHERS)
|
||||
if (option_bool(OPT_ETHERS))
|
||||
dhcp_read_ethers();
|
||||
reread_dhcp();
|
||||
dhcp_update_configs(daemon->dhcp_conf);
|
||||
@@ -1094,7 +1113,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if (confd == -1)
|
||||
continue;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface;
|
||||
else
|
||||
{
|
||||
@@ -1120,7 +1139,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(confd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
else if (!(daemon->options & OPT_DEBUG) && (p = fork()) != 0)
|
||||
else if (!option_bool(OPT_DEBUG) && (p = fork()) != 0)
|
||||
{
|
||||
if (p != -1)
|
||||
{
|
||||
@@ -1140,14 +1159,11 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
unsigned char *buff;
|
||||
struct server *s;
|
||||
int flags;
|
||||
struct in_addr dst_addr_4;
|
||||
|
||||
dst_addr_4.s_addr = 0;
|
||||
|
||||
#ifndef NO_FORK
|
||||
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
alarm(CHILD_LIFETIME);
|
||||
#endif
|
||||
|
||||
@@ -1161,10 +1177,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
|
||||
if (listener->family == AF_INET)
|
||||
dst_addr_4 = iface->addr.in.sin_addr;
|
||||
|
||||
buff = tcp_request(confd, now, dst_addr_4, iface->netmask);
|
||||
buff = tcp_request(confd, now, &iface->addr, iface->netmask);
|
||||
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
@@ -1179,7 +1192,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
|
||||
close(s->tcpfd);
|
||||
}
|
||||
#ifndef NO_FORK
|
||||
if (!(daemon->options & OPT_DEBUG))
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
flush_log();
|
||||
_exit(0);
|
||||
|
||||
209
src/dnsmasq.h
209
src/dnsmasq.h
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -14,7 +14,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define COPYRIGHT "Copyright (c) 2000-2010 Simon Kelley"
|
||||
#define COPYRIGHT "Copyright (c) 2000-2011 Simon Kelley"
|
||||
|
||||
#ifndef NO_LARGEFILE
|
||||
/* Ensure we can use files >2GB (log files may grow this big) */
|
||||
@@ -24,7 +24,9 @@
|
||||
|
||||
/* Get linux C library versions and define _GNU_SOURCE for kFreeBSD. */
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
# define _GNU_SOURCE
|
||||
# ifndef __ANDROID__
|
||||
# define _GNU_SOURCE
|
||||
# endif
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
@@ -39,18 +41,18 @@
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <nameser.h>
|
||||
# include <arpa/nameser_compat.h>
|
||||
#else
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
|
||||
/* and this. */
|
||||
#include <getopt.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
#include "dns_protocol.h"
|
||||
#include "dhcp_protocol.h"
|
||||
|
||||
#define gettext_noop(S) (S)
|
||||
#ifndef LOCALEDIR
|
||||
# define _(S) (S)
|
||||
@@ -89,7 +91,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun)
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined (__sun) || defined (__ANDROID__)
|
||||
# include <netinet/if_ether.h>
|
||||
#else
|
||||
# include <net/ethernet.h>
|
||||
@@ -163,38 +165,46 @@ struct event_desc {
|
||||
*/
|
||||
#define DNSMASQ_PACKETSZ PACKETSZ+MAXDNAME+RRFIXEDSZ
|
||||
|
||||
#define OPT_BOGUSPRIV (1u<<0)
|
||||
#define OPT_FILTER (1u<<1)
|
||||
#define OPT_LOG (1u<<2)
|
||||
#define OPT_SELFMX (1u<<3)
|
||||
#define OPT_NO_HOSTS (1u<<4)
|
||||
#define OPT_NO_POLL (1u<<5)
|
||||
#define OPT_DEBUG (1u<<6)
|
||||
#define OPT_ORDER (1u<<7)
|
||||
#define OPT_NO_RESOLV (1u<<8)
|
||||
#define OPT_EXPAND (1u<<9)
|
||||
#define OPT_LOCALMX (1u<<10)
|
||||
#define OPT_NO_NEG (1u<<11)
|
||||
#define OPT_NODOTS_LOCAL (1u<<12)
|
||||
#define OPT_NOWILD (1u<<13)
|
||||
#define OPT_ETHERS (1u<<14)
|
||||
#define OPT_RESOLV_DOMAIN (1u<<15)
|
||||
#define OPT_NO_FORK (1u<<16)
|
||||
#define OPT_AUTHORITATIVE (1u<<17)
|
||||
#define OPT_LOCALISE (1u<<18)
|
||||
#define OPT_DBUS (1u<<19)
|
||||
#define OPT_DHCP_FQDN (1u<<20)
|
||||
#define OPT_NO_PING (1u<<21)
|
||||
#define OPT_LEASE_RO (1u<<22)
|
||||
#define OPT_ALL_SERVERS (1u<<23)
|
||||
#define OPT_RELOAD (1u<<24)
|
||||
#define OPT_LOCAL_REBIND (1u<<25)
|
||||
#define OPT_TFTP_SECURE (1u<<26)
|
||||
#define OPT_TFTP_NOBLOCK (1u<<27)
|
||||
#define OPT_LOG_OPTS (1u<<28)
|
||||
#define OPT_TFTP_APREF (1u<<29)
|
||||
#define OPT_NO_OVERRIDE (1u<<30)
|
||||
#define OPT_NO_REBIND (1u<<31)
|
||||
/* Trust the compiler dead-code eliminator.... */
|
||||
#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
|
||||
|
||||
#define OPT_BOGUSPRIV 0
|
||||
#define OPT_FILTER 1
|
||||
#define OPT_LOG 2
|
||||
#define OPT_SELFMX 3
|
||||
#define OPT_NO_HOSTS 4
|
||||
#define OPT_NO_POLL 5
|
||||
#define OPT_DEBUG 6
|
||||
#define OPT_ORDER 7
|
||||
#define OPT_NO_RESOLV 8
|
||||
#define OPT_EXPAND 9
|
||||
#define OPT_LOCALMX 10
|
||||
#define OPT_NO_NEG 11
|
||||
#define OPT_NODOTS_LOCAL 12
|
||||
#define OPT_NOWILD 13
|
||||
#define OPT_ETHERS 14
|
||||
#define OPT_RESOLV_DOMAIN 15
|
||||
#define OPT_NO_FORK 16
|
||||
#define OPT_AUTHORITATIVE 17
|
||||
#define OPT_LOCALISE 18
|
||||
#define OPT_DBUS 19
|
||||
#define OPT_DHCP_FQDN 20
|
||||
#define OPT_NO_PING 21
|
||||
#define OPT_LEASE_RO 22
|
||||
#define OPT_ALL_SERVERS 23
|
||||
#define OPT_RELOAD 24
|
||||
#define OPT_LOCAL_REBIND 25
|
||||
#define OPT_TFTP_SECURE 26
|
||||
#define OPT_TFTP_NOBLOCK 27
|
||||
#define OPT_LOG_OPTS 28
|
||||
#define OPT_TFTP_APREF 29
|
||||
#define OPT_NO_OVERRIDE 30
|
||||
#define OPT_NO_REBIND 31
|
||||
#define OPT_ADD_MAC 32
|
||||
#define OPT_DNSSEC 33
|
||||
#define OPT_CONSEC_ADDR 34
|
||||
#define OPT_CONNTRACK 35
|
||||
#define OPT_LAST 36
|
||||
|
||||
/* 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. */
|
||||
@@ -235,7 +245,8 @@ struct naptr {
|
||||
};
|
||||
|
||||
struct txt_record {
|
||||
char *name, *txt;
|
||||
char *name;
|
||||
unsigned char *txt;
|
||||
unsigned short class, len;
|
||||
struct txt_record *next;
|
||||
};
|
||||
@@ -280,22 +291,27 @@ struct crec {
|
||||
} name;
|
||||
};
|
||||
|
||||
#define F_IMMORTAL 1
|
||||
#define F_CONFIG 2
|
||||
#define F_REVERSE 4
|
||||
#define F_FORWARD 8
|
||||
#define F_DHCP 16
|
||||
#define F_NEG 32
|
||||
#define F_HOSTS 64
|
||||
#define F_IPV4 128
|
||||
#define F_IPV6 256
|
||||
#define F_BIGNAME 512
|
||||
#define F_UPSTREAM 1024
|
||||
#define F_SERVER 2048
|
||||
#define F_NXDOMAIN 4096
|
||||
#define F_QUERY 8192
|
||||
#define F_CNAME 16384
|
||||
#define F_NOERR 32768
|
||||
#define F_IMMORTAL (1u<<0)
|
||||
#define F_NAMEP (1u<<1)
|
||||
#define F_REVERSE (1u<<2)
|
||||
#define F_FORWARD (1u<<3)
|
||||
#define F_DHCP (1u<<4)
|
||||
#define F_NEG (1u<<5)
|
||||
#define F_HOSTS (1u<<6)
|
||||
#define F_IPV4 (1u<<7)
|
||||
#define F_IPV6 (1u<<8)
|
||||
#define F_BIGNAME (1u<<9)
|
||||
#define F_NXDOMAIN (1u<<10)
|
||||
#define F_CNAME (1u<<11)
|
||||
#define F_NOERR (1u<<12)
|
||||
#define F_CONFIG (1u<<13)
|
||||
/* below here are only valid as args to log_query: cache
|
||||
entries are limited to 16 bits */
|
||||
#define F_UPSTREAM (1u<<16)
|
||||
#define F_RRNAME (1u<<17)
|
||||
#define F_SERVER (1u<<18)
|
||||
#define F_QUERY (1u<<19)
|
||||
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -374,7 +390,7 @@ struct resolvc {
|
||||
char *name;
|
||||
};
|
||||
|
||||
/* adn-hosts parms from command-line */
|
||||
/* adn-hosts parms from command-line (also dhcp-hostsfile and dhcp-optsfile */
|
||||
#define AH_DIR 1
|
||||
#define AH_INACTIVE 2
|
||||
struct hostsfile {
|
||||
@@ -384,6 +400,9 @@ struct hostsfile {
|
||||
int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
struct all_addr dest;
|
||||
@@ -394,7 +413,7 @@ struct frec {
|
||||
#endif
|
||||
unsigned int iface;
|
||||
unsigned short orig_id, new_id;
|
||||
int fd, forwardall, norebind;
|
||||
int fd, forwardall, flags;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
struct frec *next;
|
||||
@@ -406,8 +425,6 @@ struct frec {
|
||||
#define ACTION_OLD 3
|
||||
#define ACTION_ADD 4
|
||||
|
||||
#define DHCP_CHADDR_MAX 16
|
||||
|
||||
struct dhcp_lease {
|
||||
int clid_len; /* length of client identifier */
|
||||
unsigned char *clid; /* clientid */
|
||||
@@ -501,9 +518,10 @@ struct dhcp_opt {
|
||||
#define DHOPT_HEX 512
|
||||
#define DHOPT_VENDOR_MATCH 1024
|
||||
#define DHOPT_RFC3925 2048
|
||||
#define DHOPT_TAGOK 4096
|
||||
|
||||
struct dhcp_boot {
|
||||
char *file, *sname;
|
||||
char *file, *sname, *tftp_sname;
|
||||
struct in_addr next_server;
|
||||
struct dhcp_netid *netid;
|
||||
struct dhcp_boot *next;
|
||||
@@ -566,24 +584,10 @@ struct dhcp_context {
|
||||
#define CONTEXT_BRDCAST 4
|
||||
#define CONTEXT_PROXY 8
|
||||
|
||||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
|
||||
struct dhcp_packet {
|
||||
u8 op, htype, hlen, hops;
|
||||
u32 xid;
|
||||
u16 secs, flags;
|
||||
struct in_addr ciaddr, yiaddr, siaddr, giaddr;
|
||||
u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
|
||||
u8 options[312];
|
||||
};
|
||||
|
||||
struct ping_result {
|
||||
struct in_addr addr;
|
||||
time_t time;
|
||||
unsigned int hash;
|
||||
struct ping_result *next;
|
||||
};
|
||||
|
||||
@@ -601,7 +605,7 @@ struct tftp_transfer {
|
||||
int backoff;
|
||||
unsigned int block, blocksize, expansion;
|
||||
off_t offset;
|
||||
struct sockaddr_in peer;
|
||||
union mysockaddr peer;
|
||||
char opt_blocksize, opt_transize, netascii, carrylf;
|
||||
struct tftp_file *file;
|
||||
struct tftp_transfer *next;
|
||||
@@ -629,7 +633,7 @@ extern struct daemon {
|
||||
config file arguments. All set (including defaults)
|
||||
in option.c */
|
||||
|
||||
unsigned int options;
|
||||
unsigned int options, options2;
|
||||
struct resolvc default_resolv, *resolv_files;
|
||||
time_t last_resolv;
|
||||
struct mx_srv_record *mxnames;
|
||||
@@ -669,7 +673,7 @@ extern struct daemon {
|
||||
int enable_pxe;
|
||||
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
|
||||
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
|
||||
char *dhcp_hosts_file, *dhcp_opts_file;
|
||||
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
|
||||
int dhcp_max, tftp_max;
|
||||
int dhcp_server_port, dhcp_client_port;
|
||||
int start_tftp_port, end_tftp_port;
|
||||
@@ -727,7 +731,7 @@ extern struct daemon {
|
||||
|
||||
/* cache.c */
|
||||
void cache_init(void);
|
||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, char *arg);
|
||||
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
|
||||
char *record_source(int index);
|
||||
void querystr(char *str, unsigned short type);
|
||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||
@@ -741,29 +745,31 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||
time_t now, unsigned long ttl, unsigned short flags);
|
||||
void cache_reload(void);
|
||||
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 dump_cache(time_t now);
|
||||
char *cache_get_name(struct crec *crecp);
|
||||
char *get_domain(struct in_addr addr);
|
||||
|
||||
/* rfc1035.c */
|
||||
unsigned short extract_request(HEADER *header, size_t qlen,
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags,
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags,
|
||||
unsigned long local_ttl);
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind);
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
|
||||
time_t now, int is_sign, int checkrebind, int checking_disabled);
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now);
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *addr, time_t now);
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen,
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
|
||||
size_t *len, unsigned char **p, int *is_sign);
|
||||
int check_for_local_domain(char *name, time_t now);
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *buff);
|
||||
size_t resize_packet(HEADER *header, size_t plen,
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
|
||||
size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -804,12 +810,14 @@ void flush_log(void);
|
||||
void read_opts (int argc, char **argv, char *compile_opts);
|
||||
char *option_string(unsigned char opt, int *is_ip, int *is_name);
|
||||
void reread_dhcp(void);
|
||||
void set_option_bool(unsigned int opt);
|
||||
struct hostsfile *expand_filelist(struct hostsfile *list);
|
||||
|
||||
/* forward.c */
|
||||
void reply_query(int fd, int family, time_t now);
|
||||
void receive_query(struct listener *listen, 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);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
|
||||
@@ -871,6 +879,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,
|
||||
unsigned char *clid, int clid_len);
|
||||
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_update_from_configs(void);
|
||||
int do_script_run(time_t now);
|
||||
@@ -880,7 +889,7 @@ void rerun_scripts(void);
|
||||
/* rfc2131.c */
|
||||
#ifdef HAVE_DHCP
|
||||
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,
|
||||
int clid_len, unsigned char *clid, int *len_out);
|
||||
#endif
|
||||
@@ -908,7 +917,7 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
|
||||
#endif
|
||||
|
||||
/* bpf.c or netlink.c */
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)());
|
||||
int iface_enumerate(int family, void *parm, int (callback)());
|
||||
|
||||
/* dbus.c */
|
||||
#ifdef HAVE_DBUS
|
||||
@@ -934,3 +943,9 @@ int helper_buf_empty(void);
|
||||
void tftp_request(struct listener *listen, time_t now);
|
||||
void check_tftp_listeners(fd_set *rset, time_t now);
|
||||
#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
|
||||
|
||||
304
src/forward.c
304
src/forward.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -111,8 +111,8 @@ static void send_from(int fd, int nowild, char *packet, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned short qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
static unsigned int search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind)
|
||||
|
||||
{
|
||||
/* If the query ends in the domain in one of our servers, set
|
||||
@@ -122,13 +122,13 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
unsigned int namelen = strlen(qdomain);
|
||||
unsigned int matchlen = 0;
|
||||
struct server *serv;
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
|
||||
for (serv = daemon->servers; serv; serv=serv->next)
|
||||
/* domain matches take priority over NODOTS matches */
|
||||
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.') && namelen != 0)
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = SERV_FOR_NODOTS;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
@@ -158,39 +158,59 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
{
|
||||
if (serv->flags & SERV_NO_REBIND)
|
||||
*norebind = 1;
|
||||
else if (domainlen >= matchlen)
|
||||
else
|
||||
{
|
||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
unsigned int sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||
/* implement priority rules for --address and --server for same domain.
|
||||
--address wins if the address is for the correct AF
|
||||
--server wins otherwise. */
|
||||
if (domainlen != 0 && domainlen == matchlen)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
if ((serv->flags & SERV_LITERAL_ADDRESS))
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
if (!(sflag & qtype) && flags == 0)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags & (F_IPV4 | F_IPV6))
|
||||
continue;
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
if (domainlen >= matchlen)
|
||||
{
|
||||
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND);
|
||||
*domain = serv->domain;
|
||||
matchlen = domainlen;
|
||||
if (serv->flags & SERV_NO_ADDR)
|
||||
flags = F_NXDOMAIN;
|
||||
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||
{
|
||||
if (sflag & qtype)
|
||||
{
|
||||
flags = sflag;
|
||||
if (serv->addr.sa.sa_family == AF_INET)
|
||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||
#endif
|
||||
}
|
||||
else if (!flags || (flags & F_NXDOMAIN))
|
||||
flags = F_NOERR;
|
||||
}
|
||||
else
|
||||
flags = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flags == 0 && !(qtype & F_BIGNAME) &&
|
||||
(daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward simple names, make exception for NS queries and empty name. */
|
||||
flags = F_NXDOMAIN;
|
||||
if (flags == 0 && !(qtype & F_QUERY) &&
|
||||
option_bool(OPT_NODOTS_LOCAL) && !strchr(qdomain, '.') && namelen != 0)
|
||||
/* don't forward A or AAAA queries for simple names, except the empty name */
|
||||
flags = F_NOERR;
|
||||
|
||||
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now))
|
||||
flags = F_NOERR;
|
||||
@@ -214,16 +234,19 @@ static unsigned short search_servers(time_t now, struct all_addr **addrpp,
|
||||
|
||||
static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
struct all_addr *dst_addr, unsigned int dst_iface,
|
||||
HEADER *header, size_t plen, time_t now, struct frec *forward)
|
||||
struct dns_header *header, size_t plen, time_t now, struct frec *forward)
|
||||
{
|
||||
char *domain = NULL;
|
||||
int type = 0, norebind = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
unsigned int crc = questions_crc(header, plen, daemon->namebuff);
|
||||
unsigned short flags = 0;
|
||||
unsigned short gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
unsigned int flags = 0;
|
||||
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
|
||||
struct server *start = NULL;
|
||||
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
/* may be no servers available. */
|
||||
if (!daemon->servers)
|
||||
forward = NULL;
|
||||
@@ -232,7 +255,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* retry on existing query, send to all available servers */
|
||||
domain = forward->sentto->domain;
|
||||
forward->sentto->failed_queries++;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
{
|
||||
forward->forwardall = 1;
|
||||
daemon->last_server = NULL;
|
||||
@@ -261,9 +284,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
forward->fd = udpfd;
|
||||
forward->crc = crc;
|
||||
forward->forwardall = 0;
|
||||
forward->norebind = norebind;
|
||||
header->id = htons(forward->new_id);
|
||||
if (norebind)
|
||||
forward->flags |= FREC_NOREBIND;
|
||||
if (header->hb4 & HB4_CD)
|
||||
forward->flags |= FREC_CHECKING_DISABLED;
|
||||
|
||||
header->id = htons(forward->new_id);
|
||||
|
||||
/* In strict_order mode, always try servers in the order
|
||||
specified in resolv.conf, if a domain is given
|
||||
always try all the available servers,
|
||||
@@ -271,7 +298,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
if (type == 0)
|
||||
{
|
||||
if (daemon->options & OPT_ORDER)
|
||||
if (option_bool(OPT_ORDER))
|
||||
start = daemon->servers;
|
||||
else if (!(start = daemon->last_server) ||
|
||||
daemon->forwardcount++ > FORWARD_TEST ||
|
||||
@@ -286,7 +313,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
else
|
||||
{
|
||||
start = daemon->servers;
|
||||
if (!(daemon->options & OPT_ORDER))
|
||||
if (!option_bool(OPT_ORDER))
|
||||
forward->forwardall = 1;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +327,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
{
|
||||
struct server *firstsentto = start;
|
||||
int forwarded = 0;
|
||||
|
||||
|
||||
if (udpaddr && option_bool(OPT_ADD_MAC))
|
||||
plen = add_mac(header, plen, ((char *) header) + PACKETSZ, udpaddr);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* only send to servers dealing with our domain.
|
||||
@@ -336,6 +366,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
daemon->rfd_save = forward->rfd4;
|
||||
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,
|
||||
@@ -389,14 +429,14 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (udpfd != -1)
|
||||
{
|
||||
plen = setup_reply(header, plen, addrp, flags, daemon->local_ttl);
|
||||
send_from(udpfd, daemon->options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
send_from(udpfd, option_bool(OPT_NOWILD), (char *)header, plen, udpaddr, dst_addr, dst_iface);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t process_reply(HEADER *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind)
|
||||
static size_t process_reply(struct dns_header *header, time_t now,
|
||||
struct server *server, size_t n, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
int munged = 0, is_sign;
|
||||
@@ -416,29 +456,33 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
PUTSHORT(daemon->edns_pktsz, psave);
|
||||
}
|
||||
|
||||
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||
/* RFC 4035 sect 4.6 para 3 */
|
||||
if (!is_sign && !option_bool(OPT_DNSSEC))
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||
return n;
|
||||
|
||||
/* Complain loudly if the upstream server is non-recursive. */
|
||||
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0 &&
|
||||
if (!(header->hb4 & HB4_RA) && RCODE(header) == NOERROR && ntohs(header->ancount) == 0 &&
|
||||
server && !(server->flags & SERV_WARNED_RECURSIVE))
|
||||
{
|
||||
prettyprint_addr(&server->addr, daemon->namebuff);
|
||||
my_syslog(LOG_WARNING, _("nameserver %s refused to do a recursive query"), daemon->namebuff);
|
||||
if (!(daemon->options & OPT_LOG))
|
||||
if (!option_bool(OPT_LOG))
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
|
||||
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||
{
|
||||
munged = 1;
|
||||
header->rcode = NXDOMAIN;
|
||||
header->aa = 0;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
header->hb3 &= ~HB3_AA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (header->rcode == NXDOMAIN &&
|
||||
if (RCODE(header) == NXDOMAIN &&
|
||||
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||
check_for_local_domain(daemon->namebuff, now))
|
||||
{
|
||||
@@ -446,11 +490,11 @@ static size_t process_reply(HEADER *header, time_t now,
|
||||
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||
since we know that the domain exists, even if upstream doesn't */
|
||||
munged = 1;
|
||||
header->aa = 1;
|
||||
header->rcode = NOERROR;
|
||||
header->hb3 |= HB3_AA;
|
||||
SET_RCODE(header, NOERROR);
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, is_sign, check_rebind, checking_disabled))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -478,7 +522,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
{
|
||||
/* packet from peer server, extract data for cache, and send to
|
||||
original requester */
|
||||
HEADER *header;
|
||||
struct dns_header *header;
|
||||
union mysockaddr serveraddr;
|
||||
struct frec *forward;
|
||||
socklen_t addrlen = sizeof(serveraddr);
|
||||
@@ -502,17 +546,17 @@ void reply_query(int fd, int family, time_t now)
|
||||
sockaddr_isequal(&server->addr, &serveraddr))
|
||||
break;
|
||||
|
||||
header = (HEADER *)daemon->packet;
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
|
||||
if (!server ||
|
||||
n < (int)sizeof(HEADER) || !header->qr ||
|
||||
n < (int)sizeof(struct dns_header) || !(header->hb3 & HB3_QR) ||
|
||||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||
return;
|
||||
|
||||
server = forward->sentto;
|
||||
|
||||
if ((header->rcode == SERVFAIL || header->rcode == REFUSED) &&
|
||||
!(daemon->options & OPT_ORDER) &&
|
||||
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
/* for broken servers, attempt to send to another one. */
|
||||
{
|
||||
@@ -529,8 +573,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
header->arcount = htons(0);
|
||||
if ((nn = resize_packet(header, (size_t)n, pheader, plen)))
|
||||
{
|
||||
header->qr = 0;
|
||||
header->tc = 0;
|
||||
header->hb3 &= ~(HB3_QR | HB3_TC);
|
||||
forward_query(-1, NULL, NULL, 0, header, nn, now, forward);
|
||||
return;
|
||||
}
|
||||
@@ -539,7 +582,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
if (header->rcode == SERVFAIL || header->rcode == REFUSED)
|
||||
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
|
||||
server = NULL;
|
||||
else
|
||||
{
|
||||
@@ -554,7 +597,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(daemon->options & OPT_ALL_SERVERS))
|
||||
if (!option_bool(OPT_ALL_SERVERS))
|
||||
daemon->last_server = server;
|
||||
}
|
||||
|
||||
@@ -563,18 +606,18 @@ void reply_query(int fd, int family, time_t now)
|
||||
had replies from all to avoid filling the forwarding table when
|
||||
everything is broken */
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(header->rcode != REFUSED && header->rcode != SERVFAIL))
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
{
|
||||
int check_rebind = !forward->norebind;
|
||||
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
if (!(daemon->options & OPT_NO_REBIND))
|
||||
if (!option_bool(OPT_NO_REBIND))
|
||||
check_rebind = 0;
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind)))
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
header->ra = 1; /* recursion if available */
|
||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, nn,
|
||||
header->hb4 |= HB4_RA; /* recursion if available */
|
||||
send_from(forward->fd, option_bool(OPT_NOWILD), daemon->packet, nn,
|
||||
&forward->source, &forward->dest, forward->iface);
|
||||
}
|
||||
free_frec(forward); /* cancel */
|
||||
@@ -584,7 +627,7 @@ void reply_query(int fd, int family, time_t now)
|
||||
|
||||
void receive_query(struct listener *listen, time_t now)
|
||||
{
|
||||
HEADER *header = (HEADER *)daemon->packet;
|
||||
struct dns_header *header = (struct dns_header *)daemon->packet;
|
||||
union mysockaddr source_addr;
|
||||
unsigned short type;
|
||||
struct all_addr dst_addr;
|
||||
@@ -614,7 +657,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
/* packet buffer overwritten */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (listen->family == AF_INET && (daemon->options & OPT_NOWILD))
|
||||
if (listen->family == AF_INET && option_bool(OPT_NOWILD))
|
||||
{
|
||||
dst_addr_4 = listen->iface->addr.in.sin_addr;
|
||||
netmask = listen->iface->netmask;
|
||||
@@ -639,9 +682,9 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||
return;
|
||||
|
||||
if (n < (int)sizeof(HEADER) ||
|
||||
if (n < (int)sizeof(struct dns_header) ||
|
||||
(msg.msg_flags & MSG_TRUNC) ||
|
||||
header->qr)
|
||||
(header->hb3 & HB3_QR))
|
||||
return;
|
||||
|
||||
source_addr.sa.sa_family = listen->family;
|
||||
@@ -649,8 +692,8 @@ void receive_query(struct listener *listen, time_t now)
|
||||
if (listen->family == AF_INET6)
|
||||
source_addr.in6.sin6_flowinfo = 0;
|
||||
#endif
|
||||
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
@@ -721,7 +764,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
return;
|
||||
|
||||
if (listen->family == AF_INET &&
|
||||
(daemon->options & OPT_LOCALISE) &&
|
||||
option_bool(OPT_LOCALISE) &&
|
||||
ioctl(listen->fd, SIOCGIFNETMASK, &ifr) == -1)
|
||||
return;
|
||||
|
||||
@@ -748,7 +791,7 @@ void receive_query(struct listener *listen, time_t now)
|
||||
dst_addr_4, netmask, now);
|
||||
if (m >= 1)
|
||||
{
|
||||
send_from(listen->fd, daemon->options & OPT_NOWILD, (char *)header,
|
||||
send_from(listen->fd, option_bool(OPT_NOWILD), (char *)header,
|
||||
m, &source_addr, &dst_addr, if_index);
|
||||
daemon->local_answer++;
|
||||
}
|
||||
@@ -764,17 +807,25 @@ void receive_query(struct listener *listen, time_t now)
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
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)
|
||||
{
|
||||
int size = 0, norebind = 0;
|
||||
size_t size = 0;
|
||||
int norebind = 0;
|
||||
int checking_disabled;
|
||||
size_t m;
|
||||
unsigned short qtype, gotname;
|
||||
unsigned char c1, c2;
|
||||
/* Max TCP packet + slop */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||
HEADER *header;
|
||||
struct dns_header *header;
|
||||
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)
|
||||
{
|
||||
if (!packet ||
|
||||
@@ -783,51 +834,59 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
!read_write(confd, packet, size, 1))
|
||||
return packet;
|
||||
|
||||
if (size < (int)sizeof(HEADER))
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
header = (HEADER *)packet;
|
||||
header = (struct dns_header *)packet;
|
||||
|
||||
/* save state of "cd" flag in query */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
/* RFC 4035: sect 4.6 para 2 */
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if ((gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
{
|
||||
union mysockaddr peer_addr;
|
||||
socklen_t peer_len = sizeof(union mysockaddr);
|
||||
char types[20];
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||
{
|
||||
char types[20];
|
||||
|
||||
querystr(types, qtype);
|
||||
|
||||
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);
|
||||
querystr(types, qtype);
|
||||
|
||||
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
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||
else
|
||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||
(struct all_addr *)&peer_addr.in6.sin6_addr, types);
|
||||
#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 = 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 */
|
||||
check_log_writer(NULL);
|
||||
|
||||
if (m == 0)
|
||||
{
|
||||
unsigned short flags = 0;
|
||||
unsigned int flags = 0;
|
||||
struct all_addr *addrp = NULL;
|
||||
int type = 0;
|
||||
char *domain = NULL;
|
||||
|
||||
|
||||
if (option_bool(OPT_ADD_MAC))
|
||||
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
|
||||
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
|
||||
last_server = daemon->servers;
|
||||
else
|
||||
last_server = daemon->last_server;
|
||||
@@ -857,18 +916,38 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (type != (last_server->flags & SERV_TYPE) ||
|
||||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||
continue;
|
||||
|
||||
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))
|
||||
|
||||
if (last_server->tcpfd == -1)
|
||||
{
|
||||
close(last_server->tcpfd);
|
||||
last_server->tcpfd = -1;
|
||||
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -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;
|
||||
c2 = size;
|
||||
@@ -906,7 +985,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
someone might be attempting to insert bogus values into the cache by
|
||||
sending replies containing questions and bogus answers. */
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m, (daemon->options & OPT_NO_REBIND) && !norebind );
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -938,6 +1018,7 @@ static struct frec *allocate_frec(time_t now)
|
||||
f->time = now;
|
||||
f->sentto = NULL;
|
||||
f->rfd4 = NULL;
|
||||
f->flags = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
@@ -990,6 +1071,7 @@ static void free_frec(struct frec *f)
|
||||
|
||||
f->rfd4 = NULL;
|
||||
f->sentto = NULL;
|
||||
f->flags = 0;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (f->rfd6 && --(f->rfd6->refcount) == 0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -79,14 +79,14 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
|
||||
sigaction(SIGTERM, &sigact, NULL);
|
||||
sigaction(SIGALRM, &sigact, NULL);
|
||||
|
||||
if (!(daemon->options & OPT_DEBUG) && uid != 0)
|
||||
if (!option_bool(OPT_DEBUG) && uid != 0)
|
||||
{
|
||||
gid_t dummy;
|
||||
if (setgroups(0, &dummy) == -1 ||
|
||||
setgid(gid) == -1 ||
|
||||
setuid(uid) == -1)
|
||||
{
|
||||
if (daemon->options & OPT_NO_FORK)
|
||||
if (option_bool(OPT_NO_FORK))
|
||||
/* send error to daemon process if no-fork */
|
||||
send_event(event_fd, EVENT_HUSER_ERR, errno);
|
||||
else
|
||||
|
||||
27
src/lease.c
27
src/lease.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -37,7 +37,7 @@ void lease_init(time_t now)
|
||||
|
||||
leases_left = daemon->dhcp_max;
|
||||
|
||||
if (daemon->options & OPT_LEASE_RO)
|
||||
if (option_bool(OPT_LEASE_RO))
|
||||
{
|
||||
/* run "<lease_change_script> init" once to get the
|
||||
initial state of the database. If leasefile-ro is
|
||||
@@ -254,7 +254,7 @@ void lease_update_dns(void)
|
||||
if (lease->fqdn)
|
||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
||||
|
||||
if (!(daemon->options & OPT_DHCP_FQDN) && lease->hostname)
|
||||
if (!option_bool(OPT_DHCP_FQDN) && lease->hostname)
|
||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
||||
}
|
||||
|
||||
@@ -323,6 +323,21 @@ struct dhcp_lease *lease_find_by_addr(struct in_addr addr)
|
||||
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)
|
||||
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)
|
||||
{
|
||||
@@ -470,7 +485,7 @@ void lease_set_hostname(struct dhcp_lease *lease, char *name, int auth)
|
||||
/* Depending on mode, we check either unqualified name or FQDN. */
|
||||
for (lease_tmp = leases; lease_tmp; lease_tmp = lease_tmp->next)
|
||||
{
|
||||
if (daemon->options & OPT_DHCP_FQDN)
|
||||
if (option_bool(OPT_DHCP_FQDN))
|
||||
{
|
||||
if (!new_fqdn || !lease_tmp->fqdn || !hostname_isequal(lease_tmp->fqdn, new_fqdn) )
|
||||
continue;
|
||||
@@ -534,7 +549,7 @@ int do_script_run(time_t now)
|
||||
#ifdef HAVE_DBUS
|
||||
/* If we're going to be sending DBus signals, but the connection is not yet up,
|
||||
delay everything until it is. */
|
||||
if ((daemon->options & OPT_DBUS) && !daemon->dbus)
|
||||
if (option_bool(OPT_DBUS) && !daemon->dbus)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -586,7 +601,7 @@ int do_script_run(time_t now)
|
||||
|
||||
for (lease = leases; lease; lease = lease->next)
|
||||
if (lease->new || lease->changed ||
|
||||
(lease->aux_changed && (daemon->options & OPT_LEASE_RO)))
|
||||
(lease->aux_changed && option_bool(OPT_LEASE_RO)))
|
||||
{
|
||||
#ifdef HAVE_SCRIPT
|
||||
queue_script(lease->new ? ACTION_ADD : ACTION_OLD, lease,
|
||||
|
||||
68
src/log.c
68
src/log.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
# include <android/log.h>
|
||||
#endif
|
||||
|
||||
/* Implement logging to /dev/log asynchronously. If syslogd is
|
||||
making DNS lookups through dnsmasq, and dnsmasq blocks awaiting
|
||||
syslogd, then the two daemons can deadlock. We get around this
|
||||
@@ -55,12 +59,12 @@ int log_start(struct passwd *ent_pw, int errfd)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
echo_stderr = !!(daemon->options & OPT_DEBUG);
|
||||
echo_stderr = option_bool(OPT_DEBUG);
|
||||
|
||||
if (daemon->log_fac != -1)
|
||||
log_fac = daemon->log_fac;
|
||||
#ifdef LOG_LOCAL0
|
||||
else if (daemon->options & OPT_DEBUG)
|
||||
else if (option_bool(OPT_DEBUG))
|
||||
log_fac = LOG_LOCAL0;
|
||||
#endif
|
||||
|
||||
@@ -117,7 +121,7 @@ int log_reopen(char *log_file)
|
||||
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_SOLARIS_NETWORK
|
||||
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
|
||||
/* Solaris logging is "different", /dev/log is not unix-domain socket.
|
||||
Just leave log_fd == -1 and use the vsyslog call for everything.... */
|
||||
# define _PATH_LOG "" /* dummy */
|
||||
@@ -150,6 +154,19 @@ static void log_write(void)
|
||||
|
||||
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() */
|
||||
if (entries->pid != getpid())
|
||||
{
|
||||
@@ -159,11 +176,11 @@ static void log_write(void)
|
||||
|
||||
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->offset += rc;
|
||||
if (entries->length == 0)
|
||||
if (entries->length == len_adjust)
|
||||
{
|
||||
free_entry();
|
||||
if (entries_lost != 0)
|
||||
@@ -289,8 +306,28 @@ void my_syslog(int priority, const char *format, ...)
|
||||
|
||||
if (log_fd == -1)
|
||||
{
|
||||
/* fall-back to syslog if we die during startup or fail during running. */
|
||||
#ifdef __ANDROID__
|
||||
/* do android-specific logging.
|
||||
log_fd is always -1 on Android except when logging to a file. */
|
||||
int alog_lvl;
|
||||
|
||||
if (priority <= LOG_ERR)
|
||||
alog_lvl = ANDROID_LOG_ERROR;
|
||||
else if (priority == LOG_WARNING)
|
||||
alog_lvl = ANDROID_LOG_WARN;
|
||||
else if (priority <= LOG_INFO)
|
||||
alog_lvl = ANDROID_LOG_INFO;
|
||||
else
|
||||
alog_lvl = ANDROID_LOG_DEBUG;
|
||||
|
||||
va_start(ap, format);
|
||||
__android_log_vprint(alog_lvl, "dnsmasq", format, ap);
|
||||
va_end(ap);
|
||||
#else
|
||||
/* fall-back to syslog if we die during startup or
|
||||
fail during running (always on Solaris). */
|
||||
static int isopen = 0;
|
||||
|
||||
if (!isopen)
|
||||
{
|
||||
openlog("dnsmasq", LOG_PID, log_fac);
|
||||
@@ -299,6 +336,8 @@ void my_syslog(int priority, const char *format, ...)
|
||||
va_start(ap, format);
|
||||
vsyslog(priority, format, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -327,7 +366,11 @@ void my_syslog(int priority, const char *format, ...)
|
||||
if (!log_to_file)
|
||||
p += sprintf(p, "<%d>", priority | log_fac);
|
||||
|
||||
p += sprintf(p, "%.15s dnsmasq%s[%d]: ", ctime(&time_now) + 4, func, (int)pid);
|
||||
/* Omit timestamp for default daemontools situation */
|
||||
if (!log_stderr || !option_bool(OPT_NO_FORK))
|
||||
p += sprintf(p, "%.15s ", ctime(&time_now) + 4);
|
||||
|
||||
p += sprintf(p, "dnsmasq%s[%d]: ", func, (int)pid);
|
||||
|
||||
len = p - entry->payload;
|
||||
va_start(ap, format);
|
||||
@@ -336,10 +379,6 @@ void my_syslog(int priority, const char *format, ...)
|
||||
entry->length = len > MAX_MESSAGE ? MAX_MESSAGE : len;
|
||||
entry->offset = 0;
|
||||
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,
|
||||
@@ -398,12 +437,13 @@ void check_log_writer(fd_set *set)
|
||||
|
||||
void flush_log(void)
|
||||
{
|
||||
/* write until queue empty */
|
||||
/* write until queue empty, but don't loop forever if there's
|
||||
no connection to the syslog in existance */
|
||||
while (log_fd != -1)
|
||||
{
|
||||
struct timespec waiter;
|
||||
log_write();
|
||||
if (!entries)
|
||||
if (!entries || !connection_good)
|
||||
{
|
||||
close(log_fd);
|
||||
break;
|
||||
|
||||
117
src/netlink.c
117
src/netlink.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -30,6 +30,10 @@
|
||||
# include <linux/if_addr.h>
|
||||
#endif
|
||||
|
||||
#ifndef NDA_RTA
|
||||
# define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
|
||||
#endif
|
||||
|
||||
static struct iovec iov;
|
||||
static u32 netlink_pid;
|
||||
|
||||
@@ -122,13 +126,14 @@ static ssize_t netlink_recv(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
|
||||
/* family = AF_UNSPEC finds ARP table entries. */
|
||||
int iface_enumerate(int family, void *parm, int (*callback)())
|
||||
{
|
||||
struct sockaddr_nl addr;
|
||||
struct nlmsghdr *h;
|
||||
ssize_t len;
|
||||
static unsigned int seq = 0;
|
||||
int family = AF_INET;
|
||||
|
||||
struct {
|
||||
struct nlmsghdr nlh;
|
||||
@@ -142,7 +147,7 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
|
||||
again:
|
||||
req.nlh.nlmsg_len = sizeof(req);
|
||||
req.nlh.nlmsg_type = RTM_GETADDR;
|
||||
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_pid = 0;
|
||||
req.nlh.nlmsg_seq = ++seq;
|
||||
@@ -173,66 +178,84 @@ int iface_enumerate(void *parm, int (*ipv4_callback)(), int (*ipv6_callback)())
|
||||
else if (h->nlmsg_type == NLMSG_ERROR)
|
||||
nl_err(h);
|
||||
else if (h->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET && ipv6_callback)
|
||||
{
|
||||
family = AF_INET6;
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWADDR)
|
||||
return 1;
|
||||
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC)
|
||||
{
|
||||
struct ifaddrmsg *ifa = NLMSG_DATA(h);
|
||||
struct rtattr *rta = IFA_RTA(ifa);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa));
|
||||
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
if (ifa->ifa_family == family)
|
||||
{
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
struct in_addr netmask, addr, broadcast;
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
|
||||
addr.s_addr = 0;
|
||||
broadcast.s_addr = 0;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_LOCAL)
|
||||
addr = *((struct in_addr *)(rta+1));
|
||||
else if (rta->rta_type == IFA_BROADCAST)
|
||||
broadcast = *((struct in_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
if (addr.s_addr)
|
||||
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr.s_addr && ipv4_callback)
|
||||
if (!((*ipv4_callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
|
||||
return 0;
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
else if (ifa->ifa_family == AF_INET6)
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
struct in6_addr *addrp = NULL;
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == IFA_ADDRESS)
|
||||
addrp = ((struct in6_addr *)(rta+1));
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
if (addrp)
|
||||
if (!((*callback)(addrp, ifa->ifa_scope, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (h->nlmsg_type == RTM_NEWNEIGH && family == AF_UNSPEC)
|
||||
{
|
||||
struct ndmsg *neigh = NLMSG_DATA(h);
|
||||
struct rtattr *rta = NDA_RTA(neigh);
|
||||
unsigned int len1 = h->nlmsg_len - NLMSG_LENGTH(sizeof(*neigh));
|
||||
size_t maclen = 0;
|
||||
char *inaddr = NULL, *mac = NULL;
|
||||
|
||||
while (RTA_OK(rta, len1))
|
||||
{
|
||||
if (rta->rta_type == NDA_DST)
|
||||
inaddr = (char *)(rta+1);
|
||||
else if (rta->rta_type == NDA_LLADDR)
|
||||
{
|
||||
maclen = rta->rta_len - sizeof(struct rtattr);
|
||||
mac = (char *)(rta+1);
|
||||
}
|
||||
|
||||
if (addrp && ipv6_callback)
|
||||
if (!((*ipv6_callback)(addrp, ifa->ifa_index, ifa->ifa_index, parm)))
|
||||
return 0;
|
||||
rta = RTA_NEXT(rta, len1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (inaddr && mac)
|
||||
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void netlink_multicast(void)
|
||||
{
|
||||
ssize_t len;
|
||||
@@ -281,7 +304,7 @@ static void nl_routechange(struct nlmsghdr *h)
|
||||
return;
|
||||
|
||||
/* Force re-reading resolv file right now, for luck. */
|
||||
poll_resolv(1, 1, dnsmasq_time());
|
||||
daemon->last_resolv = 0;
|
||||
|
||||
if (daemon->srv_save)
|
||||
{
|
||||
|
||||
495
src/network.c
495
src/network.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -34,6 +34,67 @@ int indextoname(int fd, int index, char *name)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
|
||||
#include <zone.h>
|
||||
#include <alloca.h>
|
||||
#ifndef LIFC_UNDER_IPMP
|
||||
# define LIFC_UNDER_IPMP 0
|
||||
#endif
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
{
|
||||
int64_t lifc_flags;
|
||||
struct lifnum lifn;
|
||||
int numifs, bufsize, i;
|
||||
struct lifconf lifc;
|
||||
struct lifreq *lifrp;
|
||||
|
||||
if (index == 0)
|
||||
return 0;
|
||||
|
||||
if (getzoneid() == GLOBAL_ZONEID)
|
||||
{
|
||||
if (!if_indextoname(index, name))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES | LIFC_UNDER_IPMP;
|
||||
lifn.lifn_family = AF_UNSPEC;
|
||||
lifn.lifn_flags = lifc_flags;
|
||||
if (ioctl(fd, SIOCGLIFNUM, &lifn) < 0)
|
||||
return 0;
|
||||
|
||||
numifs = lifn.lifn_count;
|
||||
bufsize = numifs * sizeof(struct lifreq);
|
||||
|
||||
lifc.lifc_family = AF_UNSPEC;
|
||||
lifc.lifc_flags = lifc_flags;
|
||||
lifc.lifc_len = bufsize;
|
||||
lifc.lifc_buf = alloca(bufsize);
|
||||
|
||||
if (ioctl(fd, SIOCGLIFCONF, &lifc) < 0)
|
||||
return 0;
|
||||
|
||||
lifrp = lifc.lifc_req;
|
||||
for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++)
|
||||
{
|
||||
struct lifreq lifr;
|
||||
strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
|
||||
if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0)
|
||||
return 0;
|
||||
|
||||
if (lifr.lifr_index == index) {
|
||||
strncpy(name, lifr.lifr_name, IF_NAMESIZE);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
int indextoname(int fd, int index, char *name)
|
||||
@@ -188,15 +249,14 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
/* implement wierd TFTP service rules */
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
if (strcmp(ir->interface, ifr.ifr_name) == 0)
|
||||
{
|
||||
tftp_ok = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (!ir)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET &&
|
||||
@@ -276,10 +336,11 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
|
||||
int enumerate_interfaces(void)
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, iface_allowed_v6);
|
||||
#else
|
||||
return iface_enumerate(&daemon->interfaces, iface_allowed_v4, NULL);
|
||||
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
|
||||
}
|
||||
|
||||
/* set NONBLOCK bit on fd: See Stevens 16.6 */
|
||||
@@ -294,233 +355,207 @@ int fix_fd(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_IPV6)
|
||||
static int create_ipv6_listener(struct listener **link, int port)
|
||||
static int make_sock(union mysockaddr *addr, int type)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int tcpfd, fd;
|
||||
struct listener *l;
|
||||
int opt = 1;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
int family = addr->sa.sa_family;
|
||||
int fd, rc, opt = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
#endif
|
||||
|
||||
/* No error of the kernel doesn't support IPv6 */
|
||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||
return (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL);
|
||||
|
||||
if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||
return 0;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
!fix_fd(tcpfd) ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return 0;
|
||||
|
||||
/* The API changed around Linux 2.6.14 but the old ABI is still supported:
|
||||
handle all combinations of headers and kernel.
|
||||
OpenWrt note that this fixes the problem addressed by your very broken patch. */
|
||||
|
||||
daemon->v6pktinfo = IPV6_PKTINFO;
|
||||
|
||||
#ifdef IPV6_RECVPKTINFO
|
||||
# ifdef IPV6_2292PKTINFO
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
if ((fd = socket(family, type, 0)) == -1)
|
||||
{
|
||||
if (errno == ENOPROTOOPT && setsockopt(fd, IPV6_LEVEL, IPV6_2292PKTINFO, &opt, sizeof(opt)) != -1)
|
||||
daemon->v6pktinfo = IPV6_2292PKTINFO;
|
||||
else
|
||||
return 0;
|
||||
int port;
|
||||
|
||||
/* No error if the kernel just doesn't support this IP flavour */
|
||||
if (errno == EPROTONOSUPPORT ||
|
||||
errno == EAFNOSUPPORT ||
|
||||
errno == EINVAL)
|
||||
return -1;
|
||||
|
||||
err:
|
||||
port = prettyprint_addr(addr, daemon->namebuff);
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
sprintf(daemon->namebuff, "port %d", port);
|
||||
die(_("failed to create listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 || !fix_fd(fd))
|
||||
goto err;
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (family == AF_INET6 && setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
while (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;
|
||||
|
||||
if (type == SOCK_STREAM)
|
||||
{
|
||||
if (listen(fd, 5) == -1)
|
||||
goto err;
|
||||
}
|
||||
else if (!option_bool(OPT_NOWILD))
|
||||
{
|
||||
if (family == AF_INET)
|
||||
{
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
/* 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_RECVPKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
# endif
|
||||
#else
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
return 0;
|
||||
if (setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1)
|
||||
goto err;
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = -1;
|
||||
l->family = AF_INET6;
|
||||
l->next = NULL;
|
||||
*link = l;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct listener *create_listeners(union mysockaddr *addr, int do_tftp)
|
||||
{
|
||||
struct listener *l = NULL;
|
||||
int fd = -1, tcpfd = -1, tftpfd = -1;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
fd = make_sock(addr, SOCK_DGRAM);
|
||||
tcpfd = make_sock(addr, SOCK_STREAM);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (do_tftp)
|
||||
{
|
||||
if (addr->sa.sa_family == AF_INET)
|
||||
{
|
||||
/* port must be restored to DNS port for TCP code */
|
||||
short save = addr->in.sin_port;
|
||||
addr->in.sin_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
addr->in.sin_port = save;
|
||||
}
|
||||
# ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
short save = addr->in6.sin6_port;
|
||||
addr->in6.sin6_port = htons(TFTP_PORT);
|
||||
tftpfd = make_sock(addr, SOCK_DGRAM);
|
||||
addr->in6.sin6_port = save;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fd != -1 || tcpfd != -1 || tftpfd != -1)
|
||||
{
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->next = NULL;
|
||||
l->family = addr->sa.sa_family;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_wildcard_listeners(void)
|
||||
{
|
||||
union mysockaddr addr;
|
||||
int opt = 1;
|
||||
struct listener *l, *l6 = NULL;
|
||||
int tcpfd = -1, fd = -1, tftpfd = -1;
|
||||
struct listener *l;
|
||||
int tftp_enabled = daemon->tftp_unlimited || daemon->tftp_interfaces;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.in.sin_port = htons(daemon->port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
|
||||
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
(tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||
listen(tcpfd, 5) == -1 ||
|
||||
!fix_fd(tcpfd) ||
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
!create_ipv6_listener(&l6, daemon->port) ||
|
||||
#endif
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(fd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
}
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
# ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.in6.sin6_len = sizeof(addr.in6);
|
||||
# endif
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_addr = in6addr_any;
|
||||
addr.in6.sin6_port = htons(daemon->port);
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (daemon->tftp_unlimited || daemon->tftp_interfaces)
|
||||
{
|
||||
addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return NULL;
|
||||
|
||||
if (!fix_fd(tftpfd) ||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
setsockopt(tftpfd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(tftpfd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||
#endif
|
||||
bind(tftpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||
return NULL;
|
||||
}
|
||||
if (l)
|
||||
l->next = create_listeners(&addr, tftp_enabled);
|
||||
else
|
||||
l = create_listeners(&addr, tftp_enabled);
|
||||
#endif
|
||||
|
||||
l = safe_malloc(sizeof(struct listener));
|
||||
l->family = AF_INET;
|
||||
l->fd = fd;
|
||||
l->tcpfd = tcpfd;
|
||||
l->tftpfd = tftpfd;
|
||||
l->next = l6;
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
struct listener *create_bound_listeners(void)
|
||||
{
|
||||
struct listener *listeners = NULL;
|
||||
struct listener *new, *listeners = NULL;
|
||||
struct irec *iface;
|
||||
int rc, opt = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
static int dad_count = 0;
|
||||
#endif
|
||||
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
{
|
||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||
new->family = iface->addr.sa.sa_family;
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
new->tftpfd = -1;
|
||||
new->tcpfd = -1;
|
||||
new->fd = -1;
|
||||
listeners = new;
|
||||
|
||||
if (daemon->port != 0)
|
||||
{
|
||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tcpfd) ||
|
||||
!fix_fd(new->fd))
|
||||
die(_("failed to create listening socket: %s"), NULL, EC_BADNET);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (iface->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||
die(_("failed to set IPV6 options on listening socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
#endif
|
||||
|
||||
while(1)
|
||||
{
|
||||
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->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 (iface->addr.sa.sa_family == AF_INET6 && (errno == ENODEV || errno == EADDRNOTAVAIL) &&
|
||||
dad_count++ < DAD_WAIT)
|
||||
{
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
{
|
||||
prettyprint_addr(&iface->addr, daemon->namebuff);
|
||||
die(_("failed to bind listening socket for %s: %s"),
|
||||
daemon->namebuff, EC_BADNET);
|
||||
}
|
||||
|
||||
if (listen(new->tcpfd, 5) == -1)
|
||||
die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
|
||||
}
|
||||
|
||||
#ifdef HAVE_TFTP
|
||||
if (iface->addr.sa.sa_family == AF_INET && iface->tftp_ok)
|
||||
{
|
||||
short save = iface->addr.in.sin_port;
|
||||
iface->addr.in.sin_port = htons(TFTP_PORT);
|
||||
if ((new->tftpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ||
|
||||
setsockopt(new->tftpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||
!fix_fd(new->tftpfd) ||
|
||||
bind(new->tftpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
||||
die(_("failed to create TFTP socket: %s"), NULL, EC_BADNET);
|
||||
iface->addr.in.sin_port = save;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if ((new = create_listeners(&iface->addr, iface->tftp_ok)))
|
||||
{
|
||||
new->iface = iface;
|
||||
new->next = listeners;
|
||||
listeners = new;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@@ -700,7 +735,7 @@ void pre_allocate_sfds(void)
|
||||
if (!(srv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)) &&
|
||||
!allocate_sfd(&srv->source_addr, srv->interface) &&
|
||||
errno != 0 &&
|
||||
(daemon->options & OPT_NOWILD))
|
||||
option_bool(OPT_NOWILD))
|
||||
{
|
||||
prettyprint_addr(&srv->source_addr, daemon->namebuff);
|
||||
if (srv->interface[0] != 0)
|
||||
@@ -721,7 +756,7 @@ void check_servers(void)
|
||||
int port = 0;
|
||||
|
||||
/* interface may be new since startup */
|
||||
if (!(daemon->options & OPT_NOWILD))
|
||||
if (!option_bool(OPT_NOWILD))
|
||||
enumerate_interfaces();
|
||||
|
||||
for (new = daemon->servers; new; new = tmp)
|
||||
@@ -861,20 +896,38 @@ int reload_servers(char *fname)
|
||||
source_addr.in.sin_port = htons(daemon->query_port);
|
||||
}
|
||||
#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
|
||||
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
|
||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||
addr.in6.sin6_port = htons(NAMESERVER_PORT);
|
||||
source_addr.in6.sin6_addr = in6addr_any;
|
||||
source_addr.in6.sin6_port = htons(daemon->query_port);
|
||||
source_addr.in6.sin6_family = addr.in6.sin6_family = AF_INET6;
|
||||
source_addr.in6.sin6_flowinfo = addr.in6.sin6_flowinfo = 0;
|
||||
addr.in6.sin6_port = htons(NAMESERVER_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
|
||||
continue;
|
||||
|
||||
#endif
|
||||
|
||||
if (old_servers)
|
||||
{
|
||||
serv = old_servers;
|
||||
@@ -921,7 +974,9 @@ struct in_addr get_ifaddr(char *intr)
|
||||
|
||||
ret.sin_addr.s_addr = -1;
|
||||
|
||||
for (l = daemon->listeners; l && l->family != AF_INET; l = l->next);
|
||||
for (l = daemon->listeners;
|
||||
l && (l->family != AF_INET || l->fd == -1);
|
||||
l = l->next);
|
||||
|
||||
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
655
src/option.c
655
src/option.c
File diff suppressed because it is too large
Load Diff
313
src/rfc1035.c
313
src/rfc1035.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "dnsmasq.h"
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type,
|
||||
unsigned short class, char *format, ...);
|
||||
@@ -27,7 +27,7 @@ static int add_resource_record(HEADER *header, char *limit, int *truncp,
|
||||
#define ADD_RDLEN(header, pp, plen, len) \
|
||||
(!CHECK_LEN(header, pp, plen, len) ? 0 : (long)((pp) += (len)), 1)
|
||||
|
||||
static int extract_name(HEADER *header, size_t plen, unsigned char **pp,
|
||||
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
|
||||
char *name, int isExtract, int extrabytes)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
|
||||
@@ -217,7 +217,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
as CNAME targets according to RFC 2317 */
|
||||
char *cp;
|
||||
for (cp = cp1; *cp; cp++)
|
||||
if (!isdigit((int)*cp))
|
||||
if (!isdigit((unsigned char)*cp))
|
||||
return 0;
|
||||
|
||||
addr[3] = addr[2];
|
||||
@@ -244,7 +244,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
if (*name == '\\' && *(name+1) == '[' &&
|
||||
(*(name+2) == 'x' || *(name+2) == 'X'))
|
||||
{
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((int) *cp1) && j < 32; cp1++, j++)
|
||||
for (j = 0, cp1 = name+3; *cp1 && isxdigit((unsigned char) *cp1) && j < 32; cp1++, j++)
|
||||
{
|
||||
char xdig[2];
|
||||
xdig[0] = *cp1;
|
||||
@@ -262,7 +262,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
{
|
||||
for (cp1 = name; cp1 != penchunk; cp1 += strlen(cp1)+1)
|
||||
{
|
||||
if (*(cp1+1) || !isxdigit((int)*cp1))
|
||||
if (*(cp1+1) || !isxdigit((unsigned char)*cp1))
|
||||
return 0;
|
||||
|
||||
for (j = sizeof(struct all_addr)-1; j>0; j--)
|
||||
@@ -278,7 +278,7 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen, int extrabytes)
|
||||
static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header, size_t plen, int extrabytes)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
@@ -333,7 +333,7 @@ static unsigned char *skip_name(unsigned char *ansp, HEADER *header, size_t plen
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
|
||||
{
|
||||
int q;
|
||||
unsigned char *ansp = (unsigned char *)(header+1);
|
||||
@@ -348,7 +348,7 @@ static unsigned char *skip_questions(HEADER *header, size_t plen)
|
||||
return ansp;
|
||||
}
|
||||
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, size_t plen)
|
||||
static unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen)
|
||||
{
|
||||
int i, rdlen;
|
||||
|
||||
@@ -371,7 +371,7 @@ static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *heade
|
||||
than CRC the raw bytes, since replies might be compressed differently.
|
||||
We ignore case in the names for the same reason. Return all-ones
|
||||
if there is not question section. */
|
||||
unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
unsigned int questions_crc(struct dns_header *header, size_t plen, char *name)
|
||||
{
|
||||
int q;
|
||||
unsigned int crc = 0xffffffff;
|
||||
@@ -413,7 +413,7 @@ unsigned int questions_crc(HEADER *header, size_t plen, char *name)
|
||||
}
|
||||
|
||||
|
||||
size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
size_t resize_packet(struct dns_header *header, size_t plen, unsigned char *pheader, size_t hlen)
|
||||
{
|
||||
unsigned char *ansp = skip_questions(header, plen);
|
||||
|
||||
@@ -437,7 +437,7 @@ size_t resize_packet(HEADER *header, size_t plen, unsigned char *pheader, size_t
|
||||
return ansp - (unsigned char *)header;
|
||||
}
|
||||
|
||||
unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
||||
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
|
||||
{
|
||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||
also return length of pseudoheader in *len and pointer to the UDP size in *p
|
||||
@@ -453,7 +453,7 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
{
|
||||
*is_sign = 0;
|
||||
|
||||
if (header->opcode == QUERY)
|
||||
if (OPCODE(header) == QUERY)
|
||||
{
|
||||
for (i = ntohs(header->qdcount); i != 0; i--)
|
||||
{
|
||||
@@ -510,8 +510,122 @@ unsigned char *find_pseudoheader(HEADER *header, size_t plen, size_t *len, unsi
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct macparm {
|
||||
unsigned char *limit;
|
||||
struct dns_header *header;
|
||||
size_t plen;
|
||||
union mysockaddr *l3;
|
||||
};
|
||||
|
||||
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
|
||||
{
|
||||
struct macparm *parm = parmv;
|
||||
int match = 0;
|
||||
unsigned short rdlen;
|
||||
struct dns_header *header = parm->header;
|
||||
unsigned char *lenp, *datap, *p;
|
||||
|
||||
if (family == parm->l3->sa.sa_family)
|
||||
{
|
||||
if (family == AF_INET && memcmp (&parm->l3->in.sin_addr, addrp, INADDRSZ) == 0)
|
||||
match = 1;
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
if (family == AF_INET6 && memcmp (&parm->l3->in6.sin6_addr, addrp, IN6ADDRSZ) == 0)
|
||||
match = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!match)
|
||||
return 1; /* continue */
|
||||
|
||||
if (ntohs(header->arcount) == 0)
|
||||
{
|
||||
/* We are adding the pseudoheader */
|
||||
if (!(p = skip_questions(header, parm->plen)) ||
|
||||
!(p = skip_section(p,
|
||||
ntohs(header->ancount) + ntohs(header->nscount),
|
||||
header, parm->plen)))
|
||||
return 0;
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(PACKETSZ, p); /* max packet length - is 512 suitable default for non-EDNS0 resolvers? */
|
||||
PUTLONG(0, p); /* extended RCODE */
|
||||
lenp = p;
|
||||
PUTSHORT(0, p); /* RDLEN */
|
||||
rdlen = 0;
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
header->arcount = htons(1);
|
||||
datap = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, is_sign;
|
||||
unsigned short code, len;
|
||||
|
||||
if (ntohs(header->arcount) != 1 ||
|
||||
!(p = find_pseudoheader(header, parm->plen, NULL, NULL, &is_sign)) ||
|
||||
is_sign ||
|
||||
(!(p = skip_name(p, header, parm->plen, 10))))
|
||||
return 0;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
if (!CHECK_LEN(header, p, parm->plen, rdlen))
|
||||
return 0; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
GETSHORT(code, p);
|
||||
GETSHORT(len, p);
|
||||
if (code == EDNS0_OPTION_MAC)
|
||||
return 0;
|
||||
p += len;
|
||||
}
|
||||
|
||||
if (((ssize_t)maclen) > (parm->limit - (p + 4)))
|
||||
return 0; /* Too big */
|
||||
}
|
||||
|
||||
PUTSHORT(EDNS0_OPTION_MAC, p);
|
||||
PUTSHORT(maclen, p);
|
||||
memcpy(p, mac, maclen);
|
||||
p += maclen;
|
||||
|
||||
PUTSHORT(p - datap, lenp);
|
||||
parm->plen = p - (unsigned char *)header;
|
||||
|
||||
return 0; /* done */
|
||||
}
|
||||
|
||||
|
||||
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3)
|
||||
{
|
||||
struct macparm parm;
|
||||
|
||||
/* Must have an existing pseudoheader as the only ar-record,
|
||||
or have no ar-records. Must also not be signed */
|
||||
|
||||
if (ntohs(header->arcount) > 1)
|
||||
return plen;
|
||||
|
||||
parm.header = header;
|
||||
parm.limit = (unsigned char *)limit;
|
||||
parm.plen = plen;
|
||||
parm.l3 = l3;
|
||||
|
||||
iface_enumerate(AF_UNSPEC, &parm, filter_mac);
|
||||
|
||||
return parm.plen;
|
||||
}
|
||||
|
||||
|
||||
/* is addr in the non-globally-routed IP space? */
|
||||
static int private_net(struct in_addr addr, int ban_localhost)
|
||||
{
|
||||
@@ -525,14 +639,13 @@ static int private_net(struct in_addr addr, int ban_localhost)
|
||||
((ip_addr & 0xFFFF0000) == 0xA9FE0000) /* 169.254.0.0/16 (zeroconf) */ ;
|
||||
}
|
||||
|
||||
static unsigned char *do_doctor(unsigned char *p, int count, 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;
|
||||
unsigned long ttl;
|
||||
|
||||
for (i = count; i != 0; i--)
|
||||
{
|
||||
if (name && (daemon->options & OPT_LOG))
|
||||
if (name && option_bool(OPT_LOG))
|
||||
{
|
||||
if (!extract_name(header, qlen, &p, name, 1, 10))
|
||||
return 0;
|
||||
@@ -542,7 +655,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
GETLONG(ttl, p);
|
||||
p += 4; /* ttl */
|
||||
GETSHORT(rdlen, p);
|
||||
|
||||
if (qclass == C_IN && qtype == T_A)
|
||||
@@ -570,12 +683,12 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
addr.s_addr &= ~doctor->mask.s_addr;
|
||||
addr.s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||
header->aa = 0;
|
||||
header->hb3 &= ~HB3_AA;
|
||||
memcpy(p, &addr, INADDRSZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (qtype == T_TXT && name && (daemon->options & OPT_LOG))
|
||||
else if (qtype == T_TXT && name && option_bool(OPT_LOG))
|
||||
{
|
||||
unsigned char *p1 = p;
|
||||
if (!CHECK_LEN(header, p1, qlen, rdlen))
|
||||
@@ -592,7 +705,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
p2++;
|
||||
}
|
||||
*p2 = 0;
|
||||
my_syslog(LOG_DEBUG, "reply %s is %s", name, p1);
|
||||
my_syslog(LOG_INFO, "reply %s is %s", name, p1);
|
||||
/* restore */
|
||||
memmove(p1 + 1, p1, len);
|
||||
*p1 = len;
|
||||
@@ -607,7 +720,7 @@ static unsigned char *do_doctor(unsigned char *p, int count, HEADER *header, siz
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_soa(HEADER *header, size_t qlen, char *name)
|
||||
static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
||||
{
|
||||
unsigned char *p;
|
||||
int qtype, qclass, rdlen;
|
||||
@@ -665,7 +778,8 @@ static int find_soa(HEADER *header, size_t qlen, char *name)
|
||||
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int is_sign, int check_rebind)
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
int is_sign, int check_rebind, int checking_disabled)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -675,7 +789,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
cache_start_insert();
|
||||
|
||||
/* find_soa is needed for dns_doctor and logging side-effects, so don't call it lazily if there are any. */
|
||||
if (daemon->doctors || (daemon->options & OPT_LOG))
|
||||
if (daemon->doctors || option_bool(OPT_LOG))
|
||||
{
|
||||
searched_soa = 1;
|
||||
ttl = find_soa(header, qlen, name);
|
||||
@@ -688,7 +802,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
{
|
||||
int found = 0, cname_count = 5;
|
||||
struct crec *cpp = NULL;
|
||||
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
int flags = RCODE(header) == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||
unsigned long cttl = ULONG_MAX, attl;
|
||||
|
||||
namep = p;
|
||||
@@ -729,7 +843,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
GETLONG(attl, p1);
|
||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||
{
|
||||
(p1) -= NS_INT32SZ;
|
||||
(p1) -= 4;
|
||||
PUTLONG(daemon->max_ttl, p1);
|
||||
}
|
||||
GETSHORT(ardlen, p1);
|
||||
@@ -761,7 +875,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -809,7 +923,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
GETLONG(attl, p1);
|
||||
if ((daemon->max_ttl != 0) && (attl > daemon->max_ttl) && !is_sign)
|
||||
{
|
||||
(p1) -= NS_INT32SZ;
|
||||
(p1) -= 4;
|
||||
PUTLONG(daemon->max_ttl, p1);
|
||||
}
|
||||
GETSHORT(ardlen, p1);
|
||||
@@ -848,7 +962,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
/* check for returned address in private space */
|
||||
if (check_rebind &&
|
||||
(flags & F_IPV4) &&
|
||||
private_net(addr.addr.addr4, !(daemon->options & OPT_LOCAL_REBIND)))
|
||||
private_net(addr.addr.addr4, !option_bool(OPT_LOCAL_REBIND)))
|
||||
return 1;
|
||||
|
||||
newc = cache_insert(name, &addr, now, attl, flags | F_FORWARD);
|
||||
@@ -867,7 +981,7 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||
if (!found && !option_bool(OPT_NO_NEG))
|
||||
{
|
||||
if (!searched_soa)
|
||||
{
|
||||
@@ -889,18 +1003,19 @@ int extract_addresses(HEADER *header, size_t qlen, char *name, time_t now, int i
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't put stuff from a truncated packet into the cache, but do everything else */
|
||||
if (!header->tc)
|
||||
/* Don't put stuff from a truncated packet into the cache,
|
||||
also don't cache replies where DNSSEC validation was turned off, either
|
||||
the upstream server told us so, or the original query specified it. */
|
||||
if (!(header->hb3 & HB3_TC) && !(header->hb4 & HB4_CD) && !checking_disabled)
|
||||
cache_end_insert();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the packet holds exactly one query
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name.
|
||||
Abuse F_BIGNAME to indicate an NS query - yuck. */
|
||||
return F_IPV4 or F_IPV6 and leave the name from the query in name */
|
||||
|
||||
unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned short *typep)
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen, char *name, unsigned short *typep)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass;
|
||||
@@ -908,7 +1023,7 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
if (typep)
|
||||
*typep = 0;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 || header->opcode != QUERY)
|
||||
if (ntohs(header->qdcount) != 1 || OPCODE(header) != QUERY)
|
||||
return 0; /* must be exactly one query. */
|
||||
|
||||
if (!extract_name(header, qlen, &p, name, 1, 4))
|
||||
@@ -928,50 +1043,49 @@ unsigned short extract_request(HEADER *header, size_t qlen, char *name, unsigned
|
||||
return F_IPV6;
|
||||
if (qtype == T_ANY)
|
||||
return F_IPV4 | F_IPV6;
|
||||
if (qtype == T_NS || qtype == T_SOA)
|
||||
return F_QUERY | F_BIGNAME;
|
||||
}
|
||||
|
||||
return F_QUERY;
|
||||
}
|
||||
|
||||
|
||||
size_t setup_reply(HEADER *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned short flags, unsigned long ttl)
|
||||
size_t setup_reply(struct dns_header *header, size_t qlen,
|
||||
struct all_addr *addrp, unsigned int flags, unsigned long ttl)
|
||||
{
|
||||
unsigned char *p = skip_questions(header, qlen);
|
||||
|
||||
header->qr = 1; /* response */
|
||||
header->aa = 0; /* authoritive */
|
||||
header->ra = 1; /* recursion if available */
|
||||
header->tc = 0; /* not truncated */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
/* set RA flag */
|
||||
header->hb4 |= HB4_RA;
|
||||
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(0);
|
||||
header->ancount = htons(0); /* no answers unless changed below */
|
||||
if (flags == F_NEG)
|
||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
||||
SET_RCODE(header, SERVFAIL); /* couldn't get memory */
|
||||
else if (flags == F_NOERR)
|
||||
header->rcode = NOERROR; /* empty domain */
|
||||
SET_RCODE(header, NOERROR); /* empty domain */
|
||||
else if (flags == F_NXDOMAIN)
|
||||
header->rcode = NXDOMAIN;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else if (p && flags == F_IPV4)
|
||||
{ /* we know the address */
|
||||
header->rcode = NOERROR;
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_A, C_IN, "4", addrp);
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else if (p && flags == F_IPV6)
|
||||
{
|
||||
header->rcode = NOERROR;
|
||||
SET_RCODE(header, NOERROR);
|
||||
header->ancount = htons(1);
|
||||
header->aa = 1;
|
||||
add_resource_record(header, NULL, NULL, sizeof(HEADER), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
header->hb3 |= HB3_AA;
|
||||
add_resource_record(header, NULL, NULL, sizeof(struct dns_header), &p, ttl, NULL, T_AAAA, C_IN, "6", addrp);
|
||||
}
|
||||
#endif
|
||||
else /* nowhere to forward to */
|
||||
header->rcode = REFUSED;
|
||||
SET_RCODE(header, REFUSED);
|
||||
|
||||
return p - (unsigned char *)header;
|
||||
}
|
||||
@@ -984,12 +1098,17 @@ int check_for_local_domain(char *name, time_t now)
|
||||
struct txt_record *txt;
|
||||
struct interface_name *intr;
|
||||
struct ptr_record *ptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
||||
struct naptr *naptr;
|
||||
|
||||
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_CNAME)) &&
|
||||
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||
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))
|
||||
return 1;
|
||||
|
||||
@@ -1011,7 +1130,7 @@ int check_for_local_domain(char *name, time_t now)
|
||||
/* Is the packet a reply with the answer address equal to addr?
|
||||
If so mung is into an NXDOMAIN reply and also put that information
|
||||
in the cache. */
|
||||
int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
|
||||
struct bogus_addr *baddr, time_t now)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -1058,7 +1177,7 @@ int check_for_bogus_wildcard(HEADER *header, size_t qlen, char *name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_resource_record(HEADER *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
|
||||
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
@@ -1168,7 +1287,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
|
||||
|
||||
|
||||
/* return zero if we can't answer from cache, or packet size if we can */
|
||||
size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
|
||||
struct in_addr local_addr, struct in_addr local_netmask, time_t now)
|
||||
{
|
||||
char *name = daemon->namebuff;
|
||||
@@ -1192,11 +1311,11 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
if (find_pseudoheader(header, qlen, NULL, &pheader, &is_sign))
|
||||
{
|
||||
unsigned short udpsz, ext_rcode, flags;
|
||||
unsigned short udpsz, flags;
|
||||
unsigned char *psave = pheader;
|
||||
|
||||
GETSHORT(udpsz, pheader);
|
||||
GETSHORT(ext_rcode, pheader);
|
||||
pheader += 2; /* ext_rcode */
|
||||
GETSHORT(flags, pheader);
|
||||
|
||||
sec_reqd = flags & 0x8000; /* do bit */
|
||||
@@ -1211,7 +1330,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
dryrun = 1;
|
||||
}
|
||||
|
||||
if (ntohs(header->qdcount) == 0 || header->opcode != QUERY )
|
||||
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
|
||||
return 0;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
@@ -1249,7 +1368,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<TXT>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
daemon->local_ttl, NULL,
|
||||
T_TXT, t->class, "t", t->len, t->txt))
|
||||
@@ -1300,7 +1419,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<PTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<PTR>");
|
||||
for (ptr = daemon->ptr; ptr; ptr = ptr->next)
|
||||
if (hostname_isequal(name, ptr->name) &&
|
||||
add_resource_record(header, limit, &trunc, nameoffset, &ansp,
|
||||
@@ -1344,7 +1463,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||
else if (is_arpa == F_IPV4 &&
|
||||
(daemon->options & OPT_BOGUSPRIV) &&
|
||||
option_bool(OPT_BOGUSPRIV) &&
|
||||
private_net(addr.addr.addr4, 1))
|
||||
{
|
||||
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||
@@ -1380,7 +1499,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
for (cp = name, i = 0, a = 0; *cp; i++)
|
||||
{
|
||||
if (!isdigit(*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
if (!isdigit((unsigned char)*cp) || (x = strtol(cp, &cp, 10)) > 255)
|
||||
{
|
||||
i = 5;
|
||||
break;
|
||||
@@ -1442,7 +1561,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
|
||||
/* See if a putative address is on the network from which we recieved
|
||||
the query, is so we'll filter other answers. */
|
||||
if (local_addr.s_addr != 0 && (daemon->options & OPT_LOCALISE) && flag == F_IPV4)
|
||||
if (local_addr.s_addr != 0 && option_bool(OPT_LOCALISE) && flag == F_IPV4)
|
||||
{
|
||||
struct crec *save = crecp;
|
||||
do {
|
||||
@@ -1525,7 +1644,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
|
||||
{
|
||||
@@ -1536,16 +1655,16 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||
if (!found && (option_bool(OPT_SELFMX) || option_bool(OPT_LOCALMX)) &&
|
||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<MX>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl, NULL,
|
||||
T_MX, C_IN, "sd", 1,
|
||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
option_bool(OPT_SELFMX) ? name : daemon->mxtarget))
|
||||
anscount++;
|
||||
}
|
||||
}
|
||||
@@ -1554,7 +1673,8 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_SRV || qtype == T_ANY)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
struct mx_srv_record *move = NULL, **up = &daemon->mxnames;
|
||||
|
||||
for (rec = daemon->mxnames; rec; rec = rec->next)
|
||||
if (rec->issrv && hostname_isequal(name, rec->name))
|
||||
{
|
||||
@@ -1562,7 +1682,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (!dryrun)
|
||||
{
|
||||
unsigned int offset;
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<SRV>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
&offset, T_SRV, C_IN, "sssd",
|
||||
rec->priority, rec->weight, rec->srvport, rec->target))
|
||||
@@ -1572,9 +1692,27 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
rec->offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/* unlink first SRV record found */
|
||||
if (!move)
|
||||
{
|
||||
move = rec;
|
||||
*up = rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
}
|
||||
else
|
||||
up = &rec->next;
|
||||
|
||||
/* put first SRV record back at the end. */
|
||||
if (move)
|
||||
{
|
||||
*up = move;
|
||||
move->next = NULL;
|
||||
}
|
||||
|
||||
if (!found && (daemon->options & OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
if (!found && option_bool(OPT_FILTER) && (qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -1591,7 +1729,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
{
|
||||
log_query(F_CNAME | F_FORWARD | F_CONFIG | F_NXDOMAIN, name, NULL, "<NAPTR>");
|
||||
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
|
||||
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
|
||||
NULL, T_NAPTR, C_IN, "sszzzd",
|
||||
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
|
||||
@@ -1603,7 +1741,7 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
if (qtype == T_MAILB)
|
||||
ans = 1, nxdomain = 1;
|
||||
|
||||
if (qtype == T_SOA && (daemon->options & OPT_FILTER))
|
||||
if (qtype == T_SOA && option_bool(OPT_FILTER))
|
||||
{
|
||||
ans = 1;
|
||||
if (!dryrun)
|
||||
@@ -1650,14 +1788,23 @@ size_t answer_request(HEADER *header, char *limit, size_t qlen,
|
||||
}
|
||||
|
||||
/* done all questions, set up header and return length of result */
|
||||
header->qr = 1; /* response */
|
||||
header->aa = auth; /* authoritive - only hosts and DHCP derived names. */
|
||||
header->ra = 1; /* recursion if available */
|
||||
header->tc = trunc; /* truncation */
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
|
||||
/* set RA flag */
|
||||
header->hb4 |= HB4_RA;
|
||||
|
||||
/* authoritive - only hosts and DHCP derived names. */
|
||||
if (auth)
|
||||
header->hb3 |= HB3_AA;
|
||||
|
||||
/* truncation */
|
||||
if (trunc)
|
||||
header->hb3 |= HB3_TC;
|
||||
|
||||
if (anscount == 0 && nxdomain)
|
||||
header->rcode = NXDOMAIN;
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
else
|
||||
header->rcode = NOERROR; /* no error */
|
||||
SET_RCODE(header, NOERROR); /* no error */
|
||||
header->ancount = htons(anscount);
|
||||
header->nscount = htons(0);
|
||||
header->arcount = htons(addncount);
|
||||
|
||||
473
src/rfc2131.c
473
src/rfc2131.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -18,69 +18,6 @@
|
||||
|
||||
#ifdef HAVE_DHCP
|
||||
|
||||
#define BOOTREQUEST 1
|
||||
#define BOOTREPLY 2
|
||||
#define DHCP_COOKIE 0x63825363
|
||||
|
||||
/* The Linux in-kernel DHCP client silently ignores any packet
|
||||
smaller than this. Sigh........... */
|
||||
#define MIN_PACKETSZ 300
|
||||
|
||||
#define OPTION_PAD 0
|
||||
#define OPTION_NETMASK 1
|
||||
#define OPTION_ROUTER 3
|
||||
#define OPTION_DNSSERVER 6
|
||||
#define OPTION_HOSTNAME 12
|
||||
#define OPTION_DOMAINNAME 15
|
||||
#define OPTION_BROADCAST 28
|
||||
#define OPTION_VENDOR_CLASS_OPT 43
|
||||
#define OPTION_REQUESTED_IP 50
|
||||
#define OPTION_LEASE_TIME 51
|
||||
#define OPTION_OVERLOAD 52
|
||||
#define OPTION_MESSAGE_TYPE 53
|
||||
#define OPTION_SERVER_IDENTIFIER 54
|
||||
#define OPTION_REQUESTED_OPTIONS 55
|
||||
#define OPTION_MESSAGE 56
|
||||
#define OPTION_MAXMESSAGE 57
|
||||
#define OPTION_T1 58
|
||||
#define OPTION_T2 59
|
||||
#define OPTION_VENDOR_ID 60
|
||||
#define OPTION_CLIENT_ID 61
|
||||
#define OPTION_SNAME 66
|
||||
#define OPTION_FILENAME 67
|
||||
#define OPTION_USER_CLASS 77
|
||||
#define OPTION_CLIENT_FQDN 81
|
||||
#define OPTION_AGENT_ID 82
|
||||
#define OPTION_ARCH 93
|
||||
#define OPTION_PXE_UUID 97
|
||||
#define OPTION_SUBNET_SELECT 118
|
||||
#define OPTION_VENDOR_IDENT 124
|
||||
#define OPTION_VENDOR_IDENT_OPT 125
|
||||
#define OPTION_END 255
|
||||
|
||||
#define SUBOPT_CIRCUIT_ID 1
|
||||
#define SUBOPT_REMOTE_ID 2
|
||||
#define SUBOPT_SUBNET_SELECT 5 /* RFC 3527 */
|
||||
#define SUBOPT_SUBSCR_ID 6 /* RFC 3393 */
|
||||
#define SUBOPT_SERVER_OR 11 /* RFC 5107 */
|
||||
|
||||
#define SUBOPT_PXE_BOOT_ITEM 71 /* PXE standard */
|
||||
#define SUBOPT_PXE_DISCOVERY 6
|
||||
#define SUBOPT_PXE_SERVERS 8
|
||||
#define SUBOPT_PXE_MENU 9
|
||||
#define SUBOPT_PXE_MENU_PROMPT 10
|
||||
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPDECLINE 4
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
#define BRDBAND_FORUM_IANA 3561 /* Broadband forum IANA enterprise */
|
||||
|
||||
#define have_config(config, mask) ((config) && ((config)->flags & (mask)))
|
||||
#define option_len(opt) ((int)(((unsigned char *)(opt))[1]))
|
||||
#define option_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2u+(unsigned int)(i)]))
|
||||
@@ -89,6 +26,7 @@
|
||||
static void add_extradata_data(struct dhcp_lease *lease, unsigned char *data, size_t len, int delim);
|
||||
static void add_extradata_opt(struct dhcp_lease *lease, unsigned char *opt);
|
||||
#endif
|
||||
|
||||
static int match_bytes(struct dhcp_opt *o, unsigned char *p, int len);
|
||||
static int sanitise(unsigned char *opt, char *buf);
|
||||
static struct in_addr server_id(struct dhcp_context *context, struct in_addr override, struct in_addr fallback);
|
||||
@@ -103,8 +41,8 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
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_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,
|
||||
unsigned char *agent_id, unsigned char *real_end);
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess);
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, unsigned char *agent_id, unsigned char *real_end);
|
||||
static void clear_packet(struct dhcp_packet *mess, unsigned char *end);
|
||||
static void do_options(struct dhcp_context *context,
|
||||
struct dhcp_packet *mess,
|
||||
@@ -113,11 +51,12 @@ static void do_options(struct dhcp_context *context,
|
||||
char *hostname,
|
||||
char *domain, char *config_domain,
|
||||
struct dhcp_netid *netid,
|
||||
struct in_addr subnet_addr,
|
||||
struct in_addr subnet_addr,
|
||||
unsigned char fqdn_flags,
|
||||
int null_term, int pxearch,
|
||||
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);
|
||||
@@ -129,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 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;
|
||||
struct dhcp_lease *ltmp, *lease = NULL;
|
||||
@@ -147,7 +86,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
unsigned int time;
|
||||
struct dhcp_config *config;
|
||||
struct dhcp_netid *netid, *tagif_netid;
|
||||
struct in_addr subnet_addr, fallback, override;
|
||||
struct in_addr subnet_addr, override;
|
||||
unsigned short fuzz = 0;
|
||||
unsigned int mess_type = 0;
|
||||
unsigned char fqdn_flags = 0;
|
||||
@@ -359,17 +298,43 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!context_new)
|
||||
for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
||||
if (context_tmp->netmask.s_addr &&
|
||||
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
|
||||
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
||||
{
|
||||
context_tmp->current = context_new;
|
||||
context_new = context_tmp;
|
||||
}
|
||||
{
|
||||
struct in_addr netmask = context_tmp->netmask;
|
||||
|
||||
/* guess the netmask for relayed networks */
|
||||
if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0)
|
||||
{
|
||||
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)
|
||||
context = context_new;
|
||||
|
||||
context = context_new;
|
||||
}
|
||||
|
||||
if (!context)
|
||||
@@ -380,10 +345,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* keep _a_ local address available. */
|
||||
fallback = context->local;
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
struct dhcp_context *context_tmp;
|
||||
for (context_tmp = context; context_tmp; context_tmp = context_tmp->current)
|
||||
@@ -503,9 +465,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if(&context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
if (!message && !nailed)
|
||||
{
|
||||
@@ -536,13 +499,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
clear_packet(mess, end);
|
||||
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);
|
||||
|
||||
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)))
|
||||
@@ -603,7 +566,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
client_hostname = daemon->dhcp_buff;
|
||||
}
|
||||
|
||||
if (client_hostname && daemon->options & OPT_LOG_OPTS)
|
||||
if (client_hostname && option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u client provides name: %s"), ntohl(mess->xid), client_hostname);
|
||||
|
||||
if (have_config(config, CONFIG_NAME))
|
||||
@@ -756,7 +719,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
}
|
||||
match_vendor_opts(opt, daemon->dhcp_opts);
|
||||
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (sanitise(opt, daemon->namebuff))
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u vendor class: %s"), ntohl(mess->xid), daemon->namebuff);
|
||||
@@ -857,7 +820,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);
|
||||
|
||||
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)))
|
||||
@@ -865,40 +829,52 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
pxearch = option_uint(opt, 0, 2);
|
||||
|
||||
/* proxy DHCP here. */
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)) &&
|
||||
(context->flags & CONTEXT_PROXY))
|
||||
if ((mess_type == DHCPDISCOVER || (pxe && mess_type == DHCPREQUEST)))
|
||||
{
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
clear_packet(mess, end);
|
||||
struct dhcp_context *tmp;
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
for (tmp = context; tmp; tmp = tmp->current)
|
||||
if ((tmp->flags & CONTEXT_PROXY) &&
|
||||
match_netid(tmp->filter, tagif_netid, 1))
|
||||
break;
|
||||
|
||||
if (tmp)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
struct dhcp_boot *boot = find_boot(tagif_netid);
|
||||
|
||||
mess->yiaddr.s_addr = 0;
|
||||
if (mess_type == DHCPDISCOVER || mess->ciaddr.s_addr == 0)
|
||||
{
|
||||
mess->ciaddr.s_addr = 0;
|
||||
mess->flags |= htons(0x8000); /* broadcast */
|
||||
}
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
clear_packet(mess, end);
|
||||
|
||||
/* Provide the bootfile here, for gPXE, and in case we have no menu items
|
||||
and set discovery_control = 8 */
|
||||
if (boot)
|
||||
{
|
||||
if (boot->next_server.s_addr)
|
||||
mess->siaddr = boot->next_server;
|
||||
else if (boot->tftp_sname)
|
||||
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||
|
||||
if (boot->file)
|
||||
strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
log_packet("PXE", NULL, emac, emac_len, iface_name, ignore ? "proxy-ignored" : "proxy", mess->xid);
|
||||
log_tags(tagif_netid, mess);
|
||||
return ignore ? 0 : dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1,
|
||||
mess_type == DHCPDISCOVER ? DHCPOFFER : DHCPACK);
|
||||
option_put(mess, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, htonl(context->local.s_addr));
|
||||
pxe_misc(mess, end, uuid);
|
||||
prune_vendor_opts(tagif_netid);
|
||||
do_encap_opts(pxe_opts(pxearch, tagif_netid, context->local), OPTION_VENDOR_CLASS_OPT, DHOPT_VENDOR_MATCH, mess, end, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1028,15 +1004,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)))
|
||||
return 0;
|
||||
|
||||
log_packet("DHCPOFFER" , &mess->yiaddr, emac, emac_len, iface_name, NULL, mess->xid);
|
||||
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if(&context->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));
|
||||
clear_packet(mess, end);
|
||||
option_put(mess, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||
@@ -1049,9 +1026,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);
|
||||
}
|
||||
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:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
@@ -1082,12 +1059,30 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!context)
|
||||
{
|
||||
/* 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 (!(daemon->options & OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
message = _("wrong server-ID");
|
||||
/* Handle very strange configs where clients have more than one route to the server.
|
||||
If a clients idea of its server-id matches any of our DHCP interfaces, we let it pass.
|
||||
Have to set override to make sure we echo back the correct server-id */
|
||||
struct irec *intr;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1101,7 +1096,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
else
|
||||
{
|
||||
/* INIT-REBOOT */
|
||||
if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
|
||||
if (!lease && !option_bool(OPT_AUTHORITATIVE))
|
||||
return 0;
|
||||
|
||||
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||
@@ -1116,8 +1111,13 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
as long as we can allocate the lease now - checked below.
|
||||
This makes for a smooth recovery from a lost lease DB */
|
||||
if ((lease && mess->ciaddr.s_addr != lease->addr.s_addr) ||
|
||||
(!lease && !(daemon->options & OPT_AUTHORITATIVE)))
|
||||
(!lease && !option_bool(OPT_AUTHORITATIVE)))
|
||||
{
|
||||
/* A client rebinding will broadcast the request, so we may see it even
|
||||
if the lease is held by another server. Just ignore it in that case.
|
||||
If the request is unicast to us, then somethings wrong, NAK */
|
||||
if (!unicast_dest)
|
||||
return 0;
|
||||
message = _("lease not found");
|
||||
/* ensure we broadcast NAK */
|
||||
unicast_dest = 0;
|
||||
@@ -1221,9 +1221,10 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
if (context->netid.net)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
#ifdef HAVE_SCRIPT
|
||||
if (do_classes && daemon->lease_change_command)
|
||||
@@ -1235,6 +1236,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
lease->changed = 1;
|
||||
free(lease->extradata);
|
||||
lease->extradata = NULL;
|
||||
lease->extradata_size = lease->extradata_len = 0;
|
||||
|
||||
add_extradata_opt(lease, option_find(mess, sz, OPTION_VENDOR_ID, 1));
|
||||
@@ -1325,10 +1327,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);
|
||||
}
|
||||
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:
|
||||
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||
@@ -1351,15 +1353,16 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
||||
|
||||
if (!hostname && (hostname = host_from_dns(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)
|
||||
{
|
||||
context->netid.next = netid;
|
||||
netid = &context->netid;
|
||||
tagif_netid = run_tag_if(netid);
|
||||
tagif_netid = run_tag_if( &context->netid);
|
||||
}
|
||||
|
||||
log_tags(tagif_netid, mess);
|
||||
|
||||
log_packet("DHCPACK", &mess->ciaddr, emac, emac_len, iface_name, hostname, mess->xid);
|
||||
|
||||
if (lease)
|
||||
{
|
||||
@@ -1384,10 +1387,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),
|
||||
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 */
|
||||
return dhcp_packet_size(mess, tagif_netid, agent_id, real_end);
|
||||
return dhcp_packet_size(mess, agent_id, real_end);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1479,7 +1482,7 @@ static struct in_addr server_id(struct dhcp_context *context, struct in_addr ove
|
||||
{
|
||||
if (override.s_addr != 0)
|
||||
return override;
|
||||
else if (context)
|
||||
else if (context && context->local.s_addr != 0)
|
||||
return context->local;
|
||||
else
|
||||
return fallback;
|
||||
@@ -1568,7 +1571,7 @@ static void log_packet(char *type, void *addr, unsigned char *ext_mac,
|
||||
|
||||
print_mac(daemon->namebuff, ext_mac, mac_len);
|
||||
|
||||
if(daemon->options & OPT_LOG_OPTS)
|
||||
if(option_bool(OPT_LOG_OPTS))
|
||||
my_syslog(MS_DHCP | LOG_INFO, "%u %s(%s) %s%s%s %s",
|
||||
ntohl(xid),
|
||||
type,
|
||||
@@ -1719,30 +1722,16 @@ static unsigned char *find_overload(struct dhcp_packet *mess)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t dhcp_packet_size(struct dhcp_packet *mess, struct dhcp_netid *netid,
|
||||
unsigned char *agent_id, unsigned char *real_end)
|
||||
static void log_tags(struct dhcp_netid *netid, struct dhcp_packet *mess)
|
||||
{
|
||||
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 && (daemon->options & OPT_LOG_OPTS))
|
||||
if (netid && option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
char *s = daemon->namebuff;
|
||||
for (*s = 0; netid; netid = netid->next)
|
||||
{
|
||||
/* kill dupes. */
|
||||
struct dhcp_netid *n;
|
||||
|
||||
for (n = netid->next; n; n = n->next)
|
||||
if (strcmp(netid->net, n->net) == 0)
|
||||
break;
|
||||
@@ -1756,38 +1745,47 @@ 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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. */
|
||||
overload = find_overload(mess);
|
||||
|
||||
if (overload && (option_uint(overload, 0, 1) & 1))
|
||||
{
|
||||
*dhcp_skip_opts(mess->file) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->file, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->file) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u bootfile name: %s"), ntohl(mess->xid), (char *)mess->file);
|
||||
|
||||
if (overload && (option_uint(overload, 0, 1) & 2))
|
||||
{
|
||||
*dhcp_skip_opts(mess->sname) = OPTION_END;
|
||||
if (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
log_options(mess->sname, mess->xid);
|
||||
}
|
||||
else if ((daemon->options & OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
else if (option_bool(OPT_LOG_OPTS) && strlen((char *)mess->sname) != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u server name: %s"), ntohl(mess->xid), (char *)mess->sname);
|
||||
|
||||
|
||||
*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 (daemon->options & OPT_LOG_OPTS)
|
||||
if (option_bool(OPT_LOG_OPTS))
|
||||
{
|
||||
if (mess->siaddr.s_addr != 0)
|
||||
my_syslog(MS_DHCP | LOG_INFO, _("%u next server: %s"), ntohl(mess->xid), inet_ntoa(mess->siaddr));
|
||||
@@ -1936,20 +1934,14 @@ static int in_list(unsigned char *list, int opt)
|
||||
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;
|
||||
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, 0))
|
||||
return tmp;
|
||||
|
||||
/* 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;
|
||||
|
||||
struct dhcp_opt *opts;
|
||||
|
||||
for (opts = daemon->dhcp_opts; opts; opts = opts->next)
|
||||
if (opts->opt == opt && (opts->flags & DHOPT_TAGOK))
|
||||
return opts;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2204,7 +2196,8 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char fqdn_flags,
|
||||
int null_term, int pxe_arch,
|
||||
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_boot *boot;
|
||||
@@ -2213,12 +2206,58 @@ static void do_options(struct dhcp_context *context,
|
||||
unsigned char f0 = 0, s0 = 0;
|
||||
int done_file = 0, done_server = 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)))
|
||||
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring domain %s for DHCP host name %s"), config_domain, hostname);
|
||||
|
||||
/* logging */
|
||||
if ((daemon->options & OPT_LOG_OPTS) && req_options)
|
||||
if (option_bool(OPT_LOG_OPTS) && req_options)
|
||||
{
|
||||
char *q = daemon->namebuff;
|
||||
for (i = 0; req_options[i] != OPTION_END; i++)
|
||||
@@ -2238,6 +2277,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)
|
||||
mess->siaddr = context->local;
|
||||
|
||||
@@ -2247,11 +2292,11 @@ static void do_options(struct dhcp_context *context,
|
||||
provide an manual option to disable it.
|
||||
Some PXE ROMs have bugs (surprise!) and need zero-terminated
|
||||
names, so we always send those. */
|
||||
if ((boot = find_boot(netid)))
|
||||
if ((boot = find_boot(tagif)))
|
||||
{
|
||||
if (boot->sname)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_SNAME))
|
||||
option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
|
||||
@@ -2261,7 +2306,7 @@ static void do_options(struct dhcp_context *context,
|
||||
|
||||
if (boot->file)
|
||||
{
|
||||
if (!(daemon->options & OPT_NO_OVERRIDE) &&
|
||||
if (!option_bool(OPT_NO_OVERRIDE) &&
|
||||
req_options &&
|
||||
in_list(req_options, OPTION_FILENAME))
|
||||
option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
|
||||
@@ -2269,8 +2314,10 @@ static void do_options(struct dhcp_context *context,
|
||||
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;
|
||||
else if (boot->tftp_sname)
|
||||
mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
|
||||
}
|
||||
else
|
||||
/* Use the values of the relevant options if no dhcp-boot given and
|
||||
@@ -2279,20 +2326,20 @@ static void do_options(struct dhcp_context *context,
|
||||
dhcp-optsfile. */
|
||||
{
|
||||
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);
|
||||
done_file = 1;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2300,7 +2347,7 @@ static void do_options(struct dhcp_context *context,
|
||||
fields look like they are in use, even when they aren't. This gets restored
|
||||
at the end of this function. */
|
||||
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
f0 = mess->file[0];
|
||||
mess->file[0] = 1;
|
||||
@@ -2320,36 +2367,36 @@ static void do_options(struct dhcp_context *context,
|
||||
/* replies to DHCPINFORM may not have a valid 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));
|
||||
|
||||
/* 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 */
|
||||
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));
|
||||
|
||||
/* 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. */
|
||||
if (context->router.s_addr &&
|
||||
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));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Note that we ignore attempts to set the fqdn using --dhc-option=81,<name> */
|
||||
if (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);
|
||||
|
||||
if (fqdn_flags != 0)
|
||||
@@ -2398,6 +2445,10 @@ static void do_options(struct dhcp_context *context,
|
||||
{
|
||||
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? */
|
||||
if (!(opt->flags & DHOPT_FORCE) && !in_list(req_options, optno))
|
||||
continue;
|
||||
@@ -2416,10 +2467,6 @@ static void do_options(struct dhcp_context *context,
|
||||
if (optno == OPTION_FILENAME && done_file)
|
||||
continue;
|
||||
|
||||
/* netids match and not encapsulated? */
|
||||
if (opt != option_find2(netid, config_opts, optno))
|
||||
continue;
|
||||
|
||||
/* For the options we have default values on
|
||||
dhc-option=<optionno> means "don't include this option"
|
||||
not "include a zero-length option" */
|
||||
@@ -2486,7 +2533,7 @@ static void do_options(struct dhcp_context *context,
|
||||
continue;
|
||||
|
||||
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_ENCAP_MATCH;
|
||||
@@ -2520,12 +2567,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)
|
||||
{
|
||||
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)) &&
|
||||
@@ -2537,7 +2584,7 @@ static void do_options(struct dhcp_context *context,
|
||||
memcpy(p, daemon->dhcp_buff3, vendor_class_len);
|
||||
|
||||
/* restore BOOTP anti-overload hack */
|
||||
if (!req_options || (daemon->options & OPT_NO_OVERRIDE))
|
||||
if (!req_options || option_bool(OPT_NO_OVERRIDE))
|
||||
{
|
||||
mess->file[0] = f0;
|
||||
mess->sname[0] = s0;
|
||||
|
||||
202
src/tftp.c
202
src/tftp.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -43,7 +43,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
ssize_t len;
|
||||
char *packet = daemon->packet;
|
||||
char *filename, *mode, *p, *end, *opt;
|
||||
struct sockaddr_in addr, peer;
|
||||
union mysockaddr addr, peer;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
struct ifreq ifr;
|
||||
@@ -57,6 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int mtuflag = IP_PMTUDISC_DONT;
|
||||
#endif
|
||||
char namebuff[IF_NAMESIZE];
|
||||
char pretty_addr[ADDRSTRLEN];
|
||||
char *name;
|
||||
char *prefix = daemon->tftp_prefix;
|
||||
struct tftp_prefix *pref;
|
||||
@@ -64,6 +65,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
|
||||
union {
|
||||
struct cmsghdr align; /* this ensures alignment */
|
||||
#ifdef HAVE_IPV6
|
||||
char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
|
||||
#endif
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
char control[CMSG_SPACE(sizeof(struct in_pktinfo))];
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
@@ -90,9 +94,9 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
|
||||
return;
|
||||
|
||||
if (daemon->options & OPT_NOWILD)
|
||||
if (option_bool(OPT_NOWILD))
|
||||
{
|
||||
addr = listen->iface->addr.in;
|
||||
addr = listen->iface->addr;
|
||||
mtu = listen->iface->mtu;
|
||||
name = listen->iface->name;
|
||||
}
|
||||
@@ -102,59 +106,88 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
int check;
|
||||
struct interface_list *ir;
|
||||
|
||||
addr.sin_addr.s_addr = 0;
|
||||
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||
return;
|
||||
|
||||
addr.sa.sa_family = listen->family;
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.in.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_pktinfo *p;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
addr.sin_addr = p.p->ipi_spec_dst;
|
||||
if_index = p.p->ipi_ifindex;
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_SOLARIS_NETWORK)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
unsigned int *i;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = *(p.i);
|
||||
}
|
||||
|
||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
if (listen->family == AF_INET)
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in_addr *a;
|
||||
struct sockaddr_dl *s;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||
addr.in.sin_addr = *(p.a);
|
||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||
if_index = p.s->sdl_index;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
{
|
||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == daemon->v6pktinfo)
|
||||
{
|
||||
union {
|
||||
unsigned char *c;
|
||||
struct in6_pktinfo *p;
|
||||
} p;
|
||||
p.c = CMSG_DATA(cmptr);
|
||||
|
||||
addr.in6.sin6_addr = p.p->ipi6_addr;
|
||||
if_index = p.p->ipi6_ifindex;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff) ||
|
||||
addr.sin_addr.s_addr == 0)
|
||||
if (!indextoname(listen->tftpfd, if_index, namebuff))
|
||||
return;
|
||||
|
||||
name = namebuff;
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.sin_addr, name, &if_index);
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (listen->family == AF_INET6)
|
||||
check = iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, &if_index);
|
||||
else
|
||||
#endif
|
||||
check = iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, &if_index);
|
||||
|
||||
/* wierd TFTP service override */
|
||||
for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
|
||||
@@ -189,16 +222,29 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcmp(ir->interface, name) == 0)
|
||||
special = 1;
|
||||
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_family = AF_INET;
|
||||
if (listen->family == AF_INET)
|
||||
{
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||
addr.sin_len = sizeof(addr);
|
||||
addr.in.sin_len = sizeof(addr.in);
|
||||
#endif
|
||||
|
||||
}
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
{
|
||||
addr.in6.sin6_port = htons(port);
|
||||
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
|
||||
|
||||
if (!(transfer = whine_malloc(sizeof(struct tftp_transfer))))
|
||||
return;
|
||||
|
||||
if ((transfer->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
if ((transfer->sockfd = socket(listen->family, SOCK_DGRAM, 0)) == -1)
|
||||
{
|
||||
free(transfer);
|
||||
return;
|
||||
@@ -213,11 +259,13 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
transfer->file = NULL;
|
||||
transfer->opt_blocksize = transfer->opt_transize = 0;
|
||||
transfer->netascii = transfer->carrylf = 0;
|
||||
|
||||
|
||||
prettyprint_addr(&peer, pretty_addr);
|
||||
|
||||
/* if we have a nailed-down range, iterate until we find a free one. */
|
||||
while (1)
|
||||
{
|
||||
if (bind(transfer->sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1 ||
|
||||
if (bind(transfer->sockfd, &addr.sa, sa_len(&addr)) == -1 ||
|
||||
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
|
||||
setsockopt(transfer->sockfd, SOL_IP, IP_MTU_DISCOVER, &mtuflag, sizeof(mtuflag)) == -1 ||
|
||||
#endif
|
||||
@@ -227,7 +275,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
{
|
||||
if (++port <= daemon->end_tftp_port)
|
||||
{
|
||||
addr.sin_port = htons(port);
|
||||
if (listen->family == AF_INET)
|
||||
addr.in.sin_port = htons(port);
|
||||
#ifdef HAVE_IPV6
|
||||
else
|
||||
addr.in6.sin6_port = htons(port);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("unable to get free port for TFTP"));
|
||||
@@ -245,7 +298,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
!(filename = next(&p, end)) ||
|
||||
!(mode = next(&p, end)) ||
|
||||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), inet_ntoa(peer.sin_addr));
|
||||
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), pretty_addr);
|
||||
else
|
||||
{
|
||||
if (strcasecmp(mode, "netascii") == 0)
|
||||
@@ -256,7 +309,7 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (strcasecmp(opt, "blksize") == 0)
|
||||
{
|
||||
if ((opt = next(&p, end)) &&
|
||||
(special || !(daemon->options & OPT_TFTP_NOBLOCK)))
|
||||
(special || !option_bool(OPT_TFTP_NOBLOCK)))
|
||||
{
|
||||
transfer->blocksize = atoi(opt);
|
||||
if (transfer->blocksize < 1)
|
||||
@@ -290,12 +343,12 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
if (prefix[strlen(prefix)-1] != '/')
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
if (!special && (daemon->options & OPT_TFTP_APREF))
|
||||
if (!special && option_bool(OPT_TFTP_APREF))
|
||||
{
|
||||
size_t oldlen = strlen(daemon->namebuff);
|
||||
struct stat statbuf;
|
||||
|
||||
strncat(daemon->namebuff, inet_ntoa(peer.sin_addr), (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, pretty_addr, (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
strncat(daemon->namebuff, "/", (MAXDNAME-1) - strlen(daemon->namebuff));
|
||||
|
||||
/* remove unique-directory if it doesn't exist */
|
||||
@@ -333,7 +386,6 @@ void tftp_request(struct listener *listen, time_t now)
|
||||
free_transfer(transfer);
|
||||
else
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), daemon->namebuff, inet_ntoa(peer.sin_addr));
|
||||
transfer->next = daemon->tftp_trans;
|
||||
daemon->tftp_trans = transfer;
|
||||
}
|
||||
@@ -376,7 +428,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, int spe
|
||||
goto perm;
|
||||
}
|
||||
/* in secure mode, must be owned by user running dnsmasq */
|
||||
else if (!special && (daemon->options & OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
else if (!special && option_bool(OPT_TFTP_SECURE) && uid != statbuf.st_uid)
|
||||
goto perm;
|
||||
|
||||
/* If we're doing many tranfers from the same file, only
|
||||
@@ -426,6 +478,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
struct tftp_transfer *transfer, *tmp, **up;
|
||||
ssize_t len;
|
||||
char pretty_addr[ADDRSTRLEN];
|
||||
|
||||
struct ack {
|
||||
unsigned short op, block;
|
||||
@@ -440,6 +493,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
{
|
||||
/* we overwrote the buffer... */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
prettyprint_addr(&transfer->peer, pretty_addr);
|
||||
|
||||
if ((len = recv(transfer->sockfd, daemon->packet, daemon->packet_buff_sz, 0)) >= (ssize_t)sizeof(struct ack))
|
||||
{
|
||||
@@ -456,20 +511,22 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
char *p = daemon->packet + sizeof(struct ack);
|
||||
char *end = daemon->packet + len;
|
||||
char *err = next(&p, end);
|
||||
|
||||
/* Sanitise error message */
|
||||
if (!err)
|
||||
err = "";
|
||||
else
|
||||
{
|
||||
char *q, *r;
|
||||
for (q = r = err; *r; r++)
|
||||
if (isprint((int)*r))
|
||||
unsigned char *q, *r;
|
||||
for (q = r = (unsigned char *)err; *r; r++)
|
||||
if (isprint(*r))
|
||||
*(q++) = *r;
|
||||
*q = 0;
|
||||
}
|
||||
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("error %d %s received from %s"),
|
||||
(int)ntohs(mess->block), err,
|
||||
inet_ntoa(transfer->peer.sin_addr));
|
||||
pretty_addr);
|
||||
|
||||
/* Got err, ensure we take abort */
|
||||
transfer->timeout = now;
|
||||
@@ -498,9 +555,12 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
/* don't complain about timeout when we're awaiting the last
|
||||
ACK, some clients never send it */
|
||||
if (len != 0)
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, inet_ntoa(transfer->peer.sin_addr));
|
||||
len = 0;
|
||||
{
|
||||
my_syslog(MS_TFTP | LOG_ERR, _("failed sending %s to %s"),
|
||||
transfer->file->filename, pretty_addr);
|
||||
len = 0;
|
||||
endcon = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
@@ -509,6 +569,8 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
|
||||
if (endcon || len == 0)
|
||||
{
|
||||
if (!endcon)
|
||||
my_syslog(MS_TFTP | LOG_INFO, _("sent %s to %s"), transfer->file->filename, pretty_addr);
|
||||
/* unlink */
|
||||
*up = tmp;
|
||||
free_transfer(transfer);
|
||||
@@ -517,7 +579,7 @@ void check_tftp_listeners(fd_set *rset, time_t now)
|
||||
}
|
||||
|
||||
up = &transfer->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free_transfer(struct tftp_transfer *transfer)
|
||||
@@ -628,15 +690,13 @@ static ssize_t get_block(char *packet, struct tftp_transfer *transfer)
|
||||
for (i = 0, newcarrylf = 0; i < size; i++)
|
||||
if (mess->data[i] == '\n' && ( i != 0 || !transfer->carrylf))
|
||||
{
|
||||
if (size == transfer->blocksize)
|
||||
{
|
||||
transfer->expansion++;
|
||||
if (i == size - 1)
|
||||
newcarrylf = 1; /* don't expand LF again if it moves to the next block */
|
||||
}
|
||||
else
|
||||
transfer->expansion++;
|
||||
|
||||
if (size != transfer->blocksize)
|
||||
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 */
|
||||
memmove(&mess->data[i+1], &mess->data[i], size - (i + 1));
|
||||
mess->data[i] = '\r';
|
||||
|
||||
40
src/util.c
40
src/util.c
@@ -1,4 +1,4 @@
|
||||
/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
|
||||
/* 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
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
#include <idna.h>
|
||||
#endif
|
||||
|
||||
@@ -43,11 +43,9 @@ unsigned short rand16(void)
|
||||
|
||||
/* SURF random number generator */
|
||||
|
||||
typedef unsigned int uint32;
|
||||
|
||||
static uint32 seed[32];
|
||||
static uint32 in[12];
|
||||
static uint32 out[8];
|
||||
static u32 seed[32];
|
||||
static u32 in[12];
|
||||
static u32 out[8];
|
||||
|
||||
void rand_init()
|
||||
{
|
||||
@@ -66,7 +64,7 @@ void rand_init()
|
||||
|
||||
static void surf(void)
|
||||
{
|
||||
uint32 t[12]; uint32 x; uint32 sum = 0;
|
||||
u32 t[12]; u32 x; u32 sum = 0;
|
||||
int r; int i; int loop;
|
||||
|
||||
for (i = 0;i < 12;++i) t[i] = in[i] ^ seed[12 + i];
|
||||
@@ -120,11 +118,11 @@ static int check_name(char *in)
|
||||
dotgap = 0;
|
||||
else if (++dotgap > MAXLABEL)
|
||||
return 0;
|
||||
else if (isascii(c) && iscntrl(c))
|
||||
else if (isascii((unsigned char)c) && iscntrl((unsigned char)c))
|
||||
/* iscntrl only gives expected results for ascii */
|
||||
return 0;
|
||||
#ifndef LOCALEDIR
|
||||
else if (!isascii(c))
|
||||
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
|
||||
else if (!isascii((unsigned char)c))
|
||||
return 0;
|
||||
#endif
|
||||
else if (c != ' ')
|
||||
@@ -170,7 +168,7 @@ int legal_hostname(char *name)
|
||||
char *canonicalise(char *in, int *nomem)
|
||||
{
|
||||
char *ret = NULL;
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
@@ -180,7 +178,7 @@ char *canonicalise(char *in, int *nomem)
|
||||
if (!check_name(in))
|
||||
return NULL;
|
||||
|
||||
#ifdef LOCALEDIR
|
||||
#if defined(LOCALEDIR) || defined(HAVE_IDN)
|
||||
if ((rc = idna_to_ascii_lz(in, &ret, 0)) != IDNA_SUCCESS)
|
||||
{
|
||||
if (ret)
|
||||
@@ -335,7 +333,15 @@ int prettyprint_addr(union mysockaddr *addr, char *buf)
|
||||
}
|
||||
else if (addr->sa.sa_family == AF_INET6)
|
||||
{
|
||||
char name[IF_NAMESIZE];
|
||||
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);
|
||||
}
|
||||
#else
|
||||
@@ -365,7 +371,8 @@ void prettyprint_time(char *buf, unsigned int t)
|
||||
}
|
||||
|
||||
|
||||
/* in may equal out, when maxlen may be -1 (No max len). */
|
||||
/* in may equal out, when maxlen may be -1 (No max len).
|
||||
Return -1 for extraneous no-hex chars found. */
|
||||
int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
unsigned int *wildcard_mask, int *mac_type)
|
||||
{
|
||||
@@ -377,7 +384,10 @@ int parse_hex(char *in, unsigned char *out, int maxlen,
|
||||
|
||||
while (maxlen == -1 || i < maxlen)
|
||||
{
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++);
|
||||
for (r = in; *r != 0 && *r != ':' && *r != '-'; r++)
|
||||
if (*r != '*' && !isxdigit((unsigned char)*r))
|
||||
return -1;
|
||||
|
||||
if (*r == 0)
|
||||
maxlen = i;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user