Compare commits

..

3 Commits
v2.87 ... v2.65

Author SHA1 Message Date
Simon Kelley
8f6698643b Fix regexp fubar in bld/get-version 2012-12-14 11:48:26 +00:00
Simon Kelley
c2e5c8d7cf Bump debian version for 2.65 release. 2012-12-14 11:34:57 +00:00
Simon Kelley
95050a8d8b Backport fixes for 2.65 release. 2012-12-14 11:33:02 +00:00
129 changed files with 14204 additions and 47793 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
VERSION export-subst

14
.gitignore vendored
View File

@@ -1,14 +0,0 @@
src/*.o
src/*.mo
src/dnsmasq.pot
src/dnsmasq
src/dnsmasq_baseline
src/.copts_*
contrib/lease-tools/dhcp_lease_time
contrib/lease-tools/dhcp_release
contrib/lease-tools/dhcp_release6
debian/files
debian/substvars
debian/utils-substvars
debian/trees/
debian/build/

3560
CHANGELOG

File diff suppressed because it is too large Load Diff

View File

@@ -56,7 +56,7 @@ release 0.95 Major rewrite: remove calls to gethostbyname() and talk
any more memory after start-up. The NAT-like forwarding was
inspired by a suggestion from Eli Chen <eli@routefree.com>
release 0.96 Fixed embarrassing thinko in cache linked-list code.
release 0.96 Fixed embarrasing thinko in cache linked-list code.
release 0.98 Some enhancements and bug-fixes.
Thanks to "Denis Carre" <denis.carre@laposte.net> and Martin
@@ -78,7 +78,7 @@ release 0.98 Some enhancements and bug-fixes.
ids, to thwart DNS spoofers.
(7) Dnsmasq no longer forwards queries when the
"recursion desired" bit is not set in the header.
(8) Fixed getopt code to work on compilers with unsigned char.
(8) Fixed getopt code to work on compliers with unsigned char.
release 0.991 Added -b flag: when set causes dnsmasq to always answer
reverse queries on the RFC 1918 private IP space itself and
@@ -88,7 +88,7 @@ release 0.991 Added -b flag: when set causes dnsmasq to always answer
Fixed a bug which stopped dnsmasq working on a box with
two or more interfaces with the same IP address.
Fixed caching of CNAMEs. Previously, a CNAME which pointed
Fixed cacheing of CNAMEs. Previously, a CNAME which pointed
to a name with many A records would not have all the addresses
returned when being answered from the cache.
@@ -191,7 +191,7 @@ release 1.1 Added --user argument to allow user to change to
release 1.2 Added IPv6 DNS record support. AAAA records are cached
and read from /etc/hosts. Reverse-lookups in the
ip6.int and ip6.arpa domains are supported. Dnsmasq can
ip6.int and ip6.arpa domains are suppored. Dnsmasq can
talk to upstream servers via IPv6 if it finds IP6 addresses
in /etc/resolv.conf and it offers DNS service automatically
if IPv6 support is present in the kernel.
@@ -214,7 +214,7 @@ release 1.3 Some versions of the Linux kernel return EINVAL rather
starting, rather than after the first query - principle
of least surprise applies here.
release 1.4 Fix a bug with DHCP lease parsing which broke in
release 1.4 Fix a bug with DHPC lease parsing which broke in
non-UTC timezones. Thanks to Mark Wormgoor for
spotting and diagnosing this. Fixed versions in
the .spec files this time. Fixed bug in Suse startup
@@ -258,7 +258,7 @@ release 1.7 Fix a problem with cache not clearing properly
on receipt of SIGHUP. Bug spotted by Sat Deshpande.
In group-id changing code:
1) Drop supplementary groups.
1) Drop supplimentary groups.
2) Change gid before dropping root (patch from Soewono Effendi.)
3) Change group to "dip" if it exists, to allow access
to /etc/ppp/resolv.conf (suggestion from Jorg Sommer.)
@@ -297,7 +297,7 @@ release 1.9 Fixes to rpm .spec files.
required. The difference is not really visible with
bloated libcs like glibc, but should dramatically reduce
memory requirements when linked against ulibc for use on
embedded routers, and that's the point really. Thanks to
embeded routers, and that's the point really. Thanks to
Matthew Natalier for prompting this.
Changed debug mode (-d) so that all logging appears on
@@ -319,12 +319,12 @@ release 1.9 Fixes to rpm .spec files.
uClinux. Thanks to Matthew Natalier for uClinux stuff.
release 1.10 Log warnings if resolv.conf or dhcp.leases are not
accessible for any reason, as suggested by Hinrich Eilts.
accessable for any reason, as suggested by Hinrich Eilts.
Fixed wrong address printing in error message about
no interface with address.
Updated docs and split installation instructions into setup.html.
Updated docs and split installation instuctions into setup.html.
Fix bug in CNAME chasing code: One CNAME pointing
to many A records would lose A records after the
@@ -346,7 +346,7 @@ release 1.10 Log warnings if resolv.conf or dhcp.leases are not
Added -S option to directly specify upstream servers and
added ability to direct queries for specific domains to
specific servers. Suggested by Jens Vonderheide.
specfic servers. Suggested by Jens Vonderheide.
Upgraded random ID generation - patch from Rob Funk.
@@ -386,13 +386,13 @@ release 1.11 Actually implement the -R flag promised in the 1.10 man page.
names in /etc/hosts -suggestion from Phil Harman.
Always return a zero time-to-live for names derived from
DHCP which stops anything else caching these
DHCP which stops anthing else caching these
names. Previously the TTL was derived from the lease
time but that is incorrect since a lease can be given
up early: dnsmasq would know this but anything with the
name cached with long TTL would not be updated.
Extended HAVE_IPV6 config flag to allow compilation on
Extended HAVE_IPV6 config flag to allow compliation on
old systems which don't have modern library routines
like inet_ntop(). Thanks to Phil Harman for the patch.
@@ -471,7 +471,7 @@ release 1.14 Fixed man page description of -b option which confused
/etc/resolv.conf.
(Thanks to Klaas Teschauer)
Check that received queries have only rfc1035-legal characters
Check that recieved queries have only rfc1035-legal characters
in them. This check is mainly to avoid bad strings being
sent to syslog.
@@ -549,7 +549,7 @@ release 1.16 Allow "/" characters in domain names - this fixes
release 1.17 Fixed crash with DHCP hostnames > 40 characters.
Fixed name-comparison routines to not depend on Locale,
Fixed name-comparision routines to not depend on Locale,
in theory this versions since 1.15 could lock up or give
wrong results when run with locale != 'C'.
@@ -574,7 +574,7 @@ release 1.18 Added round-robin DNS for names which have more than one
forwarded because -D is in effect, return NXDOMAIN not
an empty reply.
Add code to return the software version in response to the
Add code to return the software version in repsonse to the
correct magic query in the same way as BIND. Use
"dig version.bind chaos txt" to make the query.
@@ -635,7 +635,7 @@ release 2.0
dynamic allocation.
Allow dhcp-host options for the same host with different
IP addresses where the correct one will be selected for
IP adresses where the correct one will be selected for
the network the host appears on.
Fix parsing of --dhcp-option to allow more than one
@@ -674,7 +674,7 @@ release 2.1
Fix unaligned access warnings on BSD/Alpha.
Allow empty DHCP options, like so: dhcp-option=44
Allow empty DHCP options, like so: dhpc-option=44
Allow single-byte DHCP options like so: dhcp-option=20,1
@@ -745,7 +745,7 @@ release 2.3
around a bug in the DHCP client in HP Jetdirect printers.
Thanks to Marko Stolle for finding this problem.
Return DHCP T1 and T2 times, with "fuzz" to desynchronise lease
Return DHCP T1 and T2 times, with "fuzz" to desychronise lease
renewals, as specified in the RFC.
Ensure that the END option is always present in DHCP
@@ -838,7 +838,7 @@ release 2.4
by Chad Skeeters.
Fixed bug in /etc/ethers parsing code triggered by tab
characters. Kudos to Dag Wieers for helping to nail that
characters. Qudos to Dag Wieers for hepling to nail that
one.
Added "bind-interfaces" option correctly.
@@ -975,7 +975,7 @@ release 2.8
configuration. Specifically: (1) options are matched on
the netids from dhcp-range, dhcp-host, vendor class and
user class(es). Multiple net-ids are allowed and options
are searched on them all. (2) matches against vendor class
are searched on them all. (2) matches agains vendor class
and user class are now on a substring, if the given
string is a substring of the vendor/user class, then a
match occurs. Thanks again to Richard Musil for prompting
@@ -997,7 +997,7 @@ release 2.8
Add checks against DHCP clients which return zero-length
hostnames. This avoids the potential lease-loss problems
referred to above. Also, if a client sends a hostname when
reffered to above. Also, if a client sends a hostname when
it creates a lease but subsequently sends no or a
zero-length hostname whilst renewing, continue to use the
existing hostname, don't wipe it out.
@@ -1010,7 +1010,7 @@ release 2.9
but to the address of another interface were ignored
unless the loopback interface was explicitly configured.
2) on OpenBSD failure to configure one interface now
causes a fatal error on startup rather than a huge
causes a fatal error on startup rather than an huge
stream of log messages. Thanks to Erik Jan Tromp for
finding that bug.
@@ -1019,7 +1019,7 @@ release 2.9
broken. The new algorithm is to pick as before for the
first try, but if a query is retried, to send to all
available servers in parallel. The first one to reply
then becomes preferred for the next query. This should
then becomes prefered for the next query. This should
improve reliability without generating significant extra
upstream load.
@@ -1027,7 +1027,7 @@ release 2.9
unqualified domains introduced in version 2.8
Allow fallback to "bind-interfaces" at runtime: Some
versions of *BSD seem to have enough stuff in the header
verions of *BSD seem to have enough stuff in the header
files to build but no kernel support. Also now log if
"bind-interfaces" is forced on.
@@ -1049,7 +1049,7 @@ release 2.9
first name found is now returned for reverse lookups,
rather than all of them.
Add back fatal errors when nonexistent
Add back fatal errors when nonexistant
interfaces or interface addresses are given but only in
"bind-interfaces" mode. Principle of least surprise applies.
@@ -1193,7 +1193,7 @@ version 2.14
version 2.15
Fixed NXDOMAIN/NODATA confusion for locally known
names. We now return a NODATA response for names which are
names. We now return a NODATA reponse for names which are
locally known. Now a query for (eg AAAA or MX) for a name
with an IPv4 address in /etc/hosts which fails upstream
will generate a NODATA response. Note that the query
@@ -1229,7 +1229,7 @@ version 2.16
Set NONBLOCK on all listening sockets to workaround non-POSIX
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
occurred when corrupted packets were received. Thanks to
occured when corrupted packets were received. Thanks to
Joris van Rantwijk for chasing that down.
Updated config.h for NetBSD. Thanks to Martin Lambers.
@@ -1297,7 +1297,7 @@ version 2.18
interfaces with more than one IPv6 address. Thanks to
Martin Pels for help with that.
Fix problems which occurred when more than one dhcp-range
Fix problems which occured when more than one dhcp-range
was specified in the same subnet: sometimes parameters
(lease time, network-id tag) from the wrong one would be
used. Thanks to Rory Campbell-Lange for the bug report.
@@ -1314,7 +1314,7 @@ version 2.19
Thanks to Richard Atterer for the bug report.
Check for under-length option fields in DHCP packets, a
zero length client-id, in particular, could seriously
zero length client-id, in particluar, could seriously
confuse dnsmasq 'till now. Thanks to Will Murname for help
with that.
@@ -1389,7 +1389,7 @@ version 2.21
recursive queries.
Fix DHCP address allocation problem when netid tags are in
use. Thanks to Will Murname for the bug report and
use. Thanks to Will Murnane for the bug report and
subsequent testing.
Add an additional data section to the reply for MX and SRV
@@ -1505,7 +1505,7 @@ version 2.23
from dnsmasq --version. Thanks to Dirk Schenkewitz for
the suggestion.
Fix pathological behaviour when a broken client keeps sending
Fix pathalogical behaviour when a broken client keeps sending
DHCPDISCOVER messages repeatedly and fast. Because dealing with
each of these takes a few seconds, (because of the ping) then a
queue of DHCP packets could build up. Now, the results of a ping
@@ -1593,7 +1593,7 @@ version 2.24
than one dhcp-range is available. Thanks to Sorin Panca
for help chasing this down.
Added more explicit error messages to the hosts file and
Added more explict error mesages to the hosts file and
ethers file reading code. Markus Kaiserswerth suffered to
make this happen.
@@ -1617,7 +1617,7 @@ version 2.25
Fixed Suse spec file - thanks to Steven Springl.
Fixed DHCP bug when two distinct subnets are on the same
Fixed DHCP bug when two distict subnets are on the same
physical interface. Thanks to Pawel Zawora for finding
this and suggesting the fix.
@@ -1740,7 +1740,7 @@ version 2.28
Fixed regression in netlink code under 2.2.x kernels which
occurred in 2.27. Erik Jan Tromp is the vintage kernel fan
who found this. P.S. It looks like this "netlink bind:
permission denied" problem occurred in kernels at least as
permission denied" problem occured in kernels at least as
late a 2.4.18. Good information from Alain Richoux.
Added a warning when it's impossible to give a host its
@@ -1761,7 +1761,7 @@ version 2.28
Eric House and Eric Spakman for help in chasing this down.
Tolerate configuration screwups which lead to the DHCP
server attempting to allocate its own address to a
server attemping to allocate its own address to a
client; eg setting the whole subnet range as a DHCP
range. Addresses in use by the server are now excluded
from use by clients.
@@ -2067,7 +2067,7 @@ version 2.36
kernel. Thanks to Philip Wall for the bug report.
Added --dhcp-bridge option, but only to the FreeBSD
build. This fixes an oddity with a particular bridged
build. This fixes an oddity with a a particular bridged
network configuration on FreeBSD. Thanks to Luigi Rizzo
for the patch.
@@ -2273,7 +2273,7 @@ version 2.40
this.
Use client-id as hash-seed for DHCP address allocation
with Firewire and InfiniBand, as these don't supply a MAC
with Firewire and Infiniband, as these don't supply an MAC
address.
Tweaked TFTP file-open code to make it behave sensibly
@@ -2307,7 +2307,7 @@ version 2.40
Continue to use unqualified hostnames provided by DHCP
clients, even if the domain part is illegal. (The domain
is ignored, and an error logged.) Previously in this
situation, the whole name would have been
situation, the whole name whould have been
rejected. Thanks to Jima for the patch.
Handle EINTR returns from wait() correctly and reap
@@ -2319,7 +2319,7 @@ version 2.40
leases file and passed to the lease-change
script. Suggestion from Ben Voigt.
Re-run the lease change script with an "old" event for
Re-run the lease chamge script with an "old" event for
each lease when dnsmasq receives a SIGHUP.
Added more useful exit codes, including passing on a
@@ -2417,7 +2417,7 @@ version 2.41
Changed behavior of DHCP server to always return total length of
a new lease in DHCPOFFER, even if an existing lease
exists. (It used to return the time remaining on the lease
when one existed.) This fixes problems with the Sony Ericsson
whne one existed.) This fixes problems with the Sony Ericsson
K610i phone. Thanks to Hakon Stordahl for finding and
fixing this.
@@ -2433,7 +2433,7 @@ version 2.41
Add --dhcp-match flag, to check for arbitrary options in
DHCP messages from clients. This enables use of dnsmasq
with iPXE. Thanks to Rance Hall for the suggestion.
with gPXE. Thanks to Rance Hall for the suggestion.
Added --dhcp-broadcast, to force broadcast replies to DHCP
clients which need them but are too dumb or too old to
@@ -2476,7 +2476,7 @@ version 2.42
Fix OS detection logic to cope with GNU/FreeBSD.
Fix uninitialised variable in DBus code - thanks to Roy
Fix unitialised variable in DBus code - thanks to Roy
Marples.
Fix network enumeration code to work on later NetBSD -

43
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@@ -291,7 +291,7 @@ convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
Copyright (C) 19yy <name of author>
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
@@ -303,16 +303,17 @@ the "copyright" line and a pointer to where the full notice is found.
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
@@ -335,5 +336,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

98
FAQ
View File

@@ -9,7 +9,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
from port 53 the replies would be _to_ port 53 and get blocked.
This is not a security hole since dnsmasq will only accept replies to that
port: queries are dropped. The replies must be to outstanding queries
port: queries are dropped. The replies must be to oustanding queries
which dnsmasq has forwarded, otherwise they are dropped too.
Addendum: dnsmasq now has the option "query-port" (-Q), which allows
@@ -22,7 +22,7 @@ A: The high ports that dnsmasq opens are for replies from the upstream
now uses a new, randomly selected, port for each query. The old
default behaviour (use one port allocated by the OS) is available by
setting --query-port=0, and setting the query port to a positive
value still works. You should think hard and know what you are
value is still works. You should think hard and know what you are
doing before using either of these options.
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
@@ -59,7 +59,7 @@ A: Yes, there is explicit support for *BSD and MacOS X and Solaris.
Q: My company's nameserver knows about some names which aren't in the
public DNS. Even though I put it first in /etc/resolv.conf, it
doesn't work: dnsmasq seems not to use the nameservers in the order
dosen't work: dnsmasq seems not to use the nameservers in the order
given. What am I doing wrong?
A: By default, dnsmasq treats all the nameservers it knows about as
@@ -112,7 +112,7 @@ A: Resolver code sometime does strange things when given names without
hostname will fix things. (ie "ping myhost" fails, but "ping
myhost." works. The solution is to make sure that all your hosts
have a domain set ("domain" in resolv.conf, or set a domain in
your DHCP server, see below for Windows XP and Mac OS X).
your DHCP server, see below fr Windows XP and Mac OS X).
Any domain will do, but "localnet" is traditional. Now when you
resolve "myhost" the resolver will attempt to look up
"myhost.localnet" so you need to have dnsmasq reply to that name.
@@ -144,19 +144,19 @@ Q: Who are Verisign, what do they have to do with the bogus-nxdomain
option in dnsmasq and why should I wory about it?
A: [note: this was written in September 2003, things may well change.]
Verisign run the .com and .net top-level-domains. They have just
Versign run the .com and .net top-level-domains. They have just
changed the configuration of their servers so that unknown .com and
.net domains, instead of returning an error code NXDOMAIN, (no such
domain) return the address of a host at Verisign which runs a web
domain) return the address of a host at Versign which runs a web
server showing a search page. Most right-thinking people regard
this new behaviour as broken :-). You can test to see if you are
suffering Verisign brokenness by run a command like
suffering Versign brokeness by run a command like
host jlsdajkdalld.com
If you get "jlsdajkdalld.com" does not exist, then all is fine, if
host returns an IP address, then the DNS is broken. (Try a few
different unlikely domains, just in case you picked a weird one
different unlikely domains, just in case you picked a wierd one
which really _is_ registered.)
Assuming that your DNS is broken, and you want to fix it, simply
@@ -180,7 +180,7 @@ A: There are a couple of configuration gotchas which have been
whilst the ISC one works.
The first thing to check is the broadcast address set for the
ethernet interface. This is normally the address on the connected
ethernet interface. This is normally the adddress on the connected
network with all ones in the host part. For instance if the
address of the ethernet interface is 192.168.55.7 and the netmask
is 255.255.255.0 then the broadcast address should be
@@ -205,7 +205,7 @@ A: By default, none of the DHCP clients send the host-name when asking
send with the "hostname" keyword in /etc/network/interfaces. (See
"man interfaces" for details.) That doesn't work for dhclient, were
you have to add something like "send host-name daisy" to
/etc/dhclient.conf [Update: the latest dhcpcd packages _do_ send
/etc/dhclient.conf [Update: the lastest dhcpcd packages _do_ send
the hostname by default.
Q: I'm network booting my machines, and trying to give them static
@@ -236,11 +236,11 @@ Q: What network types are supported by the DHCP server?
A: Ethernet (and 802.11 wireless) are supported on all platforms. On
Linux all network types (including FireWire) are supported.
Q: What are these strange "bind-interfaces" and "bind-dynamic" options?
Q: What are these strange "bind-interface" and "bind-dynamic" options?
A: Dnsmasq from v2.63 can operate in one of three different "networking
modes". This is unfortunate as it requires users configuring dnsmasq
to take into account some rather bizarre constraints and select the
to take into account some rather bizzare contraints and select the
mode which best fits the requirements of a particular installation.
The origin of these are deficiencies in the Unix networking
model and APIs and each mode has different advantages and
@@ -252,10 +252,10 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
The three modes are "wildcard", "bind-interfaces" and "bind-dynamic".
In "wildcard" mode, dnsmasq binds the wildcard IP address (0.0.0.0 or
::). This allows it to receive all the packets sent to the server on
::). This allows it to recieve all the packets sent to the server on
the relevant port. Access control (--interface, --except-interface,
--listen-address, etc) is implemented by dnsmasq: it queries the
kernel to determine the interface on which a packet was received and
kernel to determine the interface on which a packet was recieved and
the address to which it was sent, and applies the configured
rules. Wildcard mode is the default if neither of the other modes are
specified.
@@ -276,7 +276,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
The mode chosen has four different effects: co-existence with other
servers, semantics of --interface access control, effect of new
interfaces, and legality of --interface specifications for
non-existent interfaces. We will deal with these in order.
non-existent inferfaces. We will deal with these in order.
A dnsmasq instance running in wildcard mode precludes a machine from
running a second instance of dnsmasq or any other DNS, TFTP or DHCP
@@ -297,7 +297,7 @@ A: Dnsmasq from v2.63 can operate in one of three different "networking
by dnsmasq when in --bind-interfaces mode. In wildcard or bind-dynamic
mode, such interfaces are handled normally.
An --interface specification for a non-existent interface is a fatal
A --interface specification for a non-existent interface is a fatal
error at start-up when in --bind-interfaces mode, by just generates a
warning in wildcard or bind-dynamic mode.
@@ -313,25 +313,15 @@ Q: Can I get email notification when a new version of dnsmasq is
released?
A: Yes, new releases of dnsmasq are always announced through
freshmeat.net, and they allow you to subscribe to email alerts when
freshmeat.net, and they allow you to subcribe to email alerts when
new versions of particular projects are released. New releases are
also announced in the dnsmasq-discuss mailing list, subscribe at
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
Q: What does the dhcp-authoritative option do?
A: The DHCP spec says that when a DHCP server receives a renewal request
from a client it has no knowledge of, it should just ignore it.
This is because it's supported to have more than one DHCP server
on a network, and another DHCP server may be dealing with the client.
This has the unfortunate effect that when _no_ DHCP replies to
the client, it takes some time for the client to time-out and start
to get a new lease. Setting this option makes dnsmasq violate the
standard to the extent that it will send a NAK reply to the client,
causing it to immediately start to get a new lease. This improves
behaviour when machines move networks, and in the case that the DHCP
lease database is lost. As long as there are not more tha one DHCP
server on the network, it's safe to enable the option.
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
lease?
@@ -359,64 +349,18 @@ A: By default, the identity of a machine is determined by using the
method for setting the client-id varies with DHCP client software,
dhcpcd uses the "-I" flag. Windows uses a registry setting,
see http://www.jsiinc.com/SUBF/TIP2800/rh2845.htm
Addendum:
From version 2.46, dnsmasq has a solution to this which doesn't
involve setting client-IDs. It's possible to put more than one MAC
address in a --dhcp-host configuration. This tells dnsmasq that it
should use the specified IP for any of the specified MAC addresses,
and furthermore it gives dnsmasq permission to summarily abandon a
and furthermore it gives dnsmasq permission to sumarily abandon a
lease to one of the MAC addresses if another one comes along. Note
that this will work fine only as longer as only one interface is
up at any time. There is no way for dnsmasq to enforce this
constraint: if you configure multiple MAC addresses and violate
this rule, bad things will happen.
Addendum-II: The link above is dead, the former contents of the link are:
------------------------------------------------------------------------------
How can I keep the same DHCP client reservation, if the MAC address changes?
When you reserve an IP address for a DHCP client, you provide the
MAC address of the client's NIC.
It is possible to use a custom identifier, which is sent as
option 61 in the client's DHCP Discover and Request packet.
The DhcpClientIdentifier is a REG_DWORD value that is located at:
Windows NT 4.0 SP2+
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Adapter Name>'X'\Parameters\Tcpip
where <Adapter Name> is the NIC driver name and 'X' is the number of the NIC.
Windows 2000
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TcpIp\Parameters\Interfaces\<NIC GUID>
where <NIC GUID> is the GUID of the NIC.
The valid range of data is 0x0 - 0xFFFFFFFF. The custom identifier is send as 4 bytes,
8 hexadecimal character, in groups of 2 hexadecimal characters, with the groups being
sent in reverse order. If the custom identifier is less than 8 hexadeciaml characters,
it is zero padded at the end. Examples:
Custom Client Client Reservation
Identifier on DHCP Server
12345678 78563412
123456 56341200
1234 34120000
1234567 67452301
12345 45230100
123 23010000
A18F42 428FA100
CF432 32F40C00
C32D1BE BED1320C
-------------------------------------------------------------------------------------------------------
Q: Can dnsmasq do DHCP on IP-alias interfaces?
A: Yes, from version-2.21. The support is only available running under
@@ -544,7 +488,7 @@ Q: DHCP doesn't work with windows 7 but everything else is fine.
A: There seems to be a problem if Windows 7 doesn't get a value for
DHCP option 252 in DHCP packets it gets from the server. The
symptoms have been variously reported as continual DHCPINFORM
symtoms have beeen variously reported as continual DHCPINFORM
requests in an attempt to get an option-252, or even ignoring DHCP
offers completely (and failing to get an IP address) if there is no
option-252 supplied. DHCP option 252 is for WPAD, WWW Proxy

View File

@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2022 Simon Kelley
# dnsmasq is Copyright (c) 2000-2012 Simon Kelley
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -51,65 +51,41 @@ top!=pwd
# GNU make way.
top?=$(CURDIR)
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
ubus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_UBUS "" --copy '-lubox -lubus'`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
idn2_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --cflags libidn2`
idn2_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LIBIDN2 $(PKG_CONFIG) --libs libidn2`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.2`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.2`
nettle_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --cflags 'nettle hogweed' \
HAVE_CRYPTOHASH $(PKG_CONFIG) --cflags nettle \
HAVE_NETTLEHASH $(PKG_CONFIG) --cflags nettle`
nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CONFIG) --libs 'nettle hogweed' \
HAVE_CRYPTOHASH $(PKG_CONFIG) --libs nettle \
HAVE_NETTLEHASH $(PKG_CONFIG) --libs nettle`
gmp_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC NO_GMP --copy -lgmp`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --cflags libnftables`
nft_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
sum?=$(shell $(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
sum!=$(CC) -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
copts_conf = .copts_$(sum)
dbus_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --cflags dbus-1`
dbus_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DBUS $(PKG_CONFIG) --libs dbus-1`
idn_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --cflags libidn`
idn_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_IDN $(PKG_CONFIG) --libs libidn`
ct_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --cflags libnetfilter_conntrack`
ct_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_CONNTRACK $(PKG_CONFIG) --libs libnetfilter_conntrack`
lua_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --cflags lua5.1`
lua_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_LUASCRIPT $(PKG_CONFIG) --libs lua5.1`
sunos_libs = `if uname | grep SunOS >/dev/null 2>&1; then echo -lsocket -lnsl -lposix4; fi`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
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 conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o auth.o ipset.o pattern.o \
domain.o dnssec.o blockdata.o tables.o loop.o inotify.o \
poll.o rrfilter.o edns0.o arp.o crypto.o dump.o ubus.o \
metrics.o hash-questions.o domain-match.o nftset.o
dhcp-common.o outpacket.o radv.o slaac.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h ip6addr.h metrics.h
dns-protocol.h radv-protocol.h
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
build_cflags="$(version) $(dbus_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags)" \
build_libs="$(dbus_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs)" \
-f $(top)/Makefile dnsmasq
mostly_clean :
rm -f $(BUILDDIR)/*.mo $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.copts_* $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
clean : mostly_clean
rm -f $(BUILDDIR)/dnsmasq_baseline
rm -f core */core
rm -f *~ contrib/*/*~ */*~
clean :
rm -f *~ $(BUILDDIR)/*.mo contrib/*/*~ */*~ $(BUILDDIR)/*.pot
rm -f $(BUILDDIR)/.configured $(BUILDDIR)/*.o $(BUILDDIR)/dnsmasq.a $(BUILDDIR)/dnsmasq
rm -rf core */core
install : all install-common
install-common :
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
@@ -117,8 +93,8 @@ all-i18n : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
i18n=-DLOCALEDIR=\'\"$(LOCALEDIR)\"\' \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags) $(nft_cflags)" \
build_libs="$(dbus_libs) $(idn2_libs) $(idn_libs) $(ct_libs) $(lua_libs) $(sunos_libs) $(nettle_libs) $(gmp_libs) $(ubus_libs) $(nft_libs)" \
build_cflags="$(version) $(dbus_cflags) $(ct_cflags) $(lua_cflags) `$(PKG_CONFIG) --cflags libidn`" \
build_libs="$(dbus_libs) $(ct_libs) $(lua_libs) $(sunos_libs) `$(PKG_CONFIG) --libs libidn`" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
@@ -129,45 +105,28 @@ install-i18n : all-i18n install-common
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)
merge :
@cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile dnsmasq.pot
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
for f in `cd $(PO); echo *.po`; do \
echo -n msgmerge $(PO)/$$f && $(MSGMERGE) --no-wrap -U $(PO)/$$f $(BUILDDIR)/dnsmasq.pot; \
done
# Canonicalise .po file.
%.po :
@cd $(BUILDDIR) && $(MAKE) -f $(top)/Makefile dnsmasq.pot
mv $(PO)/$*.po $(PO)/$*.po.orig && $(MSGMERGE) --no-wrap $(PO)/$*.po.orig $(BUILDDIR)/dnsmasq.pot >$(PO)/$*.po;
$(BUILDDIR):
mkdir -p $(BUILDDIR)
# rules below are helpers for size tracking
baseline : mostly_clean all
@cd $(BUILDDIR) && \
mv dnsmasq dnsmasq_baseline
# rules below are targets in recusive makes with cwd=$(BUILDDIR)
bloatcheck : $(BUILDDIR)/dnsmasq_baseline mostly_clean all
@cd $(BUILDDIR) && \
$(top)/bld/bloat-o-meter dnsmasq_baseline dnsmasq; \
size dnsmasq_baseline dnsmasq
# rules below are targets in recursive makes with cwd=$(BUILDDIR)
$(copts_conf): $(hdrs)
@rm -f *.o .copts_*
.configured: $(hdrs)
@rm -f *.o
@touch $@
$(objs:.o=.c) $(hdrs):
ln -s $(top)/$(SRC)/$@ .
$(objs): $(copts_conf) $(hdrs)
.c.o:
$(CC) $(CFLAGS) $(COPTS) $(i18n) $(build_cflags) $(RPM_OPT_FLAGS) -c $<
dnsmasq : $(objs)
dnsmasq : .configured $(hdrs) $(objs)
$(CC) $(LDFLAGS) -o $@ $(objs) $(build_libs) $(LIBS)
dnsmasq.pot : $(objs:.o=.c) $(hdrs)
@@ -176,4 +135,5 @@ dnsmasq.pot : $(objs:.o=.c) $(hdrs)
%.mo : $(top)/$(PO)/%.po dnsmasq.pot
$(MSGMERGE) -o - $(top)/$(PO)/$*.po dnsmasq.pot | $(MSGFMT) -o $*.mo -
.PHONY : all clean mostly_clean install install-common all-i18n install-i18n merge baseline bloatcheck
.PHONY : all clean install install-common all-i18n install-i18n merge

View File

@@ -8,11 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c auth.c ipset.c domain.c \
dnssec.c dnssec-openssl.c blockdata.c tables.c \
loop.c inotify.c poll.c rrfilter.c edns0.c arp.c \
crypto.c dump.c ubus.c metrics.c hash-questions.c \
domain-match.c
radv.c slaac.c
LOCAL_MODULE := dnsmasq

View File

@@ -1,130 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2004 Matt Mackall <mpm@selenic.com>
#
# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
import sys, os#, re
def usage():
sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0])
sys.exit(-1)
f1, f2 = (None, None)
flag_timing, dashes = (False, False)
for f in sys.argv[1:]:
if f.startswith("-"):
if f == "--": # sym_args
dashes = True
break
if f == "-t": # timings
flag_timing = True
else:
if not os.path.exists(f):
sys.stderr.write("Error: file '%s' does not exist\n" % f)
usage()
if f1 is None:
f1 = f
elif f2 is None:
f2 = f
if flag_timing:
import time
if f1 is None or f2 is None:
usage()
sym_args = " ".join(sys.argv[3 + flag_timing + dashes:])
def getsizes(file):
sym, alias, lut = {}, {}, {}
for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines():
l = l.strip()
if not (len(l) and l[0].isdigit() and len(l.split()) == 8):
continue
num, value, size, typ, bind, vis, ndx, name = l.split()
if ndx == "UND": continue # skip undefined
if typ in ["SECTION", "FILES"]: continue # skip sections and files
if "." in name: name = "static." + name.split(".")[0]
value = int(value, 16)
size = int(size, 16) if size.startswith('0x') else int(size)
if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias
alias[(value, size)] = {"name" : name}
else:
sym[name] = {"addr" : value, "size": size}
lut[(value, size)] = 0
for addr, sz in iter(alias.keys()):
# If the non-GLOBAL sym has an implementation elsewhere then
# it's an alias, disregard it.
if not (addr, sz) in lut:
# If this non-GLOBAL sym does not have an implementation at
# another address, then treat it as a normal symbol.
sym[alias[(addr, sz)]["name"]] = {"addr" : addr, "size": sz}
for l in os.popen("readelf -W -S " + file).readlines():
x = l.split()
if len(x)<6: continue
# Should take these into account too!
#if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
if x[1] not in [".rodata"]: continue
sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)}
return sym
if flag_timing:
start_t1 = int(time.time() * 1e9)
old = getsizes(f1)
if flag_timing:
end_t1 = int(time.time() * 1e9)
start_t2 = int(time.time() * 1e9)
new = getsizes(f2)
if flag_timing:
end_t2 = int(time.time() * 1e9)
start_t3 = int(time.time() * 1e9)
grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
delta, common = [], {}
for name in iter(old.keys()):
if name in new:
common[name] = 1
for name in old:
if name not in common:
remove += 1
sz = old[name]["size"]
down += sz
delta.append((-sz, name))
for name in new:
if name not in common:
add += 1
sz = new[name]["size"]
up += sz
delta.append((sz, name))
for name in common:
d = new[name].get("size", 0) - old[name].get("size", 0)
if d>0: grow, up = grow+1, up+d
elif d<0: shrink, down = shrink+1, down-d
else:
continue
delta.append((d, name))
delta.sort()
delta.reverse()
if flag_timing:
end_t3 = int(time.time() * 1e9)
print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
for d, n in delta:
if d:
old_sz = old.get(n, {}).get("size", "-")
new_sz = new.get(n, {}).get("size", "-")
print("%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d))
print("-"*78)
total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
% (add, remove, grow, shrink, up, -down, up-down)
print(total % (" "*(80-len(total))))
if flag_timing:
print("\n%d/%d; %d Parse origin/new; processing nsecs" %
(end_t1-start_t1, end_t2-start_t2, end_t3-start_t3))
print("total nsecs: %d" % (end_t3-start_t1))

View File

@@ -9,29 +9,18 @@
# If we can find one which matches $v[0-9].* then we assume it's
# a version-number tag, else we just use the whole string.
# If there is more than one v[0-9].* tag, sort them and use the
# first. The insane arguments to the sort command are to ensure
# that, eg v2.64 comes before v2.63, but v2.63 comes before v2.63rc1
# and v2.63rc1 comes before v2.63test1
# first. This favours, eg v2.63 over 2.63rc6.
# Change directory to the toplevel source directory.
if test -z "$1" || ! test -d "$1" || ! cd "$1"; then
echo "$0: First argument $1 must be toplevel dir." >&2
exit 1
fi
if which git >/dev/null 2>&1 && \
([ -d .git ] || grep '^gitdir:' .git >/dev/null 2>&1) && \
git describe >/dev/null 2>&1; then
git describe | sed 's/^v//'
if which git >/dev/null 2>&1 && [ -d $1/.git ]; then
cd $1; git describe
elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | sort -k1.2,1.5Vr -k1.6,1.6 -k1.8,1.9Vr -k1.10,1.11Vr | head -n 1 | sed 's/^v//'
echo "${vers}" | sort | head -n 1 | sed 's/^v//'
else
cat $1/VERSION
fi

View File

@@ -1,45 +1,11 @@
#!/bin/sh
in=`cat`
search=$1
shift
search()
{
grep "^\#[[:space:]]*define[[:space:]]*$1" config.h >/dev/null 2>&1 || \
echo $in | grep $1 >/dev/null 2>&1
}
while [ "$#" -gt 0 ]; do
search=$1
pkg=$2
op=$3
lib=$4
shift 4
if search "$search"; then
# Nasty, nasty, in --copy, arg 2 (if non-empty) is another config to search for, used with NO_GMP
if [ $op = "--copy" ]; then
if [ -z "$pkg" ]; then
pkg="$lib"
elif search "$pkg"; then
pkg=""
else
pkg="$lib"
fi
elif search "${search}_STATIC"; then
pkg=`$pkg --static $op $lib`
else
pkg=`$pkg $op $lib`
fi
if search "${search}_STATIC"; then
if [ $op = "--libs" ] || [ $op = "--copy" ]; then
echo "-Wl,-Bstatic $pkg -Wl,-Bdynamic"
else
echo "$pkg"
fi
else
echo "$pkg"
fi
if grep "^\#[[:space:]]*define[[:space:]]*$search" config.h >/dev/null 2>&1 || \
grep $search >/dev/null 2>&1; then
exec $*
fi
done

View File

@@ -22,7 +22,7 @@ sudo chmod 644 /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
Optionally, edit your dnsmasq configuration file to your liking.
To start the launchd job, which starts dnsmasq, reboot or use the command:
To start the launchd job, which starts dnsmaq, reboot or use the command:
sudo launchctl load /Library/LaunchDaemons/uk.org.thekelleys.dnsmasq.plist
To stop the launchd job, which stops dnsmasq, use the command:

6
contrib/Suse/README Normal file
View File

@@ -0,0 +1,6 @@
This packaging is now unmaintained in the dnsmasq source: dnsmasq is
included in Suse proper, and up-to-date packages are now available
from
ftp://ftp.suse.com/pub/people/ug/

View File

@@ -0,0 +1,27 @@
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
It fixes the depancy from the dns daemon name 'named'
After appending the patch, the SuSEfirewall is again able to autodetect
the dnsmasq named service.
This is a very old bug in the SuSEfirewall script.
The SuSE people think the name of the dns server will allways 'named'
--- /sbin/SuSEfirewall2.orig 2004-01-23 13:30:09.000000000 +0100
+++ /sbin/SuSEfirewall2 2004-01-23 13:31:56.000000000 +0100
@@ -764,7 +764,7 @@
echo 'FW_ALLOW_INCOMING_HIGHPORTS_UDP should be set to yes, if you are running a DNS server!'
test "$FW_SERVICE_AUTODETECT" = yes -o "$FW_SERVICE_AUTODETECT" = dmz -o "$FW_SERVICE_AUTODETECT" = ext && {
- test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv named && {
+ test "$FW_SERVICE_DNS" = no -a '!' "$START_NAMED" = no && check_srv dnsmasq && {
echo -e 'Warning: detected activated named, enabling FW_SERVICE_DNS!
You still have to allow tcp/udp port 53 on internal, dmz and/or external.'
FW_SERVICE_DNS=$FW_SERVICE_AUTODETECT
@@ -878,7 +878,7 @@
test -e /etc/resolv.conf || echo "Warning: /etc/resolv.conf not found"
# Get ports/IP bindings of NAMED/SQUID
test "$FW_SERVICE_DNS" = yes -o "$FW_SERVICE_DNS" = dmz -o "$FW_SERVICE_DNS" = ext -o "$START_NAMED" = yes && DNS_PORT=`$LSOF -i -n -P | \
- $AWK -F: '/^named .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
+ $AWK -F: '/^dnsmasq .* UDP / {print $2}'| $GREP -vw 53 | $SORT -un`
test "$FW_SERVICE_SQUID" = yes -o "$FW_SERVICE_SQUID" = dmz -o "$FW_SERVICE_SQUID" = ext -o "$START_SQUID" = yes && SQUID_PORT=`$LSOF -i -n -P | \
$AWK -F: '/^squid .* UDP/ {print $2}'| $SORT -un`

View File

@@ -0,0 +1,23 @@
--- man/dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
+++ man/dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
@@ -69,7 +69,7 @@
.TP
.B \-g, --group=<groupname>
Specify the group which dnsmasq will run
-as. The defaults to "dip", if available, to facilitate access to
+as. The defaults to "dialout", if available, to facilitate access to
/etc/ppp/resolv.conf which is not normally world readable.
.TP
.B \-v, --version
--- src/config.h 2004-08-11 11:39:18.000000000 +0200
+++ src/config.h 2004-08-12 00:40:01.000000000 +0200
@@ -44,7 +44,7 @@
#endif
#define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody"
-#define CHGRP "dip"
+#define CHGRP "dialout"
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68

View File

@@ -0,0 +1,111 @@
###############################################################################
#
# General
#
###############################################################################
Name: dnsmasq
Version: 2.33
Release: 1
Copyright: GPL
Group: Productivity/Networking/DNS/Servers
Vendor: Simon Kelley
Packager: Simon Kelley
URL: http://www.thekelleys.org.uk/dnsmasq
Provides: dns_daemon
Conflicts: bind bind8 bind9
PreReq: %fillup_prereq %insserv_prereq
Autoreqprov: on
Source0: %{name}-%{version}.tar.bz2
BuildRoot: /var/tmp/%{name}-%{version}
Summary: A lightweight caching nameserver
%description
Dnsmasq is lightweight, easy to configure DNS forwarder and DHCP server. It
is designed to provide DNS and, optionally, DHCP, to a small network. It can
serve the names of local machines which are not in the global DNS. The DHCP
server integrates with the DNS server and allows machines with DHCP-allocated
addresses to appear in the DNS with names configured either in each host or
in a central configuration file. Dnsmasq supports static and dynamic DHCP
leases and BOOTP for network booting of diskless machines.
###############################################################################
#
# Build
#
###############################################################################
%prep
%setup -q
patch -p0 <rpm/%{name}-SuSE.patch
%build
%{?suse_update_config:%{suse_update_config -f}}
make all-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
###############################################################################
#
# Install
#
###############################################################################
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p ${RPM_BUILD_ROOT}/etc/init.d
make install-i18n DESTDIR=$RPM_BUILD_ROOT PREFIX=/usr
install -o root -g root -m 755 rpm/rc.dnsmasq-suse $RPM_BUILD_ROOT/etc/init.d/dnsmasq
install -o root -g root -m 644 dnsmasq.conf.example $RPM_BUILD_ROOT/etc/dnsmasq.conf
strip $RPM_BUILD_ROOT/usr/sbin/dnsmasq
ln -sf ../../etc/init.d/dnsmasq $RPM_BUILD_ROOT/usr/sbin/rcdnsmasq
###############################################################################
#
# Clean up
#
###############################################################################
%clean
rm -rf $RPM_BUILD_ROOT
###############################################################################
#
# Post-install scriptlet
#
###############################################################################
%post
%{fillup_and_insserv dnsmasq}
###############################################################################
#
# Post-uninstall scriptlet
#
# The %postun script executes after the package has been removed. It is the
# last chance for a package to clean up after itself.
#
###############################################################################
%postun
%{insserv_cleanup}
###############################################################################
#
# File list
#
###############################################################################
%files
%defattr(-,root,root)
%doc CHANGELOG COPYING FAQ doc.html setup.html UPGRADING_to_2.0 rpm/README.susefirewall
%doc contrib
%config /etc/init.d/dnsmasq
%config /etc/dnsmasq.conf
/usr/sbin/rcdnsmasq
/usr/sbin/dnsmasq
/usr/share/locale/*/LC_MESSAGES/*
%doc %{_mandir}/man8/dnsmasq.8.gz
%doc %{_mandir}/*/man8/dnsmasq.8.gz

View File

@@ -0,0 +1,79 @@
#! /bin/sh
#
# init.d/dnsmasq
#
### BEGIN INIT INFO
# Provides: dnsmasq
# Required-Start: $network $remote_fs $syslog
# Required-Stop:
# Default-Start: 3 5
# Default-Stop:
# Description: Starts internet name service masq caching server (DNS)
### END INIT INFO
NAMED_BIN=/usr/sbin/dnsmasq
NAMED_PID=/var/run/dnsmasq.pid
NAMED_CONF=/etc/dnsmasq.conf
if [ ! -x $NAMED_BIN ] ; then
echo -n "dnsmasq not installed ! "
exit 5
fi
. /etc/rc.status
rc_reset
case "$1" in
start)
echo -n "Starting name service masq caching server "
checkproc -p $NAMED_PID $NAMED_BIN
if [ $? -eq 0 ] ; then
echo -n "- Warning: dnsmasq already running ! "
else
[ -e $NAMED_PID ] && echo -n "- Warning: $NAMED_PID exists ! "
fi
startproc -p $NAMED_PID $NAMED_BIN -u nobody
rc_status -v
;;
stop)
echo -n "Shutting name service masq caching server "
checkproc -p $NAMED_PID $NAMED_BIN
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
killproc -p $NAMED_PID -TERM $NAMED_BIN
rc_status -v
;;
try-restart)
$0 stop && $0 start
rc_status
;;
restart)
$0 stop
$0 start
rc_status
;;
force-reload)
$0 reload
rc_status
;;
reload)
echo -n "Reloading name service masq caching server "
checkproc -p $NAMED_PID $NAMED_BIN
[ $? -ne 0 ] && echo -n "- Warning: dnsmasq not running ! "
killproc -p $NAMED_PID -HUP $NAMED_BIN
rc_status -v
;;
status)
echo -n "Checking for name service masq caching server "
checkproc -p $NAMED_PID $NAMED_BIN
rc_status -v
;;
probe)
test $NAMED_CONF -nt $NAMED_PID && echo reload
;;
*)
echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}"
exit 1
;;
esac
rc_exit

View File

@@ -13,10 +13,10 @@ 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
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,
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
@@ -40,7 +40,7 @@ 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
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.

View File

@@ -55,7 +55,7 @@ Index: src/dnsmasq.c
}
@@ -434,7 +433,7 @@
/* lose the setuid and setgid capabilities */
/* lose the setuid and setgid capbilities */
if (capset(hdr, data) == -1)
{
- send_event(err_pipe[1], EVENT_CAP_ERR, errno);

View File

@@ -1,6 +0,0 @@
CFLAGS?= -O2 -Wall -W
all: dhcp_release dhcp_release6 dhcp_lease_time
clean:
rm -f *~ *.o core dhcp_release dhcp_release6 dhcp_lease_time

View File

@@ -1,38 +0,0 @@
.TH DHCP_RELEASE 1
.SH NAME
dhcp_release6 \- Release a DHCPv6 lease on a the local dnsmasq DHCP server.
.SH SYNOPSIS
.B dhcp_release6 --iface <interface> --client-id <client-id> --server-id
server-id --iaid <iaid> --ip <IP> [--dry-run] [--help]
.SH "DESCRIPTION"
A utility which forces the DHCP server running on this machine to release a
DHCPv6 lease.
.SS OPTIONS
.IP "-a, --ip"
IPv6 address to release.
.IP "-c, --client-id"
Colon-separated hex string representing DHCPv6 client id. Normally
it can be found in leases file both on client and server.
.IP "-d, --dry-run"
Print hexadecimal representation of generated DHCPv6 release packet to standard
output and exit.
.IP "-h, --help"
print usage information to standard output and exit.
.IP "-i, --iaid"
Decimal representation of DHCPv6 IAID. Normally it can be found in leases file
both on client and server.
.IP "-n, --iface"
Network interface to send a DHCPv6 release packet from.
.IP "-s, --server-id"
Colon-separated hex string representing DHCPv6 server id. Normally
it can be found in leases file both on client and server.
.SH NOTES
MUST be run as root - will fail otherwise.
.SH LIMITATIONS
Only usable on IPv6 DHCP leases.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR
This manual page was written by Simon Kelley <simon@thekelleys.org.uk>.

View File

@@ -1,508 +0,0 @@
/*
dhcp_release6 --iface <interface> --client-id <client-id> --server-id
server-id --iaid <iaid> --ip <IP> [--dry-run] [--help]
MUST be run as root - will fail otherwise
*/
/* Send a DHCPRELEASE message to IPv6 multicast address 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 client-id argument is colon-separated hex string and mandatory. Normally
it can be found in leases file both on client and server
The server-id argument is colon-separated hex string and mandatory. Normally
it can be found in leases file both on client and server.
The iaid argument is numeric string and mandatory. Normally
it can be found in leases file both on client and server.
IP is an IPv6 address to release
If --dry-run is specified, dhcp_release6 just prints hexadecimal representation of
packet to send to stdout and exits.
If --help is specified, dhcp_release6 print usage information to stdout and exits
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <errno.h>
#include <unistd.h>
#define NOT_REPLY_CODE 115
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
enum DHCP6_TYPES
{
SOLICIT = 1,
ADVERTISE = 2,
REQUEST = 3,
CONFIRM = 4,
RENEW = 5,
REBIND = 6,
REPLY = 7,
RELEASE = 8,
DECLINE = 9,
RECONFIGURE = 10,
INFORMATION_REQUEST = 11,
RELAY_FORW = 12,
RELAY_REPL = 13
};
enum DHCP6_OPTIONS
{
CLIENTID = 1,
SERVERID = 2,
IA_NA = 3,
IA_TA = 4,
IAADDR = 5,
ORO = 6,
PREFERENCE = 7,
ELAPSED_TIME = 8,
RELAY_MSG = 9,
AUTH = 11,
UNICAST = 12,
STATUS_CODE = 13,
RAPID_COMMIT = 14,
USER_CLASS = 15,
VENDOR_CLASS = 16,
VENDOR_OPTS = 17,
INTERFACE_ID = 18,
RECONF_MSG = 19,
RECONF_ACCEPT = 20,
};
enum DHCP6_STATUSES
{
SUCCESS = 0,
UNSPEC_FAIL = 1,
NOADDR_AVAIL=2,
NO_BINDING = 3,
NOT_ON_LINK = 4,
USE_MULTICAST =5
};
static struct option longopts[] = {
{"ip", required_argument, 0, 'a' },
{"server-id", required_argument, 0, 's' },
{"client-id", required_argument, 0, 'c' },
{"iface", required_argument, 0, 'n' },
{"iaid", required_argument, 0, 'i' },
{"dry-run", no_argument, 0, 'd' },
{"help", no_argument, 0, 'h' },
{0, 0, 0, 0 }
};
const short DHCP6_CLIENT_PORT = 546;
const short DHCP6_SERVER_PORT = 547;
const char* DHCP6_MULTICAST_ADDRESS = "ff02::1:2";
struct dhcp6_option {
uint16_t type;
uint16_t len;
char value[1024];
};
struct dhcp6_iaaddr_option {
uint16_t type;
uint16_t len;
struct in6_addr ip;
uint32_t preferred_lifetime;
uint32_t valid_lifetime;
};
struct dhcp6_iana_option {
uint16_t type;
uint16_t len;
uint32_t iaid;
uint32_t t1;
uint32_t t2;
char options[1024];
};
struct dhcp6_packet {
size_t len;
char buf[2048];
};
size_t pack_duid(const char* str, char* dst)
{
char* tmp = strdup(str);
char* tmp_to_free = tmp;
char *ptr;
uint8_t write_pos = 0;
while ((ptr = strtok (tmp, ":")))
{
dst[write_pos] = (uint8_t) strtol(ptr, NULL, 16);
write_pos += 1;
tmp = NULL;
}
free(tmp_to_free);
return write_pos;
}
struct dhcp6_option create_client_id_option(const char* duid)
{
struct dhcp6_option option;
option.type = htons(CLIENTID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
}
struct dhcp6_option create_server_id_option(const char* duid)
{
struct dhcp6_option option;
option.type = htons(SERVERID);
bzero(option.value, sizeof(option.value));
option.len = htons(pack_duid(duid, option.value));
return option;
}
struct dhcp6_iaaddr_option create_iaadr_option(const char* ip)
{
struct dhcp6_iaaddr_option result;
result.type =htons(IAADDR);
/* no suboptions needed here, so length is 24 */
result.len = htons(24);
result.preferred_lifetime = 0;
result.valid_lifetime = 0;
int s = inet_pton(AF_INET6, ip, &(result.ip));
if (s <= 0) {
if (s == 0)
fprintf(stderr, "Not in presentation format");
else
perror("inet_pton");
exit(EXIT_FAILURE);
}
return result;
}
struct dhcp6_iana_option create_iana_option(const char * iaid, struct dhcp6_iaaddr_option ia_addr)
{
struct dhcp6_iana_option result;
result.type = htons(IA_NA);
result.iaid = htonl(atoi(iaid));
result.t1 = 0;
result.t2 = 0;
result.len = htons(12 + ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
memcpy(result.options, &ia_addr, ntohs(ia_addr.len) + 2 * sizeof(uint16_t));
return result;
}
struct dhcp6_packet create_release_packet(const char* iaid, const char* ip, const char* client_id, const char* server_id)
{
struct dhcp6_packet result;
bzero(result.buf, sizeof(result.buf));
/* message_type */
result.buf[0] = RELEASE;
/* tx_id */
bzero(result.buf+1, 3);
struct dhcp6_option client_option = create_client_id_option(client_id);
struct dhcp6_option server_option = create_server_id_option(server_id);
struct dhcp6_iaaddr_option iaaddr_option = create_iaadr_option(ip);
struct dhcp6_iana_option iana_option = create_iana_option(iaid, iaaddr_option);
int offset = 4;
memcpy(result.buf + offset, &client_option, ntohs(client_option.len) + 2*sizeof(uint16_t));
offset += (ntohs(client_option.len)+ 2 *sizeof(uint16_t) );
memcpy(result.buf + offset, &server_option, ntohs(server_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(server_option.len)+ 2* sizeof(uint16_t));
memcpy(result.buf + offset, &iana_option, ntohs(iana_option.len) + 2*sizeof(uint16_t) );
offset += (ntohs(iana_option.len)+ 2* sizeof(uint16_t));
result.len = offset;
return result;
}
uint16_t parse_iana_suboption(char* buf, size_t len)
{
size_t current_pos = 0;
char option_value[1024];
while (current_pos < len)
{
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE)
{
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos + sizeof(uint16_t) , option_len - sizeof(uint16_t));
option_value[option_len-sizeof(uint16_t)] ='\0';
fprintf(stderr, "Error: %s\n", option_value);
}
return status;
}
}
return -2;
}
int16_t parse_packet(char* buf, size_t len)
{
int16_t ret = -1;
uint8_t type = buf[0];
/*skipping tx id. you need it, uncomment following line
uint16_t tx_id = ntohs((buf[1] <<16) + (buf[2] <<8) + buf[3]);
*/
size_t current_pos = 4;
if (type != REPLY )
return NOT_REPLY_CODE;
char option_value[1024];
while (current_pos < len)
{
uint16_t option_type, option_len;
memcpy(&option_type,buf + current_pos, sizeof(uint16_t));
memcpy(&option_len,buf + current_pos + sizeof(uint16_t), sizeof(uint16_t));
option_type = ntohs(option_type);
option_len = ntohs(option_len);
current_pos += 2 * sizeof(uint16_t);
if (option_type == STATUS_CODE)
{
uint16_t status;
memcpy(&status, buf + current_pos, sizeof(uint16_t));
status = ntohs(status);
if (status != SUCCESS)
{
memcpy(option_value, buf + current_pos +sizeof(uint16_t) , option_len -sizeof(uint16_t));
fprintf(stderr, "Error: %d %s\n", status, option_value);
return status;
}
/* Got success status, return that if there's no specific error in an IA_NA. */
ret = SUCCESS;
}
if (option_type == IA_NA )
{
uint16_t result = parse_iana_suboption(buf + current_pos +24, option_len -24);
if (result)
return result;
}
current_pos += option_len;
}
return ret;
}
void usage(const char* arg, FILE* stream)
{
const char* usage_string ="--ip IPv6 --iface IFACE --server-id SERVER_ID --client-id CLIENT_ID --iaid IAID [--dry-run] | --help";
fprintf (stream, "Usage: %s %s\n", arg, usage_string);
}
static void fail_fatal(const char *errstr, int exitcode)
{
perror(errstr);
exit(exitcode);
}
int send_release_packet(const char* iface, struct dhcp6_packet* packet)
{
struct sockaddr_in6 server_addr, client_addr;
char response[1400];
int sock = socket(PF_INET6, SOCK_DGRAM, 0);
int i = 0;
if (sock < 0)
{
perror("creating socket");
return -1;
}
if (setsockopt(sock, SOL_SOCKET, 25, iface, strlen(iface)) == -1)
{
perror("SO_BINDTODEVICE");
close(sock);
return -1;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin6_family = AF_INET6;
client_addr.sin6_family = AF_INET6;
client_addr.sin6_port = htons(DHCP6_CLIENT_PORT);
client_addr.sin6_flowinfo = 0;
client_addr.sin6_scope_id =0;
if (inet_pton(AF_INET6, "::", &client_addr.sin6_addr) <= 0)
fail_fatal("inet_pton", 5);
if (bind(sock, (struct sockaddr*)&client_addr, sizeof(struct sockaddr_in6)) != 0)
perror("bind"); /* continue on bind error */
if (inet_pton(AF_INET6, DHCP6_MULTICAST_ADDRESS, &server_addr.sin6_addr) <= 0)
fail_fatal("inet_pton", 5);
server_addr.sin6_port = htons(DHCP6_SERVER_PORT);
ssize_t recv_size = 0;
int result;
for (i = 0; i < 5; i++)
{
if (sendto(sock, packet->buf, packet->len, 0, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
fail_fatal("sendto failed", 4);
recv_size = recvfrom(sock, response, sizeof(response), MSG_DONTWAIT, NULL, 0);
if (recv_size == -1)
{
if (errno == EAGAIN)
{
sleep(1);
continue;
}
else
{
perror("recvfrom");
result = UNSPEC_FAIL;
}
}
else
{
result = parse_packet(response, recv_size);
if (result == NOT_REPLY_CODE)
{
sleep(1);
continue;
}
}
close(sock);
return result;
}
close(sock);
fprintf(stderr, "Response timed out\n");
return -1;
}
int main(int argc, char * const argv[])
{
const char* UNINITIALIZED = "";
const char* iface = UNINITIALIZED;
const char* ip = UNINITIALIZED;
const char* client_id = UNINITIALIZED;
const char* server_id = UNINITIALIZED;
const char* iaid = UNINITIALIZED;
int dry_run = 0;
while (1)
{
int option_index = 0;
int c = getopt_long(argc, argv, "a:s:c:n:i:hd", longopts, &option_index);
if (c == -1)
break;
switch(c)
{
case 0:
if (longopts[option_index].flag !=0)
break;
printf ("option %s", longopts[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'i':
iaid = optarg;
break;
case 'n':
iface = optarg;
break;
case 'a':
ip = optarg;
break;
case 'c':
client_id = optarg;
break;
case 'd':
dry_run = 1;
break;
case 's':
server_id = optarg;
break;
case 'h':
usage(argv[0], stdout);
return 0;
case '?':
usage(argv[0], stderr);
return -1;
default:
abort();
}
}
if (iaid == UNINITIALIZED)
{
fprintf(stderr, "Missing required iaid parameter\n");
usage(argv[0], stderr);
return -1;
}
if (server_id == UNINITIALIZED)
{
fprintf(stderr, "Missing required server-id parameter\n");
usage(argv[0], stderr);
return -1;
}
if (client_id == UNINITIALIZED)
{
fprintf(stderr, "Missing required client-id parameter\n");
usage(argv[0], stderr);
return -1;
}
if (ip == UNINITIALIZED)
{
fprintf(stderr, "Missing required ip parameter\n");
usage(argv[0], stderr);
return -1;
}
if (iface == UNINITIALIZED)
{
fprintf(stderr, "Missing required iface parameter\n");
usage(argv[0], stderr);
return -1;
}
struct dhcp6_packet packet = create_release_packet(iaid, ip, client_id, server_id);
if (dry_run)
{
uint16_t i;
for(i=0; i<packet.len; i++)
printf("%hhx", packet.buf[i]);
printf("\n");
return 0;
}
return send_release_packet(iface, &packet);
}

View File

@@ -1,36 +0,0 @@
#!/bin/bash
STATUS_FILE="/tmp/dnsmasq-ip-mac.status"
# Script for dnsmasq lease-change hook.
# Maintains the above file with an IP address/MAC address pairs,
# one lease per line. Works with IPv4 and IPv6 leases, file is
# atomically updated, so no races for users of the data.
action="$1"
mac="$2" # IPv4
ip="$3"
# ensure it always exists.
if [ ! -f "$STATUS_FILE" ]; then
touch "$STATUS_FILE"
fi
if [ -n "$DNSMASQ_IAID" ]; then
mac="$DNSMASQ_MAC" # IPv6
fi
# worry about an add or old action when the MAC address is not known:
# leave any old one in place in that case.
if [ "$action" = "add" -o "$action" = "old" -o "$action" = "del" ]; then
if [ -n "$mac" -o "$action" = "del" ]; then
sed "/^${ip//./\.} / d" "$STATUS_FILE" > "$STATUS_FILE".new
if [ "$action" = "add" -o "$action" = "old" ]; then
echo "$ip $mac" >> "$STATUS_FILE".new
fi
mv "$STATUS_FILE".new "$STATUS_FILE" # atomic update.
fi
fi

View File

@@ -3,7 +3,7 @@
# first column of this file, then a DNAT port-forward will be set up
# to the address which has just been allocated by DHCP . The second field
# is port number(s). If there is only one, then the port-forward goes to
# the same port on the DHCP-client, if there are two separated with a
# the same port on the DHCP-client, if there are two seperated with a
# colon, then the second number is the port to which the connection
# is forwarded on the DHCP-client. By default, forwarding is set up
# for TCP, but it can done for UDP instead by prefixing the port to "u".

View File

@@ -1,18 +0,0 @@
The script reads stdin and replaces all IP addresses with names before
outputting it again. IPs from private networks are reverse looked up
via dns. Other IP addresses are searched for in the dnsmasq query log.
This gives names (CNAMEs if I understand DNS correctly) that are closer
to the name the client originally asked for then the names obtained by
reverse lookup. Just run
netstat -n -4 | ./reverse_replace.sh
to see what it does. It needs
log-queries
log-facility=/var/log/dnsmasq.log
in the dnsmasq configuration.
The script runs on debian (with dash installed) and on busybox.

View File

@@ -1,125 +0,0 @@
#!/bin/dash
# $Id: reverse_replace.sh 18 2015-03-01 16:12:35Z jo $
#
# Usage e.g.: netstat -n -4 | reverse_replace.sh
# Parses stdin for IP4 addresses and replaces them
# with names retrieved by parsing the dnsmasq log.
# This currently only gives CNAMEs. But these
# usually tell you more than the ones from reverse
# lookups.
#
# This has been tested on debian and asuswrt. Please
# report successful tests on other platforms.
#
# Author: Joachim Zobel <jz-2014@heute-morgen.de>
# License: Consider this MIT style licensed. You can
# do as you ike, but you must not remove my name.
#
LOG=/var/log/dnsmasq.log
MAX_LINES=15000
# sed regex do match IPs
IP_regex='[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
# private IP ranges
IP_private='\(^127\.\)\|\(^192\.168\.\)\|\(^10\.\)\|\(^172\.1[6-9]\.\)\|\(^172\.2[0-9]\.\)\|\(^172\.3[0-1]\.\)'
#######################################################################
# Find Commands
HOST=nslookup
if type host > /dev/null 2>&1; then
# echo "No need for nslookup, host is there"
HOST=host
fi
#######################################################################
# Functions
# Use shell variables for an (IP) lookup table
create_lookup_table()
{
# Parse log into lookup table
local CMDS="$( tail -"$MAX_LINES" "$LOG" | \
grep " is $IP_regex" | \
sed "s#.* \([^ ]*\) is \($IP_regex\).*#set_val \2 \1;#" )"
local IFS='
'
for CMD in $CMDS
do
eval $CMD
done
}
set_val()
{
local _IP=$(echo $1 | tr . _)
local KEY="__IP__$_IP"
eval "$KEY"=$2
}
get_val()
{
local _IP=$(echo $1 | tr . _)
local KEY="__IP__$_IP"
eval echo -n '${'"$KEY"'}'
}
dns_lookup()
{
local IP=$1
local RTN="$($HOST $IP | \
sed 's#\s\+#\n#g' | \
grep -v '^$' | \
tail -1 | tr -d '\n' | \
sed 's#\.$##')"
if echo $RTN | grep -q NXDOMAIN; then
echo -n $IP
else
echo -n "$RTN"
fi
}
reverse_dns()
{
local IP=$1
# Skip if it is not an IP
if ! echo $IP | grep -q "^$IP_regex$"; then
echo -n $IP
return
fi
# Do a dns lookup, if it is a local IP
if echo $IP | grep -q $IP_private; then
dns_lookup $IP
return
fi
local NAME="$(get_val $IP)"
if [ -z "$NAME" ]; then
echo -n $IP
else
echo -n $NAME
fi
}
#######################################################################
# Main
create_lookup_table
while read LINE; do
for IP in $(echo "$LINE" | \
sed "s#\b\($IP_regex\)\b#\n\1\n#g" | \
grep $IP_regex)
do
NAME=`reverse_dns $IP `
# echo "$NAME $IP"
LINE=`echo "$LINE" | sed "s#$IP#$NAME#" `
done
echo $LINE
done

View File

@@ -1,8 +1,5 @@
[Unit]
Description=dnsmasq - A lightweight DHCP and caching DNS server
After=network.target
Before=network-online.target nss-lookup.target
Wants=nss-lookup.target
Description=A lightweight DHCP and caching DNS server
[Service]
Type=dbus

View File

@@ -2,7 +2,7 @@ A remake of patch Bob Carroll had posted to dnsmasq,
now compatible with version 2.47. Hopefully he doesn't
mind (sending a copy of this mail to him too).
Maybe the patch in question is not acceptable
Maybe the patch in question is not acceptible
as it doesn't add new switch, rather it binds itself to "strict-order".
What it does is: if you have strict-order in the

View File

@@ -1,10 +0,0 @@
Hi,
I updated the try-all-ns patch to work with the latest version of git. Ended up implementing it on top of master, 2.78test2-7-g63437ff. As that specific if-clause has been changed in the last few commits, it's not compatible for 2.77, sadly.
Find the patch attached.
Regards,
Rasmus Ahlberg
Software Developer, R&D
Electrolux Small Appliances

View File

@@ -1,29 +0,0 @@
From: Jesse Glick <jglick@cloudbees.com>
To: dnsmasq-discuss@lists.thekelleys.org.uk
Subject: Re: [Dnsmasq-discuss] Ability to delegate to one server but fall
back to another after NXDOMAIN?
On Wed, Jan 15, 2014 at 12:30 PM, Simon Kelley <simon@thekelleys.org.uk> wrote:
> > There's a (very old) patch in contrib/try-all-ns that would make a starting point
This does not apply against trunk, so I tried to rework it. The
following appears to do what I expect:
diff --git a/src/forward.c b/src/forward.c
index 8167229..76070b5 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -610,7 +610,11 @@ void reply_query(int fd, int family, time_t now)
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
!option_bool(OPT_ORDER) &&
- forward->forwardall == 0)
+ forward->forwardall == 0 ||
+ /* try each in turn */
+ RCODE(header) == NXDOMAIN &&
+ option_bool(OPT_ORDER) &&
+ server->next != NULL)
/* for broken servers, attempt to send to another one. */
{
unsigned char *pheader;

View File

@@ -1,20 +0,0 @@
diff --git a/src/forward.c b/src/forward.c
index e3fa94b..ecf3b98 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -789,9 +789,12 @@ void reply_query(int fd, int family, time_t now)
/* Note: if we send extra options in the EDNS0 header, we can't recreate
the query from the reply. */
- if (RCODE(header) == REFUSED &&
- forward->forwardall == 0 &&
- !(forward->flags & FREC_HAS_EXTRADATA))
+ if ((RCODE(header) == REFUSED &&
+ forward->forwardall == 0 &&
+ !(forward->flags & FREC_HAS_EXTRADATA)) ||
+ /* If strict-order is set, try next server on NXDOMAIN reply */
+ (RCODE(header) == NXDOMAIN && option_bool(OPT_ORDER) &&
+ server->next != NULL))
/* for broken servers, attempt to send to another one. */
{
unsigned char *pheader;

View File

@@ -1,5 +1,5 @@
This is the README for the Dnsmasq webmin module.
This is the README for the DNSmasq webmin module.
Problems:
@@ -48,7 +48,7 @@ wade through the config file and man pages again.
If you modify it, or add a language file, and you have a spare moment,
please e-mail me - I won't be upset at all if you fix my poor coding!
(rather the opposite - I'd be pleased someone found it useful)
(rather the opposite - I'd be pleased someone found it usefull)
Cheers,
Neil Fisher <neil@magnecor.com.au>

6
contrib/wrt/Makefile Normal file
View File

@@ -0,0 +1,6 @@
CFLAGS?= -O2 -Wall -W
all: dhcp_release dhcp_lease_time
clean:
rm -f *~ *.o core dhcp_release dhcp_lease_time

View File

@@ -4,7 +4,7 @@ reboot, then it will eventually be restored as hosts renew their
leases. Until a host renews (which may take hours/days) it will
not exist in the DNS if dnsmasq's DDNS function is in use.
*WRT systems remount all non-volatile filesystems read-only after boot,
*WRT systems remount all non-volatile fileystems read-only after boot,
so the normal leasefile will not work. They do, however have NV
storage, accessed with the nvram command:
@@ -62,7 +62,7 @@ about 100 bytes, so restricting the number of leases to 50 will limit
use to half that. (The default limit in the distributed source is 150)
Any UI script which reads the dnsmasq leasefile will have to be
amended, probably by changing it to read the output of
ammended, probably by changing it to read the output of
`lease_update init` instead.

View File

@@ -12,11 +12,9 @@ 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.67 or later and may not work with other DHCP servers.
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 LIMITATIONS
Only works with IPv4 addresses and DHCP leases.
The address argument is a dotted-quad IP addresses and mandatory.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR

View File

@@ -20,7 +20,7 @@
nothing is sent to stdout a message is sent to stderr and a
non-zero error code is returned.
This version requires dnsmasq 2.67 or later.
Requires dnsmasq 2.40 or later.
*/
#include <sys/types.h>
@@ -46,7 +46,6 @@
#define OPTION_LEASE_TIME 51
#define OPTION_OVERLOAD 52
#define OPTION_MESSAGE_TYPE 53
#define OPTION_REQUESTED_OPTIONS 55
#define OPTION_END 255
#define DHCPINFORM 8
#define DHCP_SERVER_PORT 67
@@ -83,7 +82,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
if (p >= end - 2)
return NULL; /* malformed packet */
opt_len = option_len(p);
if (end - p < (2 + opt_len))
if (p >= end - (2 + opt_len))
return NULL; /* malformed packet */
if (*p == opt && opt_len >= minsize)
return p;
@@ -153,11 +152,7 @@ int main(int argc, char **argv)
exit(1);
}
if (inet_pton(AF_INET, argv[1], &lease) < 1)
{
fprintf(stderr, "invalid address: %s\n", argv[1]);
exit(1);
}
lease.s_addr = inet_addr(argv[1]);
memset(&packet, 0, sizeof(packet));
@@ -172,16 +167,10 @@ int main(int argc, char **argv)
*(p++) = 1;
*(p++) = DHCPINFORM;
/* Explicitly request the lease time, it won't be sent otherwise:
this is a dnsmasq extension, not standard. */
*(p++) = OPTION_REQUESTED_OPTIONS;
*(p++) = 1;
*(p++) = OPTION_LEASE_TIME;
*(p++) = OPTION_END;
dest.sin_family = AF_INET;
(void)inet_pton(AF_INET, "127.0.0.1", &dest.sin_addr);
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = ntohs(DHCP_SERVER_PORT);
if (sendto(fd, &packet, sizeof(packet), 0,
@@ -210,13 +199,13 @@ int main(int argc, char **argv)
{
unsigned int x;
if ((x = t/86400))
printf("%ud", x);
printf("%dd", x);
if ((x = (t/3600)%24))
printf("%uh", x);
printf("%dh", x);
if ((x = (t/60)%60))
printf("%um", x);
printf("%dm", x);
if ((x = t%60))
printf("%us", x);
printf("%ds", x);
}
return 0;
}

View File

@@ -27,8 +27,6 @@ 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 LIMITATIONS
Only usable on IPv4 DHCP leases.
.SH SEE ALSO
.BR dnsmasq (8)
.SH AUTHOR

View File

@@ -117,7 +117,7 @@ static ssize_t netlink_recv(int fd)
msg.msg_flags = 0;
while ((rc = recvmsg(fd, &msg, MSG_PEEK)) == -1 && errno == EINTR);
/* 2.2.x doesn't support MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
/* 2.2.x doesn't suport MSG_PEEK at all, returning EOPNOTSUPP, so we just grab a
big buffer and pray in that case. */
if (rc == -1 && errno == EOPNOTSUPP)
{
@@ -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, unsigned int index, int ifrfd, struct ifreq *ifr)
static struct in_addr find_interface(struct in_addr client, int fd, unsigned int index)
{
struct sockaddr_nl addr;
struct nlmsghdr *h;
@@ -218,17 +218,7 @@ static struct in_addr find_interface(struct in_addr client, int fd, unsigned int
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (h->nlmsg_type == NLMSG_DONE)
{
/* No match found, return first address as src/dhcp.c code does */
ifr->ifr_addr.sa_family = AF_INET;
if (ioctl(ifrfd, SIOCGIFADDR, ifr) != -1)
return ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
else
{
fprintf(stderr, "error: local IPv4 address not found\n");
exit(1);
}
}
exit(0);
else if (h->nlmsg_type == RTM_NEWADDR)
{
struct ifaddrmsg *ifa = NLMSG_DATA(h);
@@ -265,6 +255,10 @@ int main(int argc, char **argv)
struct ifreq ifr;
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
int nl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
struct iovec iov;
iov.iov_len = 200;
iov.iov_base = malloc(iov.iov_len);
if (argc < 4 || argc > 5)
{
@@ -280,22 +274,16 @@ int main(int argc, char **argv)
/* This voodoo fakes up a packet coming from the correct interface, which really matters for
a DHCP server */
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
strcpy(ifr.ifr_name, argv[1]);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
{
perror("cannot setup interface");
exit(1);
}
if (inet_pton(AF_INET, argv[2], &lease.s_addr) < 1)
{
perror("invalid ip address");
exit(1);
}
server = find_interface(lease, nl, if_nametoindex(argv[1]), fd, &ifr);
lease.s_addr = inet_addr(argv[2]);
server = find_interface(lease, nl, if_nametoindex(argv[1]));
memset(&packet, 0, sizeof(packet));

View File

@@ -40,18 +40,6 @@ ClearCache
Returns nothing. Clears the domain name cache and re-reads
/etc/hosts. The same as sending dnsmasq a HUP signal.
SetFilterWin2KOption
--------------------
Takes boolean, sets or resets the --filterwin2k option.
SetBogusPrivOption
------------------
Takes boolean, sets or resets the --bogus-priv option.
SetLocaliseQueriesOption
------------------------
Takes boolean, sets or resets the --localise-queries option.
SetServers
----------
Returns nothing. Takes a set of arguments representing the new
@@ -164,93 +152,6 @@ for SetServersEx is represented as
"/eng.mycorp.com/lab.mycorp.com/1003:1234:abcd::1%eth0"
]
GetLoopServers
--------------
(Only available if dnsmasq compiled with HAVE_LOOP)
Return an array of strings, each string is the IP address of an upstream
server which has been found to loop queries back to this dnsmasq instance, and
it therefore not being used.
AddDhcpLease
------------
Returns nothing. Adds or updates a DHCP or DHCPv6 lease to the internal lease
database, as if a client requested and obtained a lease.
If a lease for the IPv4 or IPv6 address already exist, it is overwritten.
Note that this function will trigger the DhcpLeaseAdded or DhcpLeaseUpdated
D-Bus signal and will run the configured DHCP lease script accordingly.
This function takes many arguments which are the lease parameters:
- A string with the textual representation of the IPv4 or IPv6 address of the
client.
Examples:
"192.168.1.115"
"1003:1234:abcd::1%eth0"
"2001:db8:abcd::1"
- A string representing the hardware address of the client, using the same
format as the one used in the lease database.
Examples:
"00:23:45:67:89:ab"
"06-00:20:e0:3b:13:af" (token ring)
- The hostname of the client, as an array of bytes (so there is no problem
with non-ASCII character encoding). May be empty.
Example (for "hostname.or.fqdn"):
[104, 111, 115, 116, 110, 97, 109, 101, 46, 111, 114, 46, 102, 113, 100, 110]
- The client identifier (IPv4) or DUID (IPv6) as an array of bytes. May be
empty.
Examples:
DHCPv6 DUID:
[0, 3, 0, 1, 0, 35, 69, 103, 137, 171]
DHCPv4 client identifier:
[255, 12, 34, 56, 78, 0, 1, 0, 1, 29, 9, 99, 190, 35, 69, 103, 137, 171]
- The duration of the lease, in seconds. If the lease is updated, then
the duration replaces the previous duration.
Example:
7200
- The IAID (Identity association identifier) of the DHCPv6 lease, as a network
byte-order unsigned integer. For DHCPv4 leases, this must be set to 0.
Example (for IPv6):
203569230
- A boolean which, if true, indicates that the DHCPv6 lease is for a temporary
address (IA_TA). If false, the DHCPv6 lease is for a non-temporary address
(IA_NA). For DHCPv4 leases, this must be set to false.
RemoveDhcpLease
---------------
Returns nothing. Removes a DHCP or DHCPv6 lease to the internal lease
database, as if a client sent a release message to abandon a lease.
This function takes only one parameter: the text representation of the
IPv4 or IPv6 address of the lease to remove.
Note that this function will trigger the DhcpLeaseRemoved signal and the
configured DHCP lease script will be run with the "del" action.
GetMetrics
----------
Returns an array with various metrics for DNS and DHCP.
2. SIGNALS

389
debian/changelog vendored
View File

@@ -1,372 +1,3 @@
dnsmasq (2.87-1) unstable; urgency=low
* New upstream. (closes: #1001209, #1003156)
* Include new NFTset support in the build.
* Fix crash on netboot with DNS server disabled. (closes: #996332)
* Fix rare lockup in DNSSEC. (closes: #1001576)
* Close old bug. (closes: #902963)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 08 Sep 2021 23:11:25 +0000
dnsmasq (2.86-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Fix --address=/#/...... which was lost in 2.86. (closes: #995655)
-- Michael Biebl <biebl@debian.org> Wed, 10 Nov 2021 22:05:45 +0100
dnsmasq (2.86-1) unstable; urgency=low
* Fix debian/changelog format error. (closes: #986626)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 08 Apr 2021 22:39:00 +0100
dnsmasq (2.85-1) unstable; urgency=low
* New upstream.
* Includes fix to CVE-2021-3448.
* Fix manpage typos. (closes: #986150)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 03 Apr 2021 22:17:23 +0100
dnsmasq (2.84-1.2) unstable; urgency=medium
* Non-maintainer upload.
* Bump old-version in dpkg-maintscript-helper dir_to_symlink calls to also
clean up after upgrades to an earlier version in testing.
-- Andreas Beckmann <anbe@debian.org> Thu, 01 Apr 2021 16:01:51 +0200
dnsmasq (2.84-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Fix symlink to directory conversion for /usr/share/doc/dnsmasq.
This is achieved by directly calling dpkg-maintscript-helper in the preinst,
postinst, and postrm scripts, since the package does not use debhelper.
(Closes: #985282)
-- Sébastien Villemot <sebastien@debian.org> Sun, 28 Mar 2021 10:55:07 +0200
dnsmasq (2.84-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 24 Jan 2021 22:02:01 +0000
dnsmasq (2.83-1) unstable; urgency=high
* New upstream.
* Includes fixes to CVE-2020-25681 - CVE-2020-25687 inclusive.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 15 Jan 2021 22:22:41 +0000
dnsmasq (2.82-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 22:22:41 +0000
dnsmasq (2.81-4) unstable; urgency=low
* Remove runit support when building for Ubuntu. (closes: #960401)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 26 Jun 2020 21:52:44 +0000
dnsmasq (2.81-3) unstable; urgency=low
* Fixes to control file for bug 958100
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 19 Apr 2020 21:44:12 +0000
dnsmasq (2.81-2) unstable; urgency=low
* Fix FTBFS on kFreeBSD. (closes: #958100)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 18 Apr 2020 18:34:15 +0000
dnsmasq (2.81-1) unstable; urgency=low
* New upstream.
* Fix nodocs/nodoc confusion in rules. (closes: #922758)
* Add Vcs-* fields to control. (closes: #922422)
* Add systemd support for multiple daemon instances. (closes: #914305)
* Add note explaining that ENABLED is SYSV-init only. (closes: #914755)
* Replace ash with dash in contrib/reverse-dns. (closes: #920224)
* Move to libidn2. (closes: #932695)
* Fix RA problem with two interfaces on same net, but RA service on
only one of the interfaces. (closes: #949565)
* Fix breakage of dig +trace. (closes: #942363)
* Fix build faliure with newer Nettle libraries. (closes: #940985)
* Support runscript init-system (closes: #929884)
* Security fix for CVE-2019-14834 (closes: #948373)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 8 Apr 2020 17:33:15 +0000
dnsmasq (2.80-1) unstable; urgency=low
* New upstream. (closes: #837602) (closes: #794640) (closes: #794636)
* Close old bugs, long agp fixed. (closes: #802845) (closes: #754299)
* Provide usr/lib/tmpfiles.d/dnsmasq.conf. (closes: #872396)
* Run restorecon on /run/dnsmasq for SE Linux. (closes: #872397)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 17 Sep 2018 23:11:25 +0000
dnsmasq (2.79-1) unstable; urgency=low
* New upstream. (closes: #888200)
* Fix trust-anchor regex in init script. (closes: #884347)
* Fix exit code for dhcp_release6 (closes: #883596)
* Add project homepage to control file. (closes: #887764)
* New binary package dnsmasq-base-lua, includes Lua support.
* Remove hardwired shlibs dependency for libnettle 3.3 and
fix code to avoid ABI breakage as long as compiled against
libnettle 3.4 or later. (closes: #891315)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 Feb 2018 19:54:22 +0000
dnsmasq (2.78-3) unstable; urgency=high
* Make failure of pidfile chown a warning. (closes: #889857)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 8 Feb 2018 21:26:30 +0000
dnsmasq (2.78-2) unstable; urgency=high
* Change ownership of pid file, to keep systemd happy. (closes: #889336)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 6 Feb 2018 17:21:30 +0000
dnsmasq (2.78-1) unstable; urgency=high
* New upstream.
Security fixes for CVE-2017-13704 (closes: #877102)
Security fixes for CVE-2017-14491 - CVE-2017-14496 inclusive.
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 29 Sep 2017 21:34:00 +0000
dnsmasq (2.77-2) unstable; urgency=low
* Improve sed regexp for parsing root.ds.
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 5 Jun 2017 20:46:32 +0000
dnsmasq (2.77-1) unstable; urgency=low
* New upstream.
* Don't register as a resolvconf source when config file
includes port=0 to disable DNS.
* Handle gratuitous format change in /usr/share/dns/root.ds
(closes: #858506) (closes: #860064)
* Add lsb-base dependency.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 11 Apr 2017 14:19:20 +0000
dnsmasq (2.76-5) unstable; urgency=medium
* Nail libnettle dependency to avoid ABI incompatibility.
(closes: #846642)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 14 Dec 2016 17:58:10 +0000
dnsmasq (2.76-4.1) unstable; urgency=medium
* Non-maintainer upload.
* Add two upstream patches to fix binding to an interface being
destroyed and recreated. Closes: #834722.
+ 2675f2061525bc954be14988d64384b74aa7bf8b
+ 16800ea072dd0cdf14d951c4bb8d2808b3dfe53d
-- Vincent Bernat <bernat@debian.org> Sat, 26 Nov 2016 20:15:34 +0100
dnsmasq (2.76-4) unstable; urgency=medium
* Non-maintainer upload.
* Fix FTCBFS: Use triplet-prefixed tools. (closes: #836072)
-- Helmut Grohne <helmut@subdivi.de> Tue, 30 Aug 2016 13:59:12 +0200
dnsmasq (2.76-3) unstable; urgency=medium
* Bump auth zone serial on SIGHUP. (closes: #833733)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 13 Aug 2016 21:43:10 +0000
dnsmasq (2.76-2) unstable; urgency=medium
* Fix to systemd to fix failure to start with bridge interface.
(Closes: #831372)
-- Simon Kelley <simon@thekelleys.org.uk> Sat, 16 Jul 2016 22:09:10 +0000
dnsmasq (2.76-1.2) unstable; urgency=medium
* Non-maintainer upload.
* dnsmasq: Install marker file to determine package installed state,
for the benefit of the init script. (Closes: #819856)
-- Christian Hofstaedtler <zeha@debian.org> Sat, 16 Jul 2016 00:17:57 +0000
dnsmasq (2.76-1.1) unstable; urgency=medium
* Non-maintainer upload.
* Provide nss-lookup.target for systemd, without relying on insserv.
Patch from Michael Biebl <biebl@debian.org>. (Closes: #826242)
-- Christian Hofstaedtler <zeha@debian.org> Fri, 01 Jul 2016 13:41:11 +0000
dnsmasq (2.76-1) unstable; urgency=low
* New upstream. (closes: #798586)
* Use /run/dnsmasq directly, rather than relying on link from /var/run
to avoid problems before /var is mounted. (closes: #800351)
* Test for the existence of /usr/share/doc/dnsmasq rather then
/etc/dnsmasq.d/README in the daemon startup script. (closes: #819856)
* Add --help to manpage and mention dhcp6 in summary. (closes: #821226)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 10 Sep 2015 23:07:21 +0000
dnsmasq (2.75-1) unstable; urgency=low
* New upstream. (closes: #794095)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 30 Jul 2015 20:58:31 +0000
dnsmasq (2.74-1) unstable; urgency=low
* New upstream. (LP: #1468611)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 15 Jul 2015 21:54:11 +0000
dnsmasq (2.73-2) unstable; urgency=low
* Fix behaviour of empty --conf-file (closes: #790341)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 7 Jul 2015 21:46:42 +0000
dnsmasq (2.73-1) unstable; urgency=low
* New upstream. (closes: #786996)
* Tweak field width in cache dump to avoid truncating IPv6
addresses. (closes: #771557)
* Add newline at the end of example config file. (LP: #1416895)
* Make Debian package build reproducible. (closes: #777323)
* Add Requires=network.target to systemd unit.
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 4 Jun 2015 22:31:42 +0000
dnsmasq (2.72-3) unstable; urgency=medium
* debian/systemd.service: switch from Type=dbus to Type=forking.
dnsmasq does not depend on dbus, but Type=dbus systemd services cannot
work without it. (Closes: #769486, #776530)
- debian/init: when called with systemd-exec argument, let dnsmasq
go into the background, so Type=forking can detect when it is ready
* Remove line containing only whitespace in debian/control.
(closes: #777571)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 11 Feb 2015 21:56:12 +0000
dnsmasq (2.72-2) unstable; urgency=low
* Fix build in Debian-kFreeBSD. (closes: #763693)
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 02 Oct 2014 22:34:12 +0000
dnsmasq (2.72-1) unstable; urgency=low
* New upstream.
* If dns-root-data package is installed, use it to set the DNSSEC
trust anchor(s). Recommend dns-root-data. (closes: #760460)
* Handle AD bit correctly in replies from cache. (closes: #761654)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 20 May 2014 21:01:11 +0000
dnsmasq (2.71-1) unstable; urgency=low
* New upstream.
* Fix 100% CPU-usage bug when dnsmasq started with cachesize
set to zero. (LP: #1314697)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 16 May 2014 20:17:10 +0000
dnsmasq (2.70-3) unstable; urgency=medium
* Write a pid-file, even when being started using systemd, since
other components may wish to signal dnsmasq.
* Enable dnsmasq systemd unit on install. Otherwise dnsmasq does not run on
fresh installations (without administrator handholding) and even worse it
is disabled on systems switching from sysv to systemd. Modify
postinst/postrm exactly as dh_systemd would, add dependency on
init-system-helpers. Closes: #724602
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 11 May 2014 17:45:21 +0000
dnsmasq (2.70-2) unstable; urgency=low
* Ensure daemon not stared if dnsmasq package has been removed,
even if dnsmasq-base is still installed. (closes: #746941)
* Tidy cruft in initscript. (closes: #746940)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 04 May 2014 21:34:11 +0000
dnsmasq (2.70-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 23 Apr 2014 15:14:42 +0000
dnsmasq (2.69-1) unstable; urgency=low
* New upstream.
* Set --local-service. (closes: #732610)
This tells dnsmasq to ignore DNS requests that don't come
from a local network. It's automatically ignored if
--interface --except-interface, --listen-address or
--auth-server exist in the configuration, so for most
installations, it will have no effect, but for
otherwise-unconfigured installations, it stops dnsmasq
from being vulnerable to DNS-reflection attacks.
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 4 Feb 2014 16:28:12 +0000
dnsmasq (2.68-1) unstable; urgency=low
* New upstream. (closes: #730553)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 8 Dec 2013 15:57:32 +0000
dnsmasq (2.67-1) unstable; urgency=low
* New upstream.
* Update resolvconf script. (closes: #720732)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:53:22 +0000
dnsmasq (2.66-4) unstable; urgency=low
* Update resolvconf script. (closes: #716908)
-- Simon Kelley <simon@thekelleys.org.uk> Wed, 4 Aug 2013 14:48:21 +0000
dnsmasq (2.66-3) unstable; urgency=low
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
dnsmasq (2.66-2) unstable; urgency=low
* Fix error on startup with some configs. (closes: #709010)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
dnsmasq (2.66-1) unstable; urgency=low
* New upstream.
* Add support for noipset in DEB_BUILD_OPTIONS.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 22 Feb 2013 21:52:13 +0000
dnsmasq (2.65-1) unstable; urgency=low
* New upstream.
@@ -873,7 +504,7 @@ dnsmasq (2.26-1) unstable; urgency=high
dnsmasq (2.25-1) unstable; urgency=low
* Remove bashisms in postinst and prerm scripts.
* Remove misconceived dependency on locales.
* Remove misconcieved dependency on locales.
* Depend on adduser.
-- Simon Kelley <simon@thekelleys.org.uk> Thu, 01 Dec 2005 21:02:12 +0000
@@ -895,7 +526,7 @@ dnsmasq (2.23-1) unstable; urgency=low
* Add support for DNSMASQ_EXCEPT in /etc/defaults/dnsmasq.
putting "lo" in this also disables resolvconf support.
* No longer delete pre-existing /etc/init.d symlinks. The
change in default runlevels which necessitated this
change in default runlevels which neccesitated this
is now ancient history and anyway the startup script now
behaves when called twice. (closes: #312111)
* Tightened config-file parser. (closes: #317030)
@@ -1080,7 +711,7 @@ dnsmasq (2.6-3) unstable; urgency=low
* Removed reload command from start script and moved force-reload
to be equivalent to restart. This is needed to be policy compliant
since SIGHUP doesn't cause dnsmasq to reload its configuration file,
since SIHGUP doesn't cause dnsmasq to reload its configuration file,
only the /etc/hosts, /etc/resolv.conf etc. (closes: #244208)
-- Simon Kelley <simon@thekelleys.org.uk> Sun, 18 Apr 2004 14:40:51 +0000
@@ -1098,7 +729,7 @@ dnsmasq (2.6-2) unstable; urgency=low
* Added note about the --bind-interfaces option to
readme.Debian (closes: #241700)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 13 Apr 2004 18:37:55 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 13 Apr 2004 18:37:55 +0000
dnsmasq (2.6-1) unstable; urgency=low
@@ -1170,8 +801,8 @@ dnsmasq (2.0-1) unstable; urgency=low
* New upstream: This removes the ability to read the
the leases file of ISC DHCP and replaces it with a built-in
DHCP server. Apologies in advance for breaking backwards
compatibility, but this replaces a bit of a hack (the ISC stuff)
with a nicely engineered and much more appropriate solution.
compatibilty, but this replaces a bit of a hack (the ISC stuff)
with a nicely engineered and much more apropriate solution.
Wearing my upstream-maintainer hat, I want to lose the hack now,
rather than have to support it into Sarge.
* New upstream closes some bugs since they become
@@ -1197,7 +828,7 @@ dnsmasq (1.18-1) unstable; urgency=low
* New upstream which does round-robin. (closes: #215460)
* Removed conflicts with other dns servers since it is now
possible to control exactly where dnsmasq listens on multi-homed
hosts, making co-existence with another nameserver
hosts, making co-existance with another nameserver
a viable proposition. (closes #176163)
* New upstream allows _ in hostnames and check for illegal
names in /etc/hosts. (closes: #218842)
@@ -1283,13 +914,13 @@ dnsmasq (1.11-2) unstable; urgency=low
dnsmasq (1.11-1) unstable; urgency=low
* New upstream.
* New uptream.
-- Simon Kelley <simon@thekelleys.org.uk> Tues, 12 Jan 2003 22:25:17 -0100
dnsmasq (1.10-1) unstable; urgency=low
* New upstream.
* New uptream.
* Force service to stop in postinst before restarting. I don't
understand the circumstances under which it would still be running at
this point, but this is the correct fix anyway. (closes: #169718)
@@ -1301,7 +932,7 @@ dnsmasq (1.10-1) unstable; urgency=low
dnsmasq (1.9-1) unstable; urgency=low
* New upstream.
* New uptream.
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 23 Sept 2002 21:35:07 -0100

38
debian/control vendored
View File

@@ -1,24 +1,15 @@
Source: dnsmasq
Section: net
Priority: optional
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any],
libidn2-dev, libdbus-1-dev (>=0.61), libgmp-dev,
nettle-dev (>=2.4-3), libbsd-dev [kfreebsd-any],
liblua5.2-dev, dh-runit, debhelper-compat (= 10),
pkg-config, libnftables-dev
Build-depends: gettext, libnetfilter-conntrack-dev [linux-any], libidn11-dev, libdbus-1-dev (>=0.61)
Maintainer: Simon Kelley <simon@thekelleys.org.uk>
Homepage: http://www.thekelleys.org.uk/dnsmasq/doc.html
Vcs-Git: http://thekelleys.org.uk/git/dnsmasq.git
Vcs-Browser: http://thekelleys.org.uk/gitweb/?p=dnsmasq.git
Standards-Version: 3.9.8
Standards-Version: 3.9.3
Package: dnsmasq
Architecture: all
Depends: netbase, dnsmasq-base,
init-system-helpers (>= 1.18~), lsb-base (>= 3.0-6), ${misc:Depends}
Depends: netbase, dnsmasq-base(>= ${source:Version})
Suggests: resolvconf
Breaks: ${runit:Breaks}
Conflicts: resolvconf (<<1.15), ${runit:Conflicts}
Conflicts: resolvconf (<<1.15)
Description: Small caching DNS proxy and DHCP/TFTP server
Dnsmasq is a lightweight, easy to configure, DNS forwarder and DHCP
server. It is designed to provide DNS and optionally, DHCP, to a
@@ -33,29 +24,12 @@ Package: dnsmasq-base
Architecture: any
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
Recommends: dns-root-data
Provides: dnsmasq-base
Conflicts: dnsmasq-base-lua
Replaces: dnsmasq (<< 2.63-1~)
Description: Small caching DNS proxy and DHCP/TFTP server
This package contains the dnsmasq executable and documentation, but
not the infrastructure required to run it as a system daemon. For
that, install the dnsmasq package.
Package: dnsmasq-base-lua
Architecture: any
Depends: adduser, ${shlibs:Depends}
Breaks: dnsmasq (<< 2.63-1~)
Replaces: dnsmasq (<< 2.63-1~), dnsmasq-base
Recommends: dns-root-data
Provides: dnsmasq-base
Conflicts: dnsmasq-base
Description: Small caching DNS proxy and DHCP/TFTP server
This package contains the dnsmasq executable and documentation, but
not the infrastructure required to run it as a system daemon. For
that, install the dnsmasq package. This package is an alternative
to dnsmasq-base which includes the LUA interpreter.
Package: dnsmasq-utils
Architecture: linux-any
Depends: ${shlibs:Depends}
@@ -64,3 +38,5 @@ Description: Utilities for manipulating DHCP leases
Small utilities to query a DHCP server's lease database and
remove leases from it. These programs are distributed with dnsmasq
and may not work correctly with other DHCP servers.

2
debian/copyright vendored
View File

@@ -1,4 +1,4 @@
dnsmasq is Copyright (c) 2000-2021 Simon Kelley
dnsmasq is Copyright (c) 2000-2012 Simon Kelley
It was downloaded from: http://www.thekelleys.org.uk/dnsmasq/

23
debian/default vendored
View File

@@ -1,15 +1,13 @@
# This file has six functions:
# 1) to completely disable starting this dnsmasq instance
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
# This file has five functions:
# 1) to completely disable starting dnsmasq,
# 2) to set DOMAIN_SUFFIX by running `dnsdomainname`
# 3) to select an alternative config file
# by setting DNSMASQ_OPTS to --conf-file=<file>
# 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for
# more configuration variables.
# 5) to stop the resolvconf package from controlling dnsmasq's
# idea of which upstream nameservers to use.
# 6) to avoid using this dnsmasq instance as the system's default resolver
# by setting DNSMASQ_EXCEPT="lo"
# For upgraders from very old versions, all the shell variables set
# For upgraders from very old versions, all the shell variables set
# here in previous versions are still honored by the init script
# so if you just keep your old version of this file nothing will break.
@@ -17,8 +15,6 @@
#DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt"
# Whether or not to run the dnsmasq daemon; set to 0 to disable.
# Note that this is only valid when using SYSV init. For systemd,
# use "systemctl disable dnsmasq"
ENABLED=1
# By default search this drop directory for configuration options.
@@ -28,15 +24,10 @@ ENABLED=1
# in backups made by dpkg.
CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new
# If the resolvconf package is installed, dnsmasq will use its output
# rather than the contents of /etc/resolv.conf to find upstream
# If the resolvconf package is installed, dnsmasq will use its output
# rather than the contents of /etc/resolv.conf to find upstream
# nameservers. Uncommenting this line inhibits this behaviour.
# Note that including a "resolv-file=<filename>" line in
# Not that including a "resolv-file=<filename>" line in
# /etc/dnsmasq.conf is not enough to override resolvconf if it is
# installed: the line below must be uncommented.
#IGNORE_RESOLVCONF=yes
# If the resolvconf package is installed, dnsmasq will tell resolvconf
# to use dnsmasq under 127.0.0.1 as the system's default resolver.
# Uncommenting this line inhibits this behaviour.
#DNSMASQ_EXCEPT="lo"

View File

@@ -17,8 +17,8 @@ if [ "$1" = "configure" ]; then
# dnsmasq-base, but it's much easier to create it here so that
# we don't have synchronisation issues with the creation of the
# dnsmasq user.
if [ ! -d /run/dnsmasq ]; then
mkdir /run/dnsmasq
chown dnsmasq:nogroup /run/dnsmasq
if [ ! -d /var/run/dnsmasq ]; then
mkdir /var/run/dnsmasq
chown dnsmasq:nogroup /var/run/dnsmasq
fi
fi

View File

@@ -7,5 +7,5 @@ if [ purge = "$1" ]; then
else
echo >&2 "not removing dnsmasq system account because deluser command was not found"
fi
rm -rf /run/dnsmasq
rm -rf /var/run/dnsmasq
fi

View File

@@ -1 +0,0 @@
debian/dnsmasq.runscript name=dnsmasq,logscript,presubj

View File

@@ -1,5 +0,0 @@
#!/bin/sh -eu
if [ -x /sbin/resolvconf ] ; then
/sbin/resolvconf -d lo.dnsmasq
fi

View File

@@ -1,43 +0,0 @@
#!/lib/runit/invoke-run
readonly name=dnsmasq
readonly daemon=/usr/sbin/dnsmasq
readonly marker=/usr/share/dnsmasq/installed-marker
test -e "${marker}" || exec sv down "${name}"
test -x "${daemon}" || exec sv down "${name}"
if [ ! "${RESOLV_CONF:-}" ] &&
[ "${IGNORE_RESOLVCONF:-}" != "yes" ] &&
[ -x /sbin/resolvconf ]
then
RESOLV_CONF=/run/dnsmasq/resolv.conf
fi
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
# It's automatically ignored if --interface --except-interface, --listen-address
# or --auth-server exist in the configuration, so for most installations, it will
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
# from being vulnerable to DNS-reflection attacks.
DNSMASQ_OPTS="${DNSMASQ_OPTS:-} --local-service"
# If the dns-root-data package is installed, then the trust anchors will be
# available in $ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
# --trust-anchor options.
ROOT_DS="/usr/share/dns/root.ds"
if [ -f $ROOT_DS ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
fi
mkdir -p /run/dnsmasq
chown dnsmasq:nogroup /run/dnsmasq
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
exec "${daemon}" \
--keep-in-foreground \
--log-facility=/dev/stdout \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${DNSMASQ_OPTS} \
-u dnsmasq

425
debian/init vendored
View File

@@ -8,61 +8,54 @@
# Description: DHCP and DNS server
### END INIT INFO
# Don't exit on error status
set +e
set +e # Don't exit on error status
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/dnsmasq
NAME=dnsmasq
DESC="DNS forwarder and DHCP server"
INSTANCE="${2}"
# Most configuration options in /etc/default/dnsmasq are deprecated
# but still honoured.
ENABLED=1
if [ -r /etc/default/${NAME}${INSTANCE:+.${INSTANCE}} ]; then
. /etc/default/${NAME}${INSTANCE:+.${INSTANCE}}
if [ -r /etc/default/$NAME ]; then
. /etc/default/$NAME
fi
# Get the system locale, so that messages are in the correct language, and the
# Get the system locale, so that messages are in the correct language, and the
# charset for IDN is correct
if [ -r /etc/default/locale ]; then
. /etc/default/locale
export LANG
. /etc/default/locale
export LANG
fi
# The following test ensures the dnsmasq service is not started, when the
# package 'dnsmasq' is removed but not purged, even if the dnsmasq-base
# package is still in place.
test -e /usr/share/dnsmasq/installed-marker || exit 0
test -x ${DAEMON} || exit 0
test -x $DAEMON || exit 0
# Provide skeleton LSB log functions for backports which don't have LSB functions.
if [ -f /lib/lsb/init-functions ]; then
. /lib/lsb/init-functions
. /lib/lsb/init-functions
else
log_warning_msg () {
echo "${@}."
}
log_warning_msg () {
echo "${@}."
}
log_success_msg () {
echo "${@}."
}
log_success_msg () {
echo "${@}."
}
log_daemon_msg () {
echo -n "${1}: ${2}"
}
log_daemon_msg () {
echo -n "${1}: $2"
}
log_end_msg () {
if [ "${1}" -eq 0 ]; then
echo "."
elif [ "${1}" -eq 255 ]; then
/bin/echo -e " (warning)."
else
/bin/echo -e " failed!"
fi
}
log_end_msg () {
if [ $1 -eq 0 ]; then
echo "."
elif [ $1 -eq 255 ]; then
/bin/echo -e " (warning)."
else
/bin/echo -e " failed!"
fi
}
fi
# RESOLV_CONF:
@@ -74,76 +67,57 @@ fi
# filename is set there then this inhibits the use of the resolvconf-provided
# information.
#
# Note that if the resolvconf package is installed it is not possible to
# Note that if the resolvconf package is installed it is not possible to
# override it just by configuration in /etc/dnsmasq.conf, it is necessary
# to set IGNORE_RESOLVCONF=yes in /etc/default/dnsmasq.
if [ ! "${RESOLV_CONF}" ] &&
[ "${IGNORE_RESOLVCONF}" != "yes" ] &&
if [ ! "$RESOLV_CONF" ] &&
[ "$IGNORE_RESOLVCONF" != "yes" ] &&
[ -x /sbin/resolvconf ]
then
RESOLV_CONF=/run/dnsmasq/resolv.conf
RESOLV_CONF=/var/run/dnsmasq/resolv.conf
fi
for INTERFACE in ${DNSMASQ_INTERFACE}; do
DNSMASQ_INTERFACES="${DNSMASQ_INTERFACES} -i ${INTERFACE}"
for INTERFACE in $DNSMASQ_INTERFACE; do
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -i $INTERFACE"
done
for INTERFACE in ${DNSMASQ_EXCEPT}; do
DNSMASQ_INTERFACES="${DNSMASQ_INTERFACES} -I ${INTERFACE}"
for INTERFACE in $DNSMASQ_EXCEPT; do
DNSMASQ_INTERFACES="$DNSMASQ_INTERFACES -I $INTERFACE"
done
if [ ! "${DNSMASQ_USER}" ]; then
if [ ! "$DNSMASQ_USER" ]; then
DNSMASQ_USER="dnsmasq"
fi
# This tells dnsmasq to ignore DNS requests that don't come from a local network.
# It's automatically ignored if --interface --except-interface, --listen-address
# or --auth-server exist in the configuration, so for most installations, it will
# have no effect, but for otherwise-unconfigured installations, it stops dnsmasq
# from being vulnerable to DNS-reflection attacks.
DNSMASQ_OPTS="${DNSMASQ_OPTS} --local-service"
# If the dns-root-data package is installed, then the trust anchors will be
# available in ROOT_DS, in BIND zone-file format. Reformat as dnsmasq
# --trust-anchor options.
ROOT_DS="/usr/share/dns/root.ds"
if [ -f ${ROOT_DS} ]; then
DNSMASQ_OPTS="$DNSMASQ_OPTS `env LC_ALL=C sed -rne "s/^([.a-zA-Z0-9]+)([[:space:]]+[0-9]+)*([[:space:]]+IN)*[[:space:]]+DS[[:space:]]+/--trust-anchor=\1,/;s/[[:space:]]+/,/gp" $ROOT_DS | tr '\n' ' '`"
fi
start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
# /run may be volatile, so we need to ensure that
# /run/dnsmasq exists here as well as in postinst
if [ ! -d /run/dnsmasq ]; then
mkdir /run/dnsmasq || { [ -d /run/dnsmasq ] || return 2 ; }
chown dnsmasq:nogroup /run/dnsmasq || return 2
fi
[ -x /sbin/restorecon ] && /sbin/restorecon /run/dnsmasq
# /var/run may be volatile, so we need to ensure that
# /var/run/dnsmasq exists here as well as in postinst
if [ ! -d /var/run/dnsmasq ]; then
mkdir /var/run/dnsmasq || return 2
chown dnsmasq:nogroup /var/run/dnsmasq || return 2
fi
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} -- \
-x /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid \
${MAILHOSTNAME:+ -m ${MAILHOSTNAME}} \
${MAILTARGET:+ -t ${MAILTARGET}} \
${DNSMASQ_USER:+ -u ${DNSMASQ_USER}} \
${DNSMASQ_INTERFACES:+ ${DNSMASQ_INTERFACES}} \
${DHCP_LEASE:+ -l ${DHCP_LEASE}} \
${DOMAIN_SUFFIX:+ -s ${DOMAIN_SUFFIX}} \
${RESOLV_CONF:+ -r ${RESOLV_CONF}} \
${CACHESIZE:+ -c ${CACHESIZE}} \
${CONFIG_DIR:+ -7 ${CONFIG_DIR}} \
${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} \
|| return 2
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null || return 1
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON -- \
-x /var/run/dnsmasq/$NAME.pid \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
${DHCP_LEASE:+ -l $DHCP_LEASE} \
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${CACHESIZE:+ -c $CACHESIZE} \
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} \
|| return 2
}
start_resolvconf()
@@ -151,175 +125,166 @@ start_resolvconf()
# If interface "lo" is explicitly disabled in /etc/default/dnsmasq
# Then dnsmasq won't be providing local DNS, so don't add it to
# the resolvconf server set.
for interface in ${DNSMASQ_EXCEPT}; do
[ ${interface} = lo ] && return
done
for interface in $DNSMASQ_EXCEPT
do
[ $interface = lo ] && return
done
# Also skip this if DNS functionality is disabled in /etc/dnsmasq.conf
if grep -qs '^port=0' /etc/dnsmasq.conf; then
return
fi
if [ -x /sbin/resolvconf ] ; then
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.${NAME}${INSTANCE:+.${INSTANCE}}
fi
return 0
if [ -x /sbin/resolvconf ] ; then
echo "nameserver 127.0.0.1" | /sbin/resolvconf -a lo.$NAME
fi
return 0
}
stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --name ${NAME}
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile /var/run/dnsmasq/$NAME.pid --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
return "$RETVAL"
}
stop_resolvconf()
{
if [ -x /sbin/resolvconf ] ; then
/sbin/resolvconf -d lo.${NAME}${INSTANCE:+.${INSTANCE}}
fi
return 0
if [ -x /sbin/resolvconf ] ; then
/sbin/resolvconf -d lo.$NAME
fi
return 0
}
status()
{
# Return
# 0 if daemon is running
# 1 if daemon is dead and pid file exists
# 3 if daemon is not running
# 4 if daemon status is unknown
start-stop-daemon --start --quiet --pidfile /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid --exec ${DAEMON} --test > /dev/null
case "${?}" in
0) [ -e "/run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid" ] && return 1 ; return 3 ;;
1) return 0 ;;
*) return 4 ;;
esac
# Return
# 0 if daemon is running
# 1 if daemon is dead and pid file exists
# 3 if daemon is not running
# 4 if daemon status is unknown
start-stop-daemon --start --quiet --pidfile /var/run/dnsmasq/$NAME.pid --exec $DAEMON --test > /dev/null
case "$?" in
0) [ -e "/var/run/dnsmasq/$NAME.pid" ] && return 1 ; return 3 ;;
1) return 0 ;;
*) return 4 ;;
esac
}
case "${1}" in
case "$1" in
start)
test "${ENABLED}" != "0" || exit 0
log_daemon_msg "Starting ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
start
case "${?}" in
0)
log_end_msg 0
start_resolvconf
exit 0
;;
1)
log_success_msg "(already running)"
exit 0
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
test "$ENABLED" != "0" || exit 0
log_daemon_msg "Starting $DESC" "$NAME"
start
case "$?" in
0)
log_end_msg 0
start_resolvconf
exit 0
;;
1)
log_success_msg "(already running)"
exit 0
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
stop)
stop_resolvconf
if [ "${ENABLED}" != "0" ]; then
log_daemon_msg "Stopping ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
fi
stop
RETVAL="${?}"
if [ "${ENABLED}" = "0" ]; then
case "${RETVAL}" in
0) log_daemon_msg "Stopping ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"; log_end_msg 0 ;;
esac
exit 0
fi
case "${RETVAL}" in
0) log_end_msg 0 ; exit 0 ;;
1) log_warning_msg "(not running)" ; exit 0 ;;
*) log_end_msg 1; exit 1 ;;
esac
;;
checkconfig)
${DAEMON} --test ${CONFIG_DIR:+ -7 ${CONFIG_DIR}} ${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} >/dev/null 2>&1
RETVAL="${?}"
exit ${RETVAL}
;;
stop_resolvconf
if [ "$ENABLED" != "0" ]; then
log_daemon_msg "Stopping $DESC" "$NAME"
fi
stop
RETVAL="$?"
if [ "$ENABLED" = "0" ]; then
case "$RETVAL" in
0) log_daemon_msg "Stopping $DESC" "$NAME"; log_end_msg 0 ;;
esac
exit 0
fi
case "$RETVAL" in
0) log_end_msg 0 ; exit 0 ;;
1) log_warning_msg "(not running)" ; exit 0 ;;
*) log_end_msg 1; exit 1 ;;
esac
;;
restart|force-reload)
test "${ENABLED}" != "0" || exit 1
${DAEMON} --test ${CONFIG_DIR:+ -7 ${CONFIG_DIR}} ${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}} >/dev/null 2>&1
if [ ${?} -ne 0 ]; then
NAME="configuration syntax check"
RETVAL="2"
else
stop_resolvconf
stop
RETVAL="${?}"
fi
log_daemon_msg "Restarting ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
case "${RETVAL}" in
0|1)
sleep 2
start
case "${?}" in
0)
log_end_msg 0
start_resolvconf
exit 0
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
test "$ENABLED" != "0" || exit 1
$DAEMON --test ${CONFIG_DIR:+ -7 $CONFIG_DIR} ${DNSMASQ_OPTS:+ $DNSMASQ_OPTS} >/dev/null 2>&1
if [ $? -ne 0 ]; then
NAME="configuration syntax check"
RETVAL="2"
else
stop_resolvconf
stop
RETVAL="$?"
fi
log_daemon_msg "Restarting $DESC" "$NAME"
case "$RETVAL" in
0|1)
sleep 2
start
case "$?" in
0)
log_end_msg 0
start_resolvconf
exit 0
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
*)
log_end_msg 1
exit 1
;;
esac
;;
status)
log_daemon_msg "Checking ${DESC}" "${NAME}${INSTANCE:+.${INSTANCE}}"
status
case "${?}" in
0) log_success_msg "(running)" ; exit 0 ;;
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
3) log_success_msg "(not running)" ; exit 3 ;;
*) log_success_msg "(unknown)" ; exit 4 ;;
esac
;;
log_daemon_msg "Checking $DESC" "$NAME"
status
case "$?" in
0) log_success_msg "(running)" ; exit 0 ;;
1) log_success_msg "(dead, pid file exists)" ; exit 1 ;;
3) log_success_msg "(not running)" ; exit 3 ;;
*) log_success_msg "(unknown)" ; exit 4 ;;
esac
;;
dump-stats)
kill -s USR1 `cat /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid`
;;
kill -s USR1 `cat /var/run/dnsmasq/$NAME.pid`
;;
systemd-start-resolvconf)
start_resolvconf
;;
start_resolvconf
;;
systemd-stop-resolvconf)
stop_resolvconf
;;
stop_resolvconf
;;
systemd-exec)
# /run may be volatile, so we need to ensure that
# /run/dnsmasq exists here as well as in postinst
if [ ! -d /run/dnsmasq ]; then
mkdir /run/dnsmasq || { [ -d /run/dnsmasq ] || return 2 ; }
chown dnsmasq:nogroup /run/dnsmasq || return 2
fi
exec ${DAEMON} -x /run/dnsmasq/${NAME}${INSTANCE:+.${INSTANCE}}.pid \
${MAILHOSTNAME:+ -m ${MAILHOSTNAME}} \
${MAILTARGET:+ -t ${MAILTARGET}} \
${DNSMASQ_USER:+ -u ${DNSMASQ_USER}} \
${DNSMASQ_INTERFACES:+ ${DNSMASQ_INTERFACES}} \
${DHCP_LEASE:+ -l ${DHCP_LEASE}} \
${DOMAIN_SUFFIX:+ -s ${DOMAIN_SUFFIX}} \
${RESOLV_CONF:+ -r ${RESOLV_CONF}} \
${CACHESIZE:+ -c ${CACHESIZE}} \
${CONFIG_DIR:+ -7 ${CONFIG_DIR}} \
${DNSMASQ_OPTS:+ ${DNSMASQ_OPTS}}
;;
# --pid-file without argument disables writing a PIDfile, we don't need one with sytemd.
# Enable DBus by default because we use DBus activation with systemd.
exec $DAEMON --keep-in-foreground --pid-file --enable-dbus \
${MAILHOSTNAME:+ -m $MAILHOSTNAME} \
${MAILTARGET:+ -t $MAILTARGET} \
${DNSMASQ_USER:+ -u $DNSMASQ_USER} \
${DNSMASQ_INTERFACES:+ $DNSMASQ_INTERFACES} \
${DHCP_LEASE:+ -l $DHCP_LEASE} \
${DOMAIN_SUFFIX:+ -s $DOMAIN_SUFFIX} \
${RESOLV_CONF:+ -r $RESOLV_CONF} \
${CACHESIZE:+ -c $CACHESIZE} \
${CONFIG_DIR:+ -7 $CONFIG_DIR} \
${DNSMASQ_OPTS:+ $DNSMASQ_OPTS}
;;
*)
echo "Usage: /etc/init.d/${NAME} {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3
;;
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|dump-stats|status}" >&2
exit 3
;;
esac
exit 0

View File

@@ -1,2 +0,0 @@
# This file indicates dnsmasq (and not just dnsmasq-base) is installed.
# It is an implementation detail of the dnsmasq init script.

View File

@@ -1,3 +0,0 @@
# dnsmasq-base and dnsmasq-base-lua are mutually exclusive and both
# provide /usr/share/doc/dnsmasq-base
dnsmasq-base-lua binary: usr-share-doc-symlink-without-dependency dnsmasq-base

21
debian/postinst vendored
View File

@@ -1,30 +1,11 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
# Code copied from dh_systemd_enable ----------------------
# This will only remove masks created by d-s-h on package removal.
deb-systemd-helper unmask dnsmasq.service >/dev/null || true
# was-enabled defaults to true, so new installations run enable.
if deb-systemd-helper --quiet was-enabled dnsmasq.service; then
# Enables the unit on first installation, creates new
# symlinks on upgrades if the unit file has changed.
deb-systemd-helper enable dnsmasq.service >/dev/null || true
else
# Update the statefile to add new symlinks (if any), which need to be
# cleaned up on purge. Also remove old symlinks.
deb-systemd-helper update-state dnsmasq.service >/dev/null || true
fi
# End code copied from dh_systemd_enable ------------------
if [ -x /etc/init.d/dnsmasq ]; then
update-rc.d dnsmasq defaults 15 85 >/dev/null
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ]; then
if [ -e /run/dnsmasq/dnsmasq.pid ]; then
if [ -e /var/run/dnsmasq/dnsmasq.pid ]; then
ACTION=restart
else
ACTION=start

19
debian/postrm vendored
View File

@@ -1,25 +1,6 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"
if [ purge = "$1" ]; then
update-rc.d dnsmasq remove >/dev/null
fi
# Code copied from dh_systemd_enable ----------------------
if [ "$1" = "remove" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper mask dnsmasq.service >/dev/null
fi
fi
if [ "$1" = "purge" ]; then
if [ -x "/usr/bin/deb-systemd-helper" ]; then
deb-systemd-helper purge dnsmasq.service >/dev/null
deb-systemd-helper unmask dnsmasq.service >/dev/null
fi
fi
# End code copied from dh_systemd_enable ------------------

5
debian/preinst vendored
View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -e
# /usr/share/doc/dnsmasq was a symlink in versions < 2.81-1 (see #985282)
dpkg-maintscript-helper symlink_to_dir /usr/share/doc/dnsmasq dnsmasq-base 2.84-1.2~ dnsmasq -- "$@"

10
debian/readme vendored
View File

@@ -31,7 +31,7 @@ Notes on configuring dnsmasq as packaged for Debian.
as the first nameserver address in /etc/resolv.conf.
(6) In the absence of resolvconf, dns-nameservers lines in
/etc/network/interfaces are ignored. If you do not use
/etc/network/interfaces are ignored. If you do do not use
resolvconf, list 127.0.0.1 as the first nameserver address
in /etc/resolv.conf and configure your nameservers using
"server=<IP-address>" lines in /etc/dnsmasq.conf.
@@ -54,20 +54,16 @@ Notes on configuring dnsmasq as packaged for Debian.
nodhcp : omit DHCP support.
nodhcp6 : omit DHCPv6 support.
noscript : omit lease-change script support.
uselua : provide support for lease-change scripts written
use_lua : provide support for lease-change scripts written
in Lua.
noipv6 : omit IPv6 support.
nodbus : omit DBus support.
noconntrack : omit connection tracking support.
noipset : omit IPset support.
nonftset : omit nftset support.
nortc : compile alternate mode suitable for systems without an RTC.
noi18n : omit translations and internationalisation support.
noidn : omit international domain name support, must be
combined with noi18n to be effective.
gitversion : set the version of the produced packages from the
git-derived versioning information on the source,
rather than the debian changelog.
(9) Dnsmasq comes as three packages - dnsmasq-utils, dnsmasq-base and
dnsmasq. Dnsmasq-base provides the dnsmasq executable and

40
debian/resolvconf vendored
View File

@@ -1,22 +1,23 @@
#!/bin/sh
#!/bin/bash
#
# Script to update the resolver list for dnsmasq
#
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
# If dnsmasq is installed then we go ahead and update the resolver list
# in case dnsmasq is started later.
# N.B. Resolvconf may run us even if dnsmasq is not running.
# If dnsmasq is installed then we go ahead and update
# the resolver list in case dnsmasq is started later.
#
# Assumption: On entry, PWD contains the resolv.conf-type files.
# Assumption: On entry, PWD contains the resolv.conf-type files
#
# This file is part of the dnsmasq package.
# Requires bash because it uses a non-POSIX printf extension.
#
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
#
set -e
RUN_DIR="/run/dnsmasq"
RUN_DIR="/var/run/dnsmasq"
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
MY_NAME_FOR_RESOLVCONF="dnsmasq"
[ -x /usr/sbin/dnsmasq ] || exit 0
[ -x /lib/resolvconf/list-records ] || exit 1
@@ -26,7 +27,7 @@ PATH=/bin:/sbin
report_err() { echo "$0: Error: $*" >&2 ; }
# Stores arguments (minus duplicates) in RSLT, separated by spaces
# Doesn't work properly if an argument itself contains whitespace
# Doesn't work properly if an argument itself contain whitespace
uniquify()
{
RSLT=""
@@ -44,22 +45,7 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
exit 1
fi
RSLVCNFFILES=""
for F in $(/lib/resolvconf/list-records --after "lo.$MY_NAME_FOR_RESOLVCONF") ; do
case "$F" in
"lo.$MY_NAME_FOR_RESOLVCONF")
# Omit own record
;;
lo.*)
# Include no more records after one for a local nameserver
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
break
;;
*)
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
;;
esac
done
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
NMSRVRS=""
if [ "$RSLVCNFFILES" ] ; then
@@ -70,8 +56,8 @@ fi
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
# to detect changes in the file. This means that if a resolvconf update occurs
# within one second of the previous one then dnsmasq may fail to notice the
# more recent change. To work around this problem we sleep one second here
# if necessary in order to ensure that the new mtime is different.
# more recent change. To work around this problem we sleep here to ensure
# that the new mtime is different.
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
sleep 1
fi

339
debian/rules vendored
View File

@@ -1,6 +1,6 @@
#!/usr/bin/make -f
# debian/rules file - for dnsmasq.
# Copyright 2001-2020 by Simon Kelley
# Copyright 2001-2011 by Simon Kelley
# Based on the sample in the debian hello package which carries the following:
# Copyright 1994,1995 by Ian Jackson.
# I hereby give you perpetual unlimited permission to copy,
@@ -11,282 +11,173 @@
package=dnsmasq-base
dpkg_buildflags := DEB_BUILD_MAINT_OPTIONS="hardening=+all,+pie,+bindnow" dpkg-buildflags
CFLAGS = $(shell $(dpkg_buildflags) --get CFLAGS)
CFLAGS += $(shell $(dpkg_buildflags) --get CPPFLAGS)
CFLAGS = $(shell export DEB_BUILD_OPTIONS=$(DEB_BUILD_OPTIONS); dpkg-buildflags --get CFLAGS)
CFLAGS += $(shell dpkg-buildflags --get CPPFLAGS)
CFLAGS += -Wall -W
LDFLAGS = $(shell $(dpkg_buildflags) --get LDFLAGS)
LDFLAGS = $(shell dpkg-buildflags --get LDFLAGS)
DEB_COPTS = $(COPTS)
COPTS =
TARGET = install-i18n
DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS)
DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE := $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
BUILD_DATE := $(shell dpkg-parsechangelog --show-field Date)
ifeq ($(origin CC),default)
CC = $(DEB_HOST_GNU_TYPE)-gcc
endif
# Support non-cross-builds on systems without gnu-triplet-binaries for pkg-config.
ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
PKG_CONFIG=pkg-config
else
PKG_CONFIG=$(DEB_HOST_GNU_TYPE)-pkg-config
endif
# Force package version based on git tags.
ifneq (,$(filter gitversion,$(DEB_BUILD_OPTIONS)))
PACKAGE_VERSION = $(shell bld/get-version `pwd` | sed 's/test/~&/; s/[a-z]/~&/; s/-/./g; s/$$/-1/; s/^/-v/';)
endif
DEB_BUILD_ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
ifeq (,$(filter nodbus,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DBUS
endif
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_LIBIDN2
endif
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_NFTSET
COPTS += -DHAVE_DBUS
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
ifeq ($(DEB_BUILD_ARCH_OS),linux)
COPTS += -DHAVE_CONNTRACK
endif
endif
ifneq (,$(filter noipset,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_IPSET
endif
ifneq (,$(filter nodhcp6,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_DHCP6
COPTS += -DNO_DHCP6
endif
ifneq (,$(filter noipv6,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_IPV6
COPTS += -DNO_IPV6
endif
ifneq (,$(filter notftp,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_TFTP
COPTS += -DNO_TFTP
endif
ifneq (,$(filter nodhcp,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_DHCP
COPTS += -DNO_DHCP
endif
ifneq (,$(filter noscript,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DNO_SCRIPT
COPTS += -DNO_SCRIPT
endif
ifneq (,$(filter nortc,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_BROKEN_RTC
COPTS += -DHAVE_BROKEN_RTC
endif
ifneq (,$(filter noi18n,$(DEB_BUILD_OPTIONS)))
TARGET = install
ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
COPTS += -DHAVE_IDN
endif
endif
ifneq (,$(filter uselua,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_LUASCRIPT
COPTS += -DHAVE_LUASCRIPT
endif
ifeq (,$(filter nodnssec,$(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_DNSSEC
endif
ifeq ($(DEB_HOST_ARCH_OS),kfreebsd)
# For strlcpy in FreeBSD
LIBS += $(shell ${PKG_CONFIG} --libs libbsd-overlay)
CFLAGS += $(shell ${PKG_CONFIG} --cflags libbsd-overlay)
endif
define build_tree
rm -rf $1
install -m 755 \
-d $1/DEBIAN \
-d $1/etc/dbus-1/system.d \
-d $1/usr/share/doc/$(package) \
-d $1/usr/share/doc/$(package)/examples \
-d $1/usr/share/$(package) \
-d $1/var/lib/misc
endef
define add_docs
# Need to remove paypal links in Debian Package for policy reasons.
sed -e /\<H2\>Donations/Q -e /icon.png/d doc.html -e /favicon.ico/d >$1/usr/share/doc/$(package)/doc.html
echo "</BODY>" >>$1/usr/share/doc/$(package)/doc.html
install -m 644 setup.html $1/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example $1/usr/share/doc/$(package)/examples/.
install -m 644 FAQ $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG $1/usr/share/doc/$(package)/changelog
gzip -9n $1/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG.archive $1/usr/share/doc/$(package)/changelog.archive
gzip -9n $1/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/DBus-interface
install -m 644 debian/systemd_howto $1/usr/share/doc/$(package)/.
gzip -9n $1/usr/share/doc/$(package)/systemd_howto
gzip -9n $1/usr/share/man/man8/dnsmasq.8
for f in $1/usr/share/man/*; do \
if [ -f $$f/man8/dnsmasq.8 ]; then \
gzip -9n $$f/man8/dnsmasq.8 ; \
fi \
done
endef
define add_files
install -m 644 trust-anchors.conf $1/usr/share/$(package)/.
install -m 644 debian/dnsmasq-base.conffiles $1/DEBIAN/conffiles
install -m 755 debian/dnsmasq-base.postinst $1/DEBIAN/postinst
install -m 755 debian/dnsmasq-base.postrm $1/DEBIAN/postrm
install -m 644 debian/changelog $1/usr/share/doc/$(package)/changelog.Debian
gzip -9n $1/usr/share/doc/$(package)/changelog.Debian
install -m 644 debian/readme $1/usr/share/doc/$(package)/README.Debian
install -m 644 debian/copyright $1/usr/share/doc/$(package)/copyright
install -m 644 debian/dbus.conf $1/etc/dbus-1/system.d/dnsmasq.conf
endef
clean:
$(checkdir)
make BUILDDIR=debian/build/no-lua clean
make BUILDDIR=debian/build/lua clean
make -C contrib/lease-tools clean
rm -rf debian/build debian/trees debian/*~ debian/files debian/substvars debian/utils-substvars
rm -rf debian/daemon debian/base debian/utils debian/*~ debian/files debian/substvars debian/utils-substvars
make clean
make -C contrib/wrt clean
binary-indep: checkroot
$(checkdir)
rm -rf debian/trees/daemon
rm -rf debian/daemon
install -m 755 \
-d debian/trees/daemon/DEBIAN \
-d debian/trees/daemon/usr/share/doc/dnsmasq \
-d debian/trees/daemon/etc/init.d \
-d debian/trees/daemon/etc/dnsmasq.d \
-d debian/trees/daemon/etc/resolvconf/update.d \
-d debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/trees/daemon/usr/share/dnsmasq \
-d debian/trees/daemon/usr/share/doc/dnsmasq \
-d debian/trees/daemon/etc/default \
-d debian/trees/daemon/lib/systemd/system \
-d debian/trees/daemon/usr/lib/tmpfiles.d \
-d debian/trees/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/trees/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/preinst debian/prerm debian/trees/daemon/DEBIAN
if ! dpkg-vendor --derives-from Ubuntu; then \
rm -f debian/dnsmasq.postinst.debhelper debian/dnsmasq.postrm.debhelper; \
dh_runit -pdnsmasq -Pdebian/trees/daemon; \
cat debian/dnsmasq.postinst.debhelper >> debian/trees/daemon/DEBIAN/postinst; \
cat debian/dnsmasq.postrm.debhelper >> debian/trees/daemon/DEBIAN/postrm; \
cd debian/trees/daemon && find etc/sv -type f -printf '/%p\n' >>DEBIAN/conffiles; \
fi
install -m 755 debian/init debian/trees/daemon/etc/init.d/dnsmasq
install -m 755 debian/resolvconf debian/trees/daemon/etc/resolvconf/update.d/dnsmasq
install -m 755 debian/resolvconf-package debian/trees/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
install -m 644 debian/installed-marker debian/trees/daemon/usr/share/dnsmasq
install -m 644 debian/default debian/trees/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/trees/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/trees/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/trees/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/systemd@.service debian/trees/daemon/lib/systemd/system/dnsmasq@.service
install -m 644 debian/tmpfiles.conf debian/trees/daemon/usr/lib/tmpfiles.d/dnsmasq.conf
install -m 644 debian/insserv debian/trees/daemon/etc/insserv.conf.d/dnsmasq
install -m 644 debian/copyright debian/trees/daemon/usr/share/doc/dnsmasq/copyright
install -m 644 debian/changelog debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
gzip -9n debian/trees/daemon/usr/share/doc/dnsmasq/changelog.Debian
cd debian/trees/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/dnsmasq.substvars -pdnsmasq -Pdebian/trees/daemon
find debian/trees/daemon -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/daemon
chmod -R g-ws debian/trees/daemon
dpkg --build debian/trees/daemon ..
-d debian/daemon/DEBIAN \
-d debian/daemon/usr/share/doc \
-d debian/daemon/etc/init.d \
-d debian/daemon/etc/dnsmasq.d \
-d debian/daemon/etc/resolvconf/update.d \
-d debian/daemon/usr/lib/resolvconf/dpkg-event.d \
-d debian/daemon/etc/default \
-d debian/daemon/lib/systemd/system \
-d debian/daemon/etc/insserv.conf.d
install -m 644 debian/conffiles debian/daemon/DEBIAN
install -m 755 debian/postinst debian/postrm debian/prerm debian/daemon/DEBIAN
install -m 755 debian/init debian/daemon/etc/init.d/dnsmasq
install -m 755 debian/resolvconf debian/daemon/etc/resolvconf/update.d/dnsmasq
install -m 755 debian/resolvconf-package debian/daemon/usr/lib/resolvconf/dpkg-event.d/dnsmasq
install -m 644 debian/default debian/daemon/etc/default/dnsmasq
install -m 644 dnsmasq.conf.example debian/daemon/etc/dnsmasq.conf
install -m 644 debian/readme.dnsmasq.d debian/daemon/etc/dnsmasq.d/README
install -m 644 debian/systemd.service debian/daemon/lib/systemd/system/dnsmasq.service
install -m 644 debian/insserv debian/daemon/etc/insserv.conf.d/dnsmasq
ln -s $(package) debian/daemon/usr/share/doc/dnsmasq
cd debian/daemon && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-gencontrol -pdnsmasq -Pdebian/daemon
chown -R root.root debian/daemon
chmod -R g-ws debian/daemon
dpkg --build debian/daemon ..
binary-arch: checkroot
$(call build_tree,debian/trees/base)
make $(TARGET) BUILDDIR=debian/build/no-lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
$(call add_docs,debian/trees/base)
else
rm -rf debian/trees/base/usr/share/man
$(checkdir)
rm -rf debian/base
install -m 755 \
-d debian/base/DEBIAN \
-d debian/base/etc/dbus-1/system.d \
-d debian/base/usr/share/doc/$(package) \
-d debian/base/usr/share/doc/$(package)/examples \
-d debian/base/var/run \
-d debian/base/var/lib/misc
make $(TARGET) PREFIX=/usr DESTDIR=`pwd`/debian/base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(COPTS)" CC=gcc
ifeq (,$(findstring nodocs,$(DEB_BUILD_OPTIONS)))
install -m 644 doc.html debian/base/usr/share/doc/$(package)/.
install -m 644 setup.html debian/base/usr/share/doc/$(package)/.
install -m 644 dnsmasq.conf.example debian/base/usr/share/doc/$(package)/examples/.
install -m 644 FAQ debian/base/usr/share/doc/$(package)/.
gzip -9 debian/base/usr/share/doc/$(package)/FAQ
install -m 644 CHANGELOG debian/base/usr/share/doc/$(package)/changelog
gzip -9 debian/base/usr/share/doc/$(package)/changelog
install -m 644 CHANGELOG.archive debian/base/usr/share/doc/$(package)/changelog.archive
gzip -9 debian/base/usr/share/doc/$(package)/changelog.archive
install -m 644 dbus/DBus-interface debian/base/usr/share/doc/$(package)/.
gzip -9 debian/base/usr/share/doc/$(package)/DBus-interface
endif
$(call add_files,debian/trees/base)
install -m 644 debian/dnsmasq-base.conffiles debian/base/DEBIAN/conffiles
install -m 755 debian/dnsmasq-base.postinst debian/base/DEBIAN/postinst
install -m 755 debian/dnsmasq-base.postrm debian/base/DEBIAN/postrm
install -m 644 debian/changelog debian/base/usr/share/doc/$(package)/changelog.Debian
gzip -9 debian/base/usr/share/doc/$(package)/changelog.Debian
install -m 644 debian/readme debian/base/usr/share/doc/$(package)/README.Debian
install -m 644 debian/copyright debian/base/usr/share/doc/$(package)/copyright
install -m 644 debian/dbus.conf debian/base/etc/dbus-1/system.d/dnsmasq.conf
gzip -9 debian/base/usr/share/man/man8/dnsmasq.8
for f in debian/base/usr/share/man/*; do \
if [ -f $$f/man8/dnsmasq.8 ]; then \
gzip -9 $$f/man8/dnsmasq.8 ; \
fi \
done
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/base/usr/sbin/dnsmasq
strip -R .note -R .comment debian/base/usr/sbin/dnsmasq
endif
cd debian/trees/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/trees/base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base -Pdebian/trees/base
find debian/trees/base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/base
chmod -R g-ws debian/trees/base
dpkg --build debian/trees/base ..
cd debian/base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps debian/base/usr/sbin/dnsmasq
dpkg-gencontrol -pdnsmasq-base -Pdebian/base
chown -R root.root debian/base
chmod -R g-ws debian/base
dpkg --build debian/base ..
$(call build_tree,debian/trees/lua-base)
make $(TARGET) BUILDDIR=debian/build/lua PREFIX=/usr DESTDIR=`pwd`/debian/trees/lua-base CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="-DHAVE_LUASCRIPT $(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
$(call add_docs,debian/trees/lua-base)
else
rm -rf debian/trees/lua-base/usr/share/man
endif
$(call add_files,debian/trees/lua-base)
install -m 755 -d debian/trees/lua-base/usr/share/lintian/overrides
install -m 644 debian/lintian-override debian/trees/lua-base/usr/share/lintian/overrides/dnsmasq-base-lua
ifeq ($(DEB_BUILD_ARCH_OS),linux)
rm -rf debian/utils
install -m 755 -d debian/utils/DEBIAN \
-d debian/utils/usr/share/man/man1 \
-d debian/utils/usr/bin \
-d debian/utils/usr/share/doc/dnsmasq-utils
make -C contrib/wrt PREFIX=/usr DESTDIR=`pwd`/debian/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(COPTS)" CC=gcc
install -m 755 contrib/wrt/dhcp_release debian/utils/usr/bin/dhcp_release
install -m 644 contrib/wrt/dhcp_release.1 debian/utils/usr/share/man/man1/dhcp_release.1
gzip -9 debian/utils/usr/share/man/man1/dhcp_release.1
install -m 755 contrib/wrt/dhcp_lease_time debian/utils/usr/bin/dhcp_lease_time
install -m 644 contrib/wrt/dhcp_lease_time.1 debian/utils/usr/share/man/man1/dhcp_lease_time.1
install -m 644 debian/copyright debian/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9 debian/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9 debian/utils/usr/share/man/man1/dhcp_lease_time.1
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/lua-base/usr/sbin/dnsmasq
endif
ln -s $(package) debian/trees/lua-base/usr/share/doc/dnsmasq-base-lua
cd debian/trees/lua-base && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps --warnings=1 debian/trees/lua-base/usr/sbin/dnsmasq
dpkg-gencontrol $(PACKAGE_VERSION) -pdnsmasq-base-lua -Pdebian/trees/lua-base
find debian/trees/lua-base -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/lua-base
chmod -R g-ws debian/trees/lua-base
dpkg --build debian/trees/lua-base ..
ifeq ($(DEB_HOST_ARCH_OS),linux)
rm -rf debian/trees/utils
install -m 755 -d debian/trees/utils/DEBIAN \
-d debian/trees/utils/usr/bin \
-d debian/trees/utils/usr/share/doc/dnsmasq-utils
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
install -m 755 -d debian/trees/utils/usr/share/man/man1
endif
make -C contrib/lease-tools PREFIX=/usr DESTDIR=`pwd`/debian/trees/utils CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" COPTS="$(DEB_COPTS)" CC=$(CC) PKG_CONFIG=$(PKG_CONFIG) LIBS="$(LIBS)"
install -m 755 contrib/lease-tools/dhcp_release debian/trees/utils/usr/bin/dhcp_release
install -m 755 contrib/lease-tools/dhcp_release6 debian/trees/utils/usr/bin/dhcp_release6
install -m 755 contrib/lease-tools/dhcp_lease_time debian/trees/utils/usr/bin/dhcp_lease_time
ifeq (,$(findstring nodoc,$(DEB_BUILD_OPTIONS)))
install -m 644 contrib/lease-tools/dhcp_release.1 debian/trees/utils/usr/share/man/man1/dhcp_release.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release.1
install -m 644 contrib/lease-tools/dhcp_release6.1 debian/trees/utils/usr/share/man/man1/dhcp_release6.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_release6.1
install -m 644 contrib/lease-tools/dhcp_lease_time.1 debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
gzip -9n debian/trees/utils/usr/share/man/man1/dhcp_lease_time.1
endif
install -m 644 debian/copyright debian/trees/utils/usr/share/doc/dnsmasq-utils/copyright
install -m 644 debian/changelog debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
gzip -9n debian/trees/utils/usr/share/doc/dnsmasq-utils/changelog.Debian
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_release6
$(DEB_HOST_GNU_TYPE)-strip -R .note -R .comment debian/trees/utils/usr/bin/dhcp_lease_time
strip -R .note -R .comment debian/utils/usr/bin/dhcp_release
strip -R .note -R .comment debian/utils/usr/bin/dhcp_lease_time
endif
cd debian/trees/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | LC_ALL=C sort -z | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/trees/utils/usr/bin/dhcp_release debian/trees/utils/usr/bin/dhcp_release6 debian/trees/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol $(PACKAGE_VERSION) -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/trees/utils
find debian/trees/utils -depth -newermt '$(BUILD_DATE)' -print0 | xargs -0r touch --no-dereference --date='$(BUILD_DATE)'
chown -R root.root debian/trees/utils
chmod -R g-ws debian/trees/utils
dpkg --build debian/trees/utils ..
cd debian/utils && find . -type f ! -regex '.*DEBIAN/.*' -printf '%P\0' | xargs -r0 md5sum > DEBIAN/md5sums
dpkg-shlibdeps -Tdebian/utils-substvars debian/utils/usr/bin/dhcp_release debian/utils/usr/bin/dhcp_lease_time
dpkg-gencontrol -Tdebian/utils-substvars -pdnsmasq-utils -Pdebian/utils
chown -R root.root debian/utils
chmod -R g-ws debian/utils
dpkg --build debian/utils ..
endif
define checkdir

View File

@@ -1,26 +1,28 @@
[Unit]
Description=dnsmasq - A lightweight DHCP and caching DNS server
Requires=network.target
Wants=nss-lookup.target
Before=nss-lookup.target
After=network.target
Description=A lightweight DHCP and caching DNS server
[Service]
Type=forking
PIDFile=/run/dnsmasq/dnsmasq.pid
Type=dbus
BusName=uk.org.thekelleys.dnsmasq
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/etc/init.d/dnsmasq checkconfig
ExecStartPre=/usr/sbin/dnsmasq --test
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
# wrapper picking up extra configuration files and then execs dnsmasq
# itself, when called with the "systemd-exec" function.
#
# It also adds the command-line flags
# --keep-in-foreground --pid-file --enable-dbus
# to disable writing a pid-file (not needed with systemd) and
# enable DBus by default because we use DBus activation.
#
ExecStart=/etc/init.d/dnsmasq systemd-exec
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called like
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start).
# resolvconf to work with the dnsmasq DNS server. They're called liek
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start.
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf
ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf

View File

@@ -1,31 +0,0 @@
[Unit]
Description=dnsmasq (%i) - A lightweight DHCP and caching DNS server
Requires=network.target
Wants=nss-lookup.target
Before=nss-lookup.target
After=network.target
[Service]
Type=forking
PIDFile=/run/dnsmasq/dnsmasq.%i.pid
# Test the config file and refuse starting if it is not valid.
ExecStartPre=/etc/init.d/dnsmasq checkconfig "%i"
# We run dnsmasq via the /etc/init.d/dnsmasq script which acts as a
# wrapper picking up extra configuration files and then execs dnsmasq
# itself, when called with the "systemd-exec" function.
ExecStart=/etc/init.d/dnsmasq systemd-exec "%i"
# The systemd-*-resolvconf functions configure (and deconfigure)
# resolvconf to work with the dnsmasq DNS server. They're called like
# this to get correct error handling (ie don't start-resolvconf if the
# dnsmasq daemon fails to start).
ExecStartPost=/etc/init.d/dnsmasq systemd-start-resolvconf "%i"
ExecStop=/etc/init.d/dnsmasq systemd-stop-resolvconf "%i"
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target

41
debian/systemd_howto vendored
View File

@@ -1,41 +0,0 @@
HOWTO
=====
dnsmasq comes with the possibility to run multiple systemd service instances on the same machine.
There is the main service which is enabled by default via `systemctl enable dnsmasq.service` and uses the configuration from `/etc/default/dnsmasq`.
Additional service instances can be enabled via `systemctl enable dnsmasq@<instance name>.service` that use the configuration from `/etc/default/dnsmasq.<instance name>`.
It is recommended to use a separate configuration file and directory for each instance.
Additionally make sure that all instances use either different ports and/or ip addresses to avoid binding collisions.
Example setup for an instance called "alt"
#1 File `/etc/dnsmasq.alt.conf` copied from `/etc/dnsmasq.conf`
#2 Directory `/etc/dnsmasq.alt.d`
#3 File `/etc/default/dnsmasq.alt` copied from `/etc/default/dnsmasq` with following adaptions:
* The options DNSMASQ_OPTS and CONFIG_DIR point to the correct configuration file and directory.
DNSMASQ_OPTS="... --conf-file=/etc/dnsmasq.alt.conf ..."
CONFIG_DIR=/etc/dnsmasq.alt.d,.dpkg-dist,.dpkg-old,.dpkg-new
* The option DNSMASQ_EXCEPT must contain "lo" to avoid that an instance becomes the machine's DNS resolver.
DNSMASQ_EXCEPT="lo"
* If the additional instance should bind to all IP addresses of a specific interface, e.g. "dnsalt01", then the following addition could be used:
DNSMASQ_OPTS="... --bind-dynamic --interface=dnsalt01 ..."
Additionally the main instance must be stopped from binding to interfaces that are used by other instances:
DNSMASQ_OPTS="... --bind-dynamic --except-interface=dnsalt* ..."
* If the additional instance should not use the machine's DNS resolver, normally that's the dnsmasq main instance, as upstream server, then the following addition could be used:
IGNORE_RESOLVCONF=yes
#4 Enable additional instance via `systemctl enable dnsmasq@alt.service`
#5 Start additional instance without reboot via `systemctl start dnsmasq@alt.service`
TODO
====
#1 - Found shortcoming on 2019-03-10
Only the option DNSMASQ_EXCEPT="lo" avoids that an DNS instance will be set as the machine's DNS resolver.
This may interfere with the wish to run an additional instance on a different port on the localhost addresses.
My suggestion in the initial Debian report [1] was to specify an explicit variable for this.
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914305#5
#2 - Preferred configuration way
Should the variables DNSMASQ_INTERFACE and DNSMASQ_EXCEPT be used instead of --interface and --except-interface? (while "lo" still has to be in DNSMASQ_EXCEPT as of now)

View File

@@ -1 +0,0 @@
d /run/dnsmasq 755 dnsmasq nogroup

View File

@@ -20,18 +20,6 @@
# Never forward addresses in the non-routed address spaces.
#bogus-priv
# Uncomment these to enable DNSSEC validation and caching:
# (Requires dnsmasq to be built with DNSSEC option.)
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
#dnssec
# Replies which are not DNSSEC signed may be legitimate, because the domain
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
# check that an unsigned reply is OK, by finding a secure proof that a DS
# record somewhere between the root and the domain does not exist.
# The cost of setting this is that even queries in unsigned domains will need
# one or more extra DNS queries to verify.
#dnssec-check-unsigned
# Uncomment this to filter useless windows-originated DNS requests
# which can trigger dial-on-demand links needlessly.
@@ -81,26 +69,12 @@
# --address (and --server) work with IPv6 addresses too.
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
# Add the IPs of all queries to yahoo.com, google.com, and their
# subdomains to the vpn and search ipsets:
#ipset=/yahoo.com/google.com/vpn,search
# Add the IPs of all queries to yahoo.com, google.com, and their
# subdomains to netfilters sets, which is equivalent to
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
# Use netfilters sets for both IPv4 and IPv6:
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
#nftset=/yahoo.com/4#ip#test#vpn4
#nftset=/yahoo.com/6#ip#test#vpn6
# 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
# and this sets the source (ie local) address used to talk to
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that
# IP on the machine, obviously).
# server=10.1.2.3@192.168.1.1#55
@@ -199,7 +173,7 @@
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
# hosts. Use the DHCPv4 lease to derive the name, network segment and
# MAC address and assume that the host will also have an
# IPv6 address calculated using the SLAAC algorithm.
# IPv6 address calculated using the SLAAC alogrithm.
#dhcp-range=1234::, ra-names
# Do Router Advertisements, BUT NOT DHCP for this subnet.
@@ -220,7 +194,7 @@
#dhcp-range=1234::, ra-stateless, ra-names
# Do router advertisements for all subnets where we're doing DHCPv6
# Unless overridden by ra-stateless, ra-names, et al, the router
# Unless overriden by ra-stateless, ra-names, et al, the router
# advertisements will have the M and O bits set, so that the clients
# get addresses and configuration from DHCPv6, and the A bit reset, so the
# clients don't use SLAAC addresses.
@@ -261,13 +235,6 @@
# the IP address 192.168.0.60
#dhcp-host=id:01:02:02:04,192.168.0.60
# Always give the InfiniBand interface with hardware address
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
# ip address 192.168.0.61. The client id is derived from the prefix
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
# hex digits of the hardware address.
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
# Always give the host with client identifier "marjorie"
# the IP address 192.168.0.60
#dhcp-host=id:marjorie,192.168.0.60
@@ -298,7 +265,7 @@
# Give a fixed IPv6 address and name to client with
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
# Note also that the [] around the IPv6 address are obligatory.
# Note also the they [] around the IPv6 address are obilgatory.
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
# Ignore any clients which are not specified in dhcp-host lines
@@ -362,14 +329,6 @@
# Ask client to poll for option changes every six hours. (RFC4242)
#dhcp-option=option6:information-refresh-time,6h
# Set option 58 client renewal time (T1). Defaults to half of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T1,1m
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
# lease time if not specified. (RFC2132)
#dhcp-option=option:T2,2m
# Set the NTP time server address to be the same machine as
# is running dnsmasq
#dhcp-option=42,0.0.0.0
@@ -446,22 +405,22 @@
#dhcp-option-force=211,30i
# Set the boot filename for netboot/PXE. You will only need
# this if you want to boot machines over the network and you will need
# a TFTP server; either dnsmasq's built-in TFTP server or an
# 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 iPXE. The idea is to send two different
# filenames, the first loads iPXE, and the second tells iPXE what to
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
#dhcp-boot=undionly.kpxe
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
# 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 iPXE. All the options are
# 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
@@ -511,9 +470,6 @@
# Set the root directory for files available via FTP.
#tftp-root=/var/ftpd
# Do not abort if the tftp-root is unavailable
#tftp-no-fail
# 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
@@ -535,7 +491,7 @@
# (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 fashion. This facility can be used to
# 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
@@ -557,14 +513,6 @@
# http://www.isc.org/files/auth.html
#dhcp-authoritative
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
# option with a DHCPACK including a Rapid Commit option and fully committed address
# and configuration information. This must only be enabled if either the server is
# the only server for the subnet, or multiple servers are present and they each
# commit a binding for all clients.
#dhcp-rapid-commit
# Run an executable when a DHCP lease is created or destroyed.
# The arguments sent to the script are "add" or "del",
# then the MAC address, the IP address and finally the hostname
@@ -676,14 +624,3 @@
# Include another lot of configuration options.
#conf-file=/etc/dnsmasq.more.conf
#conf-dir=/etc/dnsmasq.d
# Include all the files in a directory except those ending in .bak
#conf-dir=/etc/dnsmasq.d,.bak
# Include all files in a directory which end in .conf
#conf-dir=/etc/dnsmasq.d/,*.conf
# If a DHCP client claims that its name is "wpad", ignore that.
# This fixes a security hole. see CERT Vulnerability VU#598349
#dhcp-name-match=set:wpad-ignore,wpad
#dhcp-ignore-names=tag:wpad-ignore

137
doc.html
View File

@@ -1,7 +1,8 @@
<HTML>
<HEAD>
<TITLE> Dnsmasq - network services for small networks.</TITLE>
<link rel="icon" href="http://www.thekelleys.org.uk/dnsmasq/images/favicon.ico">
<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">
<table width="100%" border="0" cellpadding="0" cellspacing="0">
@@ -10,48 +11,82 @@
<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 provides network infrastructure for small networks: DNS, DHCP, router advertisement and network boot. It is designed to be
lightweight and have a small footprint, suitable for resource constrained routers and firewalls. It has also been widely used
for tethering on smartphones and portable hotspots, and to support virtual networking in virtualisation frameworks.
Supported platforms include Linux (with glibc and uclibc), Android, *BSD, and Mac OS X. Dnsmasq is included in most
Linux distributions and the ports systems of FreeBSD, OpenBSD and NetBSD. Dnsmasq provides full IPv6 support.
Dnsmasq is a lightweight, easy to configure DNS forwarder and DHCP
server. It is designed to provide DNS and, optionally, DHCP, to a
small network. It can serve the names of local machines which are
not in the global DNS. The DHCP server integrates with the DNS
server and allows machines with DHCP-allocated addresses
to appear in the DNS with names configured either in each host or
in a central configuration file. Dnsmasq supports static and dynamic
DHCP leases and BOOTP/TFTP/PXE for network booting of diskless machines.
<P>
The DNS subsystem provides a local DNS server for the network, with forwarding of all query types to upstream recursive DNS servers and
caching of common record types (A, AAAA, CNAME and PTR, also DNSKEY and DS when DNSSEC is enabled).
<DIR>
<LI>Local DNS names can be defined by reading /etc/hosts, by importing names from the DHCP subsystem, or by configuration of a wide range of useful record types.</LI>
<LI>Upstream servers can be configured in a variety of convenient ways, including dynamic configuration as these change on moving upstream network.
<LI>Authoritative DNS mode allows local DNS names may be exported to zone in the global DNS. Dnsmasq acts as authoritative server for this zone, and also provides
zone transfer to secondaries for the zone, if required.</LI>
<LI>DNSSEC validation may be performed on DNS replies from upstream nameservers, providing security against spoofing and cache poisoning.</LI>
<LI>Specified sub-domains can be directed to their own upstream DNS servers, making VPN configuration easy.</LI>
<LI>Internationalised domain names are supported.
</DIR>
Dnsmasq is targeted at home networks using NAT and
connected to the internet via a modem, cable-modem or ADSL
connection but would be a good choice for any smallish network (up to
1000 clients is known to work) where low
resource use and ease of configuration are important.
<P>
The DHCP subsystem supports DHCPv4, DHCPv6, BOOTP and PXE.
Supported platforms include Linux (with glibc and uclibc), Android, *BSD,
Solaris and Mac OS X.
Dnsmasq is included in at least the following Linux distributions:
Gentoo, Debian, Slackware, Suse, Fedora,
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, fli4l,
CoyoteLinux, Endian Firewall and
Clarkconnect. It is also available as FreeBSD, OpenBSD and NetBSD ports and is used in
Linksys wireless routers (dd-wrt, openwrt and the stock firmware) and the m0n0wall project.
<P>
Dnsmasq provides the following features:
<DIR>
<LI> Both static and dynamic DHCP leases are supported, along with stateless mode in DHCPv6.</LI>
<LI> The PXE system is a full PXE server, supporting netboot menus and multiple architecture support. It
includes proxy-mode, where the PXE system co-operates with another DHCP server.</LI>
<LI> There is a built in read-only TFTP server to support netboot.</LI>
<LI> Machines which are configured by DHCP have their names automatically
<LI>
The DNS configuration of machines behind the firewall is simple and
doesn't depend on the details of the ISP's dns servers
<LI>
Clients which try to do DNS lookups while a modem link to the
internet is down will time out immediately.
</LI>
<LI>
Dnsmasq will serve names from the /etc/hosts file on the firewall
machine: If the names of local machines are there, then they can all
be addressed without having to maintain /etc/hosts on each machine.
</LI>
<LI>
The integrated DHCP server supports static and dynamic DHCP leases and
multiple networks and IP ranges. It works across BOOTP relays and
supports DHCP options including RFC3397 DNS search lists.
Machines which are configured by DHCP have their names automatically
included in the DNS and the names can specified by each machine or
centrally by associating a name with a MAC address or UID in the dnsmasq
configuration file.</LI>
centrally by associating a name with a MAC address in the dnsmasq
config file.
</LI>
<LI>
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
mappings (PTR records), reducing the load on upstream servers and
improving performance (especially on modem connections).
</LI>
<LI>
Dnsmasq can be configured to automatically pick up the addresses of
its upstream nameservers from ppp or dhcp configuration. It will
automatically reload this information if it changes. This facility
will be of particular interest to maintainers of Linux firewall
distributions since it allows dns configuration to be made automatic.
</LI>
<LI>
On IPv6-enabled boxes, dnsmasq can both talk to upstream servers via IPv6
and offer DNS service via IPv6. On dual-stack (IPv4 and IPv6) boxes it talks
both protocols and can even act as IPv6-to-IPv4 or IPv4-to-IPv6 forwarder.
</LI>
<LI>
Dnsmasq can be configured to send queries for certain domains to
upstream servers handling only those domains. This makes integration
with private DNS systems easy.
</LI>
<LI>
Dnsmasq supports MX and SRV records and can be configured to return MX records
for any or all local machines.
</LI>
</DIR>
<P>
The Router Advertisement subsystem provides basic autoconfiguration for IPv6 hosts. It can be used stand-alone or in conjunction with DHCPv6.
<DIR>
<LI> The M and O bits are configurable, to control hosts' use of DHCPv6.</LI>
<LI> Router advertisements can include the RDNSS option.</LI>
<LI> There is a mode which uses name information from DHCPv4 configuration to provide DNS entries
for autoconfigured IPv6 addresses which would otherwise be anonymous.</LI>
</DIR>
<P>
For extra compactness, unused features may be omitted at compile time.
<H2>Get code.</H2>
@@ -66,36 +101,16 @@ the repo, or get a copy using git protocol with the command
<PRE><TT>git clone git://thekelleys.org.uk/dnsmasq.git </TT></PRE>
or
<PRE><TT>git clone http://thekelleys.org.uk/git/dnsmasq.git </TT></PRE>
<H2>License.</H2>
Dnsmasq is distributed under the GPL, version 2 or version 3 at your discretion. See the files COPYING and COPYING-v3 in the distribution
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
for details.
<H2>Contact.</H2>
There is a dnsmasq mailing list at <A
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
first location for queries, bugreports, suggestions etc. The list is mirrored, with a
search facility, at <A HREF="https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/">
https://www.mail-archive.com/dnsmasq-discuss@lists.thekelleys.org.uk/</A>.
You can contact me at <A
first location for queries, bugreports, suggestions etc.
Dnsmasq was written by Simon Kelley. You can contact me at <A
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
<H2>Donations.</H2>
Dnsmasq is mainly written and maintained by Simon Kelley. For most of its life, dnsmasq has been a spare-time project.
These days I'm working on it as my main activity.
I don't have an employer or anyone who pays me regularly to work on dnsmasq. If you'd like to make
a contribution towards my expenses, please use the donation button below.
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="V3X9GVW5GX6DA">
<input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal The safer, easier way to pay online.">
<img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1" height="1">
</form>
</BODY>

File diff suppressed because it is too large Load Diff

View File

@@ -478,8 +478,7 @@ la traza reversa direcci
.TP
.B \-c, --cache-size=<tamaño de caché>
Fijar el tamaño del caché de dnsmasq. El predeterminado es 150 nombres.
Fijar el tamaño a cero deshabilita el caché. Nota: el gran tamaño de
caché afecta el rendimiento.
Fijar el tamaño a cero deshabilita el caché.
.TP
.B \-N, --no-negcache
Deshabilitar caché negativo. El caché negativo le permite a dnsmasq
@@ -1063,14 +1062,10 @@ esta opci
cuando hay cambios hechos a el client-id y tiempos de arriendo y vencimiento.
.TP
.B --bridge-interface=<nombre de interface>,<alias>[,<alias>]
Tratar paquetes de pedidos DHCP (v4 y v6) y de IPv6 Router Solicit que
llegan a cualquiera de las interfaces <alias> como si hubieran llegado
a la interface <nombre de interface>. Esta opción permite que dnsmasq
puede proporcionar los servicios DHCP y RA a través de interfaces
ethernet sin dirección y sin puente; por ejemplo en un nodo de cálculo
de OpenStack, donde cada una de esas interfaces es una interfaz TAP
para una máquina virtual, o al usar bridging estilo viejo en
plataformas BSD.
Tratar paquetes de pedidos DHCP que llegan a cualquiera de las interfaces <alias>
como si hubieran llegado a la interface <nombre de interface>. Esta opción
es necesaria al usar bridging estilo viejo en plataformas BSD, dado a que
los paquetes llegan a interfaces tap que no tienen una dirección IP.
.TP
.B \-s, --domain=<dominio>[,<rango de IPs>]
Especifica los dominios DNS para el servidor DHCP. Dominios pueden ser

File diff suppressed because it is too large Load Diff

2133
po/de.po

File diff suppressed because it is too large Load Diff

2236
po/es.po

File diff suppressed because it is too large Load Diff

1849
po/fi.po

File diff suppressed because it is too large Load Diff

1995
po/fr.po

File diff suppressed because it is too large Load Diff

2093
po/id.po

File diff suppressed because it is too large Load Diff

1849
po/it.po

File diff suppressed because it is too large Load Diff

1942
po/no.po

File diff suppressed because it is too large Load Diff

2016
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1942
po/ro.po

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,7 @@ by modifying MODIFY_RESOLV_CONF_DYNAMICALLY="no" in <TT>/etc/sysconfig/network/c
<h3>Automatic DNS server configuration with DHCP.</h3>
You need to get your DHCP client to write the address(es) of the DNS
You need to get your DHCP client to write the addresse(s) of the DNS
servers to a file other than <TT>/etc/resolv.conf</TT>. For dhcpcd, the
<TT>dhcpcd.exe</TT> script gets run with the addresses of the nameserver(s) in
the shell variable <TT>$DNS</TT>. The following bit of shell script
@@ -86,8 +86,8 @@ uses that to write a file suitable for dnsmasq.
<PRE>
echo -n >|/etc/dhcpc/resolv.conf
dnsservers=${DNS//,/ }
for serv in $dnsservers; do
dnsservs=${DNS//,/ }
for serv in $dnsservs; do
echo "nameserver $serv" >>/etc/dhcpc/resolv.conf
done
@@ -125,7 +125,7 @@ address of its ethernet card. For the former to work, a machine needs to know it
requests a DHCP lease. For dhcpcd, the -h option specifies this. The
names may be anything as far as DHCP is concerned, but dnsmasq adds
some limitations. By default the names must no have a domain part, ie
they must just be alphanumeric names, without any dots. This is a
they must just be a alphanumeric name, without any dots. This is a
security feature to stop a machine on your network telling DHCP that
its name is "www.microsoft.com" and thereby grabbing traffic which
shouldn't go to it. A domain part is only allowed by dnsmasq in DHCP machine names
@@ -186,7 +186,7 @@ more than one nameserver just include as many
<H2>Local domains.</H2>
Sometimes people have local domains which they do not want forwarded
to upstream servers. This is accommodated by using server options
to upstream servers. This is accomodated by using server options
without the server IP address. To make things clearer <TT>local</TT>
is a synonym for <TT>server</TT>. For example the option
<TT>local=/localnet/</TT> ensures that any domain name query which ends in

232
src/arp.c
View File

@@ -1,232 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
/* Time between forced re-loads from kernel. */
#define INTERVAL 90
#define ARP_MARK 0
#define ARP_FOUND 1 /* Confirmed */
#define ARP_NEW 2 /* Newly created */
#define ARP_EMPTY 3 /* No MAC addr */
struct arp_record {
unsigned short hwlen, status;
int family;
unsigned char hwaddr[DHCP_CHADDR_MAX];
union all_addr addr;
struct arp_record *next;
};
static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
static time_t last = 0;
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
{
struct arp_record *arp;
(void)parmv;
if (maclen > DHCP_CHADDR_MAX)
return 1;
/* Look for existing entry */
for (arp = arps; arp; arp = arp->next)
{
if (family != arp->family || arp->status == ARP_NEW)
continue;
if (family == AF_INET)
{
if (arp->addr.addr4.s_addr != ((struct in_addr *)addrp)->s_addr)
continue;
}
else
{
if (!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, (struct in6_addr *)addrp))
continue;
}
if (arp->status == ARP_EMPTY)
{
/* existing address, was negative. */
arp->status = ARP_NEW;
arp->hwlen = maclen;
memcpy(arp->hwaddr, mac, maclen);
}
else if (arp->hwlen == maclen && memcmp(arp->hwaddr, mac, maclen) == 0)
/* Existing entry matches - confirm. */
arp->status = ARP_FOUND;
else
continue;
break;
}
if (!arp)
{
/* New entry */
if (freelist)
{
arp = freelist;
freelist = freelist->next;
}
else if (!(arp = whine_malloc(sizeof(struct arp_record))))
return 1;
arp->next = arps;
arps = arp;
arp->status = ARP_NEW;
arp->hwlen = maclen;
arp->family = family;
memcpy(arp->hwaddr, mac, maclen);
if (family == AF_INET)
arp->addr.addr4.s_addr = ((struct in_addr *)addrp)->s_addr;
else
memcpy(&arp->addr.addr6, addrp, IN6ADDRSZ);
}
return 1;
}
/* If in lazy mode, we cache absence of ARP entries. */
int find_mac(union mysockaddr *addr, unsigned char *mac, int lazy, time_t now)
{
struct arp_record *arp, *tmp, **up;
int updated = 0;
again:
/* If the database is less then INTERVAL old, look in there */
if (difftime(now, last) < INTERVAL)
{
/* addr == NULL -> just make cache up-to-date */
if (!addr)
return 0;
for (arp = arps; arp; arp = arp->next)
{
if (addr->sa.sa_family != arp->family)
continue;
if (arp->family == AF_INET &&
arp->addr.addr4.s_addr != addr->in.sin_addr.s_addr)
continue;
if (arp->family == AF_INET6 &&
!IN6_ARE_ADDR_EQUAL(&arp->addr.addr6, &addr->in6.sin6_addr))
continue;
/* Only accept positive entries unless in lazy mode. */
if (arp->status != ARP_EMPTY || lazy || updated)
{
if (mac && arp->hwlen != 0)
memcpy(mac, arp->hwaddr, arp->hwlen);
return arp->hwlen;
}
}
}
/* Not found, try the kernel */
if (!updated)
{
updated = 1;
last = now;
/* Mark all non-negative entries */
for (arp = arps; arp; arp = arp->next)
if (arp->status != ARP_EMPTY)
arp->status = ARP_MARK;
iface_enumerate(AF_UNSPEC, NULL, filter_mac);
/* Remove all unconfirmed entries to old list. */
for (arp = arps, up = &arps; arp; arp = tmp)
{
tmp = arp->next;
if (arp->status == ARP_MARK)
{
*up = arp->next;
arp->next = old;
old = arp;
}
else
up = &arp->next;
}
goto again;
}
/* record failure, so we don't consult the kernel each time
we're asked for this address */
if (freelist)
{
arp = freelist;
freelist = freelist->next;
}
else
arp = whine_malloc(sizeof(struct arp_record));
if (arp)
{
arp->next = arps;
arps = arp;
arp->status = ARP_EMPTY;
arp->family = addr->sa.sa_family;
arp->hwlen = 0;
if (addr->sa.sa_family == AF_INET)
arp->addr.addr4.s_addr = addr->in.sin_addr.s_addr;
else
memcpy(&arp->addr.addr6, &addr->in6.sin6_addr, IN6ADDRSZ);
}
return 0;
}
int do_arp_script_run(void)
{
struct arp_record *arp;
/* Notify any which went, then move to free list */
if (old)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_SCRIPT_ARP))
queue_arp(ACTION_ARP_DEL, old->hwaddr, old->hwlen, old->family, &old->addr);
#endif
arp = old;
old = arp->next;
arp->next = freelist;
freelist = arp;
return 1;
}
for (arp = arps; arp; arp = arp->next)
if (arp->status == ARP_NEW)
{
#ifdef HAVE_SCRIPT
if (option_bool(OPT_SCRIPT_ARP))
queue_arp(ACTION_ARP, arp->hwaddr, arp->hwlen, arp->family, &arp->addr);
#endif
arp->status = ARP_FOUND;
return 1;
}
return 0;
}

View File

@@ -1,900 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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_AUTH
static struct addrlist *find_addrlist(struct addrlist *list, int flag, union all_addr *addr_u)
{
do {
if (!(list->flags & ADDRLIST_IPV6))
{
struct in_addr netmask, addr = addr_u->addr4;
if (!(flag & F_IPV4))
continue;
netmask.s_addr = htonl(~(in_addr_t)0 << (32 - list->prefixlen));
if (is_same_net(addr, list->addr.addr4, netmask))
return list;
}
else if (is_same_net6(&(addr_u->addr6), &list->addr.addr6, list->prefixlen))
return list;
} while ((list = list->next));
return NULL;
}
static struct addrlist *find_subnet(struct auth_zone *zone, int flag, union all_addr *addr_u)
{
if (!zone->subnet)
return NULL;
return find_addrlist(zone->subnet, flag, addr_u);
}
static struct addrlist *find_exclude(struct auth_zone *zone, int flag, union all_addr *addr_u)
{
if (!zone->exclude)
return NULL;
return find_addrlist(zone->exclude, flag, addr_u);
}
static int filter_zone(struct auth_zone *zone, int flag, union all_addr *addr_u)
{
if (find_exclude(zone, flag, addr_u))
return 0;
/* No subnets specified, no filter */
if (!zone->subnet)
return 1;
return find_subnet(zone, flag, addr_u) != NULL;
}
int in_zone(struct auth_zone *zone, char *name, char **cut)
{
size_t namelen = strlen(name);
size_t domainlen = strlen(zone->domain);
if (cut)
*cut = NULL;
if (namelen >= domainlen &&
hostname_isequal(zone->domain, &name[namelen - domainlen]))
{
if (namelen == domainlen)
return 1;
if (name[namelen - domainlen - 1] == '.')
{
if (cut)
*cut = &name[namelen - domainlen - 1];
return 1;
}
}
return 0;
}
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
int local_query, int do_bit, int have_pseudoheader)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
int qtype, qclass, rc;
int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0;
struct crec *crecp;
int auth = !local_query, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0, out_of_zone = 0;
struct auth_zone *zone = NULL;
struct addrlist *subnet = NULL;
char *cut;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
struct interface_name *intr;
struct naptr *na;
union all_addr addr;
struct cname *a, *candidate;
unsigned int wclen;
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
/* determine end of question section (we put answers there) */
if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */
/* now process each question, answers go in RRs after the question */
p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--)
{
unsigned int flag = 0;
int found = 0;
int cname_wildcard = 0;
/* save pointer to name for copying into answers */
nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
if (qclass != C_IN)
{
auth = 0;
out_of_zone = 1;
continue;
}
if ((qtype == T_PTR || qtype == T_SOA || qtype == T_NS) &&
(flag = in_arpa_name_2_addr(name, &addr)) &&
!local_query)
{
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = find_subnet(zone, flag, &addr)))
break;
if (!zone)
{
out_of_zone = 1;
auth = 0;
continue;
}
else if (qtype == T_SOA)
soa = 1, found = 1;
else if (qtype == T_NS)
ns = 1, found = 1;
}
if (qtype == T_PTR && flag)
{
intr = NULL;
if (flag == F_IPV4)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (!(addrlist->flags & ADDRLIST_IPV6) && addr.addr4.s_addr == addrlist->addr.addr4.s_addr)
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
else if (flag == F_IPV6)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if ((addrlist->flags & ADDRLIST_IPV6) && IN6_ARE_ADDR_EQUAL(&addr.addr6, &addrlist->addr.addr6))
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
if (intr)
{
if (local_query || in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(flag | F_REVERSE | F_CONFIG, intr->name, &addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
anscount++;
}
}
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
do {
strcpy(name, cache_get_name(crecp));
if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
{
char *p = strchr(name, '.');
if (p)
*p = 0; /* must be bare name */
/* add external domain */
if (zone)
{
strcat(name, ".");
strcat(name, zone->domain);
}
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid), 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else if (crecp->flags & (F_DHCP | F_HOSTS) && (local_query || in_zone(zone, name, NULL)))
{
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid), 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else
continue;
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
if (!found && is_rev_synth(flag, &addr, name) && (local_query || in_zone(zone, name, NULL)))
{
log_query(F_CONFIG | F_REVERSE | flag, name, &addr, NULL, 0);
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
if (found)
nxdomain = 0;
else
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | (auth ? F_AUTH : 0), NULL, &addr, NULL, 0);
continue;
}
cname_restart:
if (found)
/* NS and SOA .arpa requests have set found above. */
cut = NULL;
else
{
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
{
out_of_zone = 1;
auth = 0;
continue;
}
}
for (rec = daemon->mxnames; rec; rec = rec->next)
if (!rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
{
nxdomain = 0;
if (rc == 2 && qtype == T_MX)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
anscount++;
}
}
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
if (rec->issrv && (rc = hostname_issubdomain(name, rec->name)))
{
nxdomain = 0;
if (rc == 2 && qtype == T_SRV)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
/* 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;
}
for (txt = daemon->rr; txt; txt = txt->next)
if ((rc = hostname_issubdomain(name, txt->name)))
{
nxdomain = 0;
if (rc == 2 && txt->class == qtype)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, NULL, txt->class);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && (rc = hostname_issubdomain(name, txt->name)))
{
nxdomain = 0;
if (rc == 2 && qtype == T_TXT)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (na = daemon->naptr; na; na = na->next)
if ((rc = hostname_issubdomain(name, na->name)))
{
nxdomain = 0;
if (rc == 2 && qtype == T_NAPTR)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>", 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
}
}
if (qtype == T_A)
flag = F_IPV4;
if (qtype == T_AAAA)
flag = F_IPV6;
for (intr = daemon->int_names; intr; intr = intr->next)
if ((rc = hostname_issubdomain(name, intr->name)))
{
struct addrlist *addrlist;
nxdomain = 0;
if (rc == 2 && flag)
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (((addrlist->flags & ADDRLIST_IPV6) ? T_AAAA : T_A) == qtype &&
(local_query || filter_zone(zone, flag, &addrlist->addr)))
{
if (addrlist->flags & ADDRLIST_REVONLY)
continue;
found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &addrlist->addr))
anscount++;
}
}
if (!found && is_name_synthetic(flag, name, &addr) )
{
nxdomain = 0;
log_query(F_FORWARD | F_CONFIG | flag, name, &addr, NULL, 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN, qtype == T_A ? "4" : "6", &addr))
anscount++;
}
if (!cut)
{
nxdomain = 0;
if (qtype == T_SOA)
{
auth = soa = 1; /* inhibits auth section */
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>", 0);
}
else if (qtype == T_AXFR)
{
struct iname *peers;
if (peer_addr->sa.sa_family == AF_INET)
peer_addr->in.sin_port = 0;
else
{
peer_addr->in6.sin6_port = 0;
peer_addr->in6.sin6_scope_id = 0;
}
for (peers = daemon->auth_peers; peers; peers = peers->next)
if (sockaddr_isequal(peer_addr, &peers->addr))
break;
/* Refuse all AXFR unless --auth-sec-servers or auth-peers is set */
if ((!daemon->secondary_forward_server && !daemon->auth_peers) ||
(daemon->auth_peers && !peers))
{
if (peer_addr->sa.sa_family == AF_INET)
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
else
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
return 0;
}
auth = 1;
soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1;
axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>", 0);
}
else if (qtype == T_NS)
{
auth = 1;
ns = 1; /* inhibits auth section */
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>", 0);
}
}
if (!option_bool(OPT_DHCP_FQDN) && cut)
{
*cut = 0; /* remove domain part */
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if (crecp->flags & F_DHCP)
do
{
nxdomain = 0;
if ((crecp->flags & flag) &&
(local_query || filter_zone(zone, flag, &(crecp->addr))))
{
*cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
*cut = 0; /* remove domain part */
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
*cut = '.'; /* restore domain part */
}
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
do
{
nxdomain = 0;
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
{
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
/* Only supply CNAME if no record for any type is known. */
if (nxdomain)
{
/* Check for possible wildcard match against *.domain
return length of match, to get longest.
Note that if return length of wildcard section, so
we match b.simon to _both_ *.simon and b.simon
but return a longer (better) match to b.simon.
*/
for (wclen = 0, candidate = NULL, a = daemon->cnames; a; a = a->next)
if (a->alias[0] == '*')
{
char *test = name;
while ((test = strchr(test+1, '.')))
{
if (hostname_isequal(test, &(a->alias[1])))
{
if (strlen(test) > wclen && !cname_wildcard)
{
wclen = strlen(test);
candidate = a;
cname_wildcard = 1;
}
break;
}
}
}
else if (hostname_isequal(a->alias, name) && strlen(a->alias) > wclen)
{
/* Simple case, no wildcard */
wclen = strlen(a->alias);
candidate = a;
}
if (candidate)
{
log_query(F_CONFIG | F_CNAME, name, NULL, NULL, 0);
strcpy(name, candidate->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, &nameoffset,
T_CNAME, C_IN, "d", name))
anscount++;
goto cname_restart;
}
else if (cache_find_non_terminal(name, now))
nxdomain = 0;
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL, 0);
}
}
/* Add auth section */
if (auth && zone)
{
char *authname;
int newoffset, offset = 0;
if (!subnet)
authname = zone->domain;
else
{
/* handle NS and SOA for PTR records */
authname = name;
if (!(subnet->flags & ADDRLIST_IPV6))
{
in_addr_t a = ntohl(subnet->addr.addr4.s_addr) >> 8;
char *p = name;
if (subnet->prefixlen >= 24)
p += sprintf(p, "%u.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%u.", a & 0xff);
a = a >> 8;
sprintf(p, "%u.in-addr.arpa", a & 0xff);
}
else
{
char *p = name;
int i;
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
{
int dig = ((unsigned char *)&subnet->addr.addr6)[i>>3];
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
}
sprintf(p, "ip6.arpa");
}
}
/* handle NS and SOA in auth section or for explicit queries */
newoffset = ansp - (unsigned char *)header;
if (((anscount == 0 && !ns) || soa) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
authname, daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{
offset = newoffset;
if (soa)
anscount++;
else
authcount++;
}
if (anscount != 0 || ns)
{
struct name_list *secondary;
/* Only include the machine running dnsmasq if it's acting as an auth server */
if (daemon->authinterface)
{
newoffset = ansp - (unsigned char *)header;
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
{
if (offset == 0)
offset = newoffset;
if (ns)
anscount++;
else
authcount++;
}
}
if (!subnet)
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
if (add_resource_record(header, limit, &trunc, offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
{
if (ns)
anscount++;
else
authcount++;
}
}
if (axfr)
{
for (rec = daemon->mxnames; rec; rec = rec->next)
if (in_zone(zone, rec->name, &cut))
{
if (cut)
*cut = 0;
if (rec->issrv)
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
else
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
anscount++;
}
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->rr; txt; txt = txt->next)
if (in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (na = daemon->naptr; na; na = na->next)
if (in_zone(zone, na->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (in_zone(zone, intr->name, &cut))
{
struct addrlist *addrlist;
if (cut)
*cut = 0;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if (!(addrlist->flags & ADDRLIST_IPV6) &&
(local_query || filter_zone(zone, F_IPV4, &addrlist->addr)) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
for (addrlist = intr->addr; addrlist; addrlist = addrlist->next)
if ((addrlist->flags & ADDRLIST_IPV6) &&
(local_query || filter_zone(zone, F_IPV6, &addrlist->addr)) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (a = daemon->cnames; a; a = a->next)
if (in_zone(zone, a->alias, &cut))
{
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL,
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
anscount++;
}
cache_enumerate(1);
while ((crecp = cache_enumerate(0)))
{
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
(crecp->flags & F_FORWARD))
{
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
{
char *cache_name = cache_get_name(crecp);
if (!strchr(cache_name, '.') &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
anscount++;
}
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
{
strcpy(name, cache_get_name(crecp));
if (in_zone(zone, name, &cut) &&
(local_query || filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr))))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, (crecp->flags & F_IPV6) ? T_AAAA : T_A, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
anscount++;
}
}
}
}
/* repeat SOA as last record */
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
anscount++;
}
}
/* done all questions, set up header and return length of result */
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
if (local_query)
{
/* set RA flag */
header->hb4 |= HB4_RA;
}
else
{
/* clear RA flag */
header->hb4 &= ~HB4_RA;
}
/* data is never DNSSEC signed. */
header->hb4 &= ~HB4_AD;
/* authoritative */
if (auth)
header->hb3 |= HB3_AA;
/* truncation */
if (trunc)
header->hb3 |= HB3_TC;
if ((auth || local_query) && nxdomain)
SET_RCODE(header, NXDOMAIN);
else
SET_RCODE(header, NOERROR); /* no error */
header->ancount = htons(anscount);
header->nscount = htons(authcount);
header->arcount = htons(0);
if (!local_query && out_of_zone)
{
SET_RCODE(header, REFUSED);
header->ancount = htons(0);
header->nscount = htons(0);
addr.log.rcode = REFUSED;
addr.log.ede = EDE_NOT_AUTH;
log_query(F_UPSTREAM | F_RCODE, "error", &addr, NULL, 0);
return resize_packet(header, ansp - (unsigned char *)header, NULL, 0);
}
/* Advertise our packet size limit in our reply */
if (have_pseudoheader)
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
return ansp - (unsigned char *)header;
}
#endif

View File

@@ -1,176 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
static struct blockdata *keyblock_free;
static unsigned int blockdata_count, blockdata_hwm, blockdata_alloced;
static void blockdata_expand(int n)
{
struct blockdata *new = whine_malloc(n * sizeof(struct blockdata));
if (new)
{
int i;
new[n-1].next = keyblock_free;
keyblock_free = new;
for (i = 0; i < n - 1; i++)
new[i].next = &new[i+1];
blockdata_alloced += n;
}
}
/* Preallocate some blocks, proportional to cachesize, to reduce heap fragmentation. */
void blockdata_init(void)
{
keyblock_free = NULL;
blockdata_alloced = 0;
blockdata_count = 0;
blockdata_hwm = 0;
/* Note that daemon->cachesize is enforced to have non-zero size if OPT_DNSSEC_VALID is set */
if (option_bool(OPT_DNSSEC_VALID))
blockdata_expand(daemon->cachesize);
}
void blockdata_report(void)
{
my_syslog(LOG_INFO, _("pool memory in use %zu, max %zu, allocated %zu"),
blockdata_count * sizeof(struct blockdata),
blockdata_hwm * sizeof(struct blockdata),
blockdata_alloced * sizeof(struct blockdata));
}
static struct blockdata *blockdata_alloc_real(int fd, char *data, size_t len)
{
struct blockdata *block, *ret = NULL;
struct blockdata **prev = &ret;
size_t blen;
while (len > 0)
{
if (!keyblock_free)
blockdata_expand(50);
if (keyblock_free)
{
block = keyblock_free;
keyblock_free = block->next;
blockdata_count++;
}
else
{
/* failed to alloc, free partial chain */
blockdata_free(ret);
return NULL;
}
if (blockdata_hwm < blockdata_count)
blockdata_hwm = blockdata_count;
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
if (data)
{
memcpy(block->key, data, blen);
data += blen;
}
else if (!read_write(fd, block->key, blen, 1))
{
/* failed read free partial chain */
blockdata_free(ret);
return NULL;
}
len -= blen;
*prev = block;
prev = &block->next;
block->next = NULL;
}
return ret;
}
struct blockdata *blockdata_alloc(char *data, size_t len)
{
return blockdata_alloc_real(0, data, len);
}
void blockdata_free(struct blockdata *blocks)
{
struct blockdata *tmp;
if (blocks)
{
for (tmp = blocks; tmp->next; tmp = tmp->next)
blockdata_count--;
tmp->next = keyblock_free;
keyblock_free = blocks;
blockdata_count--;
}
}
/* if data == NULL, return pointer to static block of sufficient size */
void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
{
size_t blen;
struct blockdata *b;
void *new, *d;
static unsigned int buff_len = 0;
static unsigned char *buff = NULL;
if (!data)
{
if (len > buff_len)
{
if (!(new = whine_malloc(len)))
return NULL;
if (buff)
free(buff);
buff = new;
}
data = buff;
}
for (d = data, b = block; len > 0 && b; b = b->next)
{
blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
memcpy(d, b->key, blen);
d += blen;
len -= blen;
}
return data;
}
void blockdata_write(struct blockdata *block, size_t len, int fd)
{
for (; len > 0 && block; block = block->next)
{
size_t blen = len > KEYBLOCK_LEN ? KEYBLOCK_LEN : len;
read_write(fd, block->key, blen, 0);
len -= blen;
}
}
struct blockdata *blockdata_read(int fd, size_t len)
{
return blockdata_alloc_real(fd, NULL, len);
}

187
src/bpf.c
View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,19 +19,12 @@
#if defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK)
#include <ifaddrs.h>
#include <sys/param.h>
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
#include <sys/param.h>
#include <sys/sysctl.h>
#endif
#include <net/if.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet/if_ether.h>
#if defined(__FreeBSD__)
# include <net/if_var.h>
#endif
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#ifndef SA_SIZE
#define SA_SIZE(sa) \
@@ -40,13 +33,6 @@
1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
#endif
#ifdef HAVE_BSD_NETWORK
static int del_family = 0;
static union all_addr del_addr;
#endif
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
int arp_enumerate(void *parm, int (*callback)())
{
int mib[6];
@@ -97,13 +83,13 @@ int arp_enumerate(void *parm, int (*callback)())
return 1;
}
#endif /* defined(HAVE_BSD_NETWORK) && !defined(__APPLE__) */
#endif
int iface_enumerate(int family, void *parm, int (*callback)())
{
struct ifaddrs *head, *addrs;
int errsave, fd = -1, ret = 0;
int errsav, ret = 0;
if (family == AF_UNSPEC)
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
@@ -119,87 +105,36 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (getifaddrs(&head) == -1)
return 0;
#if defined(HAVE_BSD_NETWORK)
if (family == AF_INET6)
fd = socket(PF_INET6, SOCK_DGRAM, 0);
#endif
for (addrs = head; addrs; addrs = addrs->ifa_next)
{
if (addrs->ifa_addr->sa_family == family)
{
int iface_index = if_nametoindex(addrs->ifa_name);
if (iface_index == 0 || !addrs->ifa_addr ||
(!addrs->ifa_netmask && family != AF_LINK))
if (iface_index == 0)
continue;
if (family == AF_INET)
{
struct in_addr addr, netmask, broadcast;
addr = ((struct sockaddr_in *) addrs->ifa_addr)->sin_addr;
#ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET && del_addr.addr4.s_addr == addr.s_addr)
continue;
#endif
netmask = ((struct sockaddr_in *) addrs->ifa_netmask)->sin_addr;
if (addrs->ifa_broadaddr)
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
else
broadcast.s_addr = 0;
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
goto err;
}
#ifdef HAVE_IPV6
else if (family == AF_INET6)
{
struct in6_addr *addr = &((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_addr;
unsigned char *netmask = (unsigned char *) &((struct sockaddr_in6 *) addrs->ifa_netmask)->sin6_addr;
int scope_id = ((struct sockaddr_in6 *) addrs->ifa_addr)->sin6_scope_id;
int i, j, prefix = 0;
u32 valid = 0xffffffff, preferred = 0xffffffff;
int flags = 0;
#ifdef HAVE_BSD_NETWORK
if (del_family == AF_INET6 && IN6_ARE_ADDR_EQUAL(&del_addr.addr6, addr))
continue;
#endif
#if defined(HAVE_BSD_NETWORK) && !defined(__APPLE__)
struct in6_ifreq ifr6;
memset(&ifr6, 0, sizeof(ifr6));
safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
{
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
flags |= IFACE_TENTATIVE;
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
flags |= IFACE_DEPRECATED;
#ifdef IN6_IFF_TEMPORARY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_TEMPORARY)))
flags |= IFACE_PERMANENT;
#endif
#ifdef IN6_IFF_PRIVACY
if (!(ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_AUTOCONF | IN6_IFF_PRIVACY)))
flags |= IFACE_PERMANENT;
#endif
}
ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
if (fd != -1 && ioctl(fd, SIOCGIFALIFETIME_IN6, &ifr6) != -1)
{
valid = ifr6.ifr_ifru.ifru_lifetime.ia6t_vltime;
preferred = ifr6.ifr_ifru.ifru_lifetime.ia6t_pltime;
}
#endif
for (i = 0; i < IN6ADDRSZ; i++, prefix += 8)
if (netmask[i] != 0xff)
break;
if (i != IN6ADDRSZ && netmask[i])
for (j = 7; j > 0; j--, prefix++)
if ((netmask[i] & (1 << j)) == 0)
@@ -210,13 +145,12 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
addr->s6_addr[2] = 0;
addr->s6_addr[3] = 0;
}
if (!((*callback)(addr, prefix, scope_id, iface_index, flags,
(int) preferred, (int)valid, parm)))
goto err;
}
}
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
goto err;
}
#endif
#ifdef HAVE_DHCP6
else if (family == AF_LINK)
{
@@ -233,15 +167,13 @@ int iface_enumerate(int family, void *parm, int (*callback)())
ret = 1;
err:
errsave = errno;
freeifaddrs(head);
if (fd != -1)
close(fd);
errno = errsave;
errsav = errno;
freeifaddrs(head);
errno = errsav;
return ret;
}
#endif /* defined(HAVE_BSD_NETWORK) || defined(HAVE_SOLARIS_NETWORK) */
#endif
#if defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP)
@@ -357,86 +289,9 @@ void send_via_bpf(struct dhcp_packet *mess, size_t len,
iov[3].iov_base = mess;
iov[3].iov_len = len;
while (retry_send(writev(daemon->dhcp_raw_fd, iov, 4)));
while (writev(daemon->dhcp_raw_fd, iov, 4) == -1 && retry_send());
}
#endif /* defined(HAVE_BSD_NETWORK) && defined(HAVE_DHCP) */
#endif
#ifdef HAVE_BSD_NETWORK
void route_init(void)
{
/* AF_UNSPEC: all addr families */
daemon->routefd = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
if (daemon->routefd == -1 || !fix_fd(daemon->routefd))
die(_("cannot create PF_ROUTE socket: %s"), NULL, EC_BADNET);
}
void route_sock(void)
{
struct if_msghdr *msg;
int rc = recv(daemon->routefd, daemon->packet, daemon->packet_buff_sz, 0);
if (rc < 4)
return;
msg = (struct if_msghdr *)daemon->packet;
if (rc < msg->ifm_msglen)
return;
if (msg->ifm_version != RTM_VERSION)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_WARNING, _("Unknown protocol version from route socket"));
warned = 1;
}
}
else if (msg->ifm_type == RTM_NEWADDR)
{
del_family = 0;
queue_event(EVENT_NEWADDR);
}
else if (msg->ifm_type == RTM_DELADDR)
{
/* There's a race in the kernel, such that if we run iface_enumerate() immediately
we get a DELADDR event, the deleted address still appears. Here we store the deleted address
in a static variable, and omit it from the set returned by iface_enumerate() */
int mask = ((struct ifa_msghdr *)msg)->ifam_addrs;
int maskvec[] = { RTA_DST, RTA_GATEWAY, RTA_NETMASK, RTA_GENMASK,
RTA_IFP, RTA_IFA, RTA_AUTHOR, RTA_BRD };
int of;
unsigned int i;
for (i = 0, of = sizeof(struct ifa_msghdr); of < rc && i < sizeof(maskvec)/sizeof(maskvec[0]); i++)
if (mask & maskvec[i])
{
struct sockaddr *sa = (struct sockaddr *)((char *)msg + of);
size_t diff = (sa->sa_len != 0) ? sa->sa_len : sizeof(long);
if (maskvec[i] == RTA_IFA)
{
del_family = sa->sa_family;
if (del_family == AF_INET)
del_addr.addr4 = ((struct sockaddr_in *)sa)->sin_addr;
else if (del_family == AF_INET6)
del_addr.addr6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
else
del_family = 0;
}
of += diff;
/* round up as needed */
if (diff & (sizeof(long) - 1))
of += sizeof(long) - (diff & (sizeof(long) - 1));
}
queue_event(EVENT_NEWADDR);
}
}
#endif /* HAVE_BSD_NETWORK */

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,48 +17,32 @@
#define FTABSIZ 150 /* max number of outstanding requests (default) */
#define MAX_PROCS 20 /* max no children for TCP requests */
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
#define TCP_MAX_QUERIES 100 /* Maximum number of queries per incoming TCP connection */
#define TCP_BACKLOG 32 /* kernel backlog limit for TCP connections */
#define EDNS_PKTSZ 4096 /* default max EDNS.0 UDP packet from RFC5625 */
#define SAFE_PKTSZ 1232 /* "go anywhere" UDP packet size, see https://dnsflagday.net/2020/ */
#define KEYBLOCK_LEN 40 /* choose to minimise fragmentation when storing DNSSEC keys */
#define DNSSEC_WORK 50 /* Max number of queries to validate one question */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define KEYBLOCK_LEN 140 /* choose to mininise fragmentation when storing DNSSEC keys */
#define TIMEOUT 10 /* drop UDP queries after TIMEOUT seconds */
#define FORWARD_TEST 50 /* try all servers every 50 queries */
#define FORWARD_TIME 20 /* or 20 seconds */
#define UDP_TEST_TIME 60 /* How often to reset our idea of max packet size. */
#define SERVERS_LOGGED 30 /* Only log this many servers when logging state */
#define LOCALS_LOGGED 8 /* Only log this many local addresses when logging state */
#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 */
#define TTL_FLOOR_LIMIT 3600 /* don't allow --min-cache-ttl to raise TTL above this under any circumstances */
#define MAXLEASES 1000 /* maximum number of DHCP leases */
#define PING_WAIT 3 /* wait for ping address-in-use test */
#define PING_CACHE_TIME 30 /* Ping test assumed to be valid this long. */
#define DECLINE_BACKOFF 600 /* disable DECLINEd static addresses for this long */
#define DHCP_PACKET_MAX 16384 /* hard limit on DHCP packet size */
#define SMALLDNAME 50 /* most domain names are smaller than this */
#define CNAME_CHAIN 10 /* chains longer than this atr dropped for loop protection */
#define DNSSEC_MIN_TTL 60 /* DNSKEY and DS records in cache last at least this long */
#define SMALLDNAME 40 /* most domain names are smaller than this */
#define HOSTSFILE "/etc/hosts"
#define ETHERSFILE "/etc/ethers"
#define DEFLEASE 3600 /* default DHCPv4 lease time, one hour */
#define DEFLEASE6 (3600*24) /* default lease time for DHCPv6. One day. */
#define DEFLEASE 3600 /* default lease time, 1 hour */
#define CHUSER "nobody"
#define CHGRP "dip"
#define TFTP_MAX_CONNECTIONS 50 /* max simultaneous connections */
#define LOG_MAX 5 /* log-queue length */
#define RANDFILE "/dev/urandom"
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
#define DNSMASQ_UBUS_NAME "dnsmasq" /* Default - may be overridden by config */
#define AUTH_TTL 600 /* default TTL for auth DNS */
#define SOA_REFRESH 1200 /* SOA refresh default */
#define SOA_RETRY 180 /* SOA retry default */
#define SOA_EXPIRY 1209600 /* SOA expiry default */
#define LOOP_TEST_DOMAIN "test" /* domain for loop testing, "test" is reserved by RFC 2606 and won't therefore clash */
#define LOOP_TEST_TYPE T_TXT
/* compile-time options: uncomment below to enable or do eg.
make COPTS=-DHAVE_BROKEN_RTC
@@ -96,65 +80,28 @@ HAVE_DBUS
support some methods to allow (re)configuration of the upstream DNS
servers via DBus.
HAVE_UBUS
define this if you want to link against libubus
HAVE_IDN
define this if you want international domain name 2003 support.
HAVE_LIBIDN2
define this if you want international domain name 2008 support.
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 propagates conntrack marks from
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.
HAVE_IPSET
define this to include the ability to selectively add resolved ip addresses
to given ipsets.
HAVE_NFTSET
define this to include the ability to selectively add resolved ip addresses
to given nftables sets.
HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
HAVE_CRYPTOHASH
include just hash function from crypto library, but no DNSSEC.
HAVE_DNSSEC
include DNSSEC validator.
HAVE_DUMPFILE
include code to dump packets to a libpcap-format file for debugging.
HAVE_LOOP
include functionality to probe for and remove DNS forwarding loops.
HAVE_INOTIFY
use the Linux inotify facility to efficiently re-read configuration files.
NO_ID
Don't report *.bind CHAOS info to clients, forward such requests upstream instead.
NO_IPV6
NO_TFTP
NO_DHCP
NO_DHCP6
NO_SCRIPT
NO_LARGEFILE
NO_AUTH
NO_DUMPFILE
NO_LOOP
NO_INOTIFY
these are available to explicitly disable compile time options which would
otherwise be enabled automatically or which are enabled by default
in the distributed source tree. Building dnsmasq
these are avilable to explictly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
with something like "make COPTS=-DNO_SCRIPT" will do the trick.
NO_GMP
Don't use and link against libgmp, Useful if nettle is built with --enable-mini-gmp.
LEASEFILE
CONFFILE
@@ -164,11 +111,6 @@ RESOLVFILE
*/
/* Defining this builds a binary which handles time differently and works better on a system without a
stable RTC (it uses uptime, not epoch time) and writes the DHCP leases file less often to avoid flash wear.
*/
/* #define HAVE_BROKEN_RTC */
/* The default set of options to build. Built with these options, dnsmasq
has no library dependencies other than libc */
@@ -177,26 +119,13 @@ RESOLVFILE
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_SCRIPT
#define HAVE_AUTH
#define HAVE_IPSET
#define HAVE_LOOP
#define HAVE_DUMPFILE
/* Build options which require external libraries.
Defining HAVE_<opt>_STATIC as _well_ as HAVE_<opt> will link the library statically.
You can use "make COPTS=-DHAVE_<opt>" instead of editing these.
*/
/* #define HAVE_LUASCRIPT */
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
/* #define HAVE_IDN */
/* #define HAVE_LIBIDN2 */
/* #define HAVE_CONNTRACK */
/* #define HAVE_CRYPTOHASH */
/* #define HAVE_DNSSEC */
/* #define HAVE_NFTSET */
/* Default locations for important system files. */
@@ -246,17 +175,37 @@ HAVE_SOLARIS_NETWORK
HAVE_GETOPT_LONG
defined when GNU-style getopt_long available.
HAVE_ARC4RANDOM
defined if arc4random() available to get better security from DNS spoofs
by using really random ids (OpenBSD)
HAVE_SOCKADDR_SA_LEN
defined if struct sockaddr has sa_len field (*BSD)
*/
#if defined(__UCLIBC__)
/* Must preceed __linux__ since uClinux defines __linux__ too. */
#if defined(__uClinux__)
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
/* Never use fork() on uClinux. Note that this is subtly different from the
--keep-in-foreground option, since it also suppresses forking new
processes for TCP connections and disables the call-a-script on leasechange
system. It's intended for use on MMU-less kernels. */
#define NO_FORK
#elif defined(__UCLIBC__)
#define HAVE_LINUX_NETWORK
#if defined(__UCLIBC_HAS_GNU_GETOPT__) || \
((__UCLIBC_MAJOR__==0) && (__UCLIBC_MINOR__==9) && (__UCLIBC_SUBLEVEL__<21))
# define HAVE_GETOPT_LONG
#endif
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#if !defined(__ARCH_HAS_MMU__) && !defined(__UCLIBC_HAS_MMU__)
# define NO_FORK
#endif
#if defined(__UCLIBC_HAS_IPV6__)
# ifndef IPV6_V6ONLY
# define IPV6_V6ONLY 26
@@ -267,6 +216,7 @@ HAVE_SOCKADDR_SA_LEN
#elif defined(__linux__)
#define HAVE_LINUX_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#elif defined(__FreeBSD__) || \
@@ -274,44 +224,61 @@ HAVE_SOCKADDR_SA_LEN
defined(__DragonFly__) || \
defined(__FreeBSD_kernel__)
#define HAVE_BSD_NETWORK
/* Later versions of FreeBSD have getopt_long() */
/* Later verions of FreeBSD have getopt_long() */
#if defined(optional_argument) && defined(required_argument)
# define HAVE_GETOPT_LONG
#endif
#if !defined(__FreeBSD_kernel__)
# define HAVE_ARC4RANDOM
#endif
#define HAVE_SOCKADDR_SA_LEN
#elif defined(__APPLE__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#define HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
#define NO_IPSET
/* Define before sys/socket.h is included so we get socklen_t */
#define _BSD_SOCKLEN_T_
/* Select the RFC_3542 version of the IPv6 socket API.
Define before netinet6/in6.h is included. */
#define __APPLE_USE_RFC_3542
/* Required for Mojave. */
#ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
#endif
#define NO_IPSET
#elif defined(__NetBSD__)
#define HAVE_BSD_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#define HAVE_SOCKADDR_SA_LEN
#elif defined(__sun) || defined(__sun__)
#define HAVE_SOLARIS_NETWORK
#define HAVE_GETOPT_LONG
#undef HAVE_ARC4RANDOM
#undef HAVE_SOCKADDR_SA_LEN
#define ETHER_ADDR_LEN 6
#endif
/* Decide if we're going to support IPv6 */
/* We assume that systems which don't have IPv6
headers don't have ntop and pton either */
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
# define HAVE_IPV6
# define ADDRSTRLEN INET6_ADDRSTRLEN
#elif defined(INET_ADDRSTRLEN)
# undef HAVE_IPV6
# define ADDRSTRLEN INET_ADDRSTRLEN
#else
# undef HAVE_IPV6
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
#endif
/* rules to implement compile-time option dependencies and
the NO_XXX flags */
#ifdef NO_IPV6
#undef HAVE_IPV6
#endif
#ifdef NO_TFTP
#undef HAVE_TFTP
#endif
@@ -321,7 +288,7 @@ HAVE_SOCKADDR_SA_LEN
#undef HAVE_DHCP6
#endif
#if defined(NO_DHCP6)
#if defined(NO_DHCP6) || !defined(HAVE_IPV6)
#undef HAVE_DHCP6
#endif
@@ -330,7 +297,7 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_DHCP
#endif
#if defined(NO_SCRIPT)
#if defined(NO_SCRIPT) || !defined(HAVE_DHCP) || defined(NO_FORK)
#undef HAVE_SCRIPT
#undef HAVE_LUASCRIPT
#endif
@@ -340,32 +307,16 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_SCRIPT
#endif
#ifdef NO_AUTH
#undef HAVE_AUTH
#endif
#if defined(NO_IPSET)
#undef HAVE_IPSET
#endif
#ifdef NO_LOOP
#undef HAVE_LOOP
#endif
#ifdef NO_DUMPFILE
#undef HAVE_DUMPFILE
#endif
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
#define HAVE_INOTIFY
#endif
/* Define a string indicating which options are in use.
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
#ifdef DNSMASQ_COMPILE_OPTS
static char *compile_opts =
#ifndef HAVE_IPV6
"no-"
#endif
"IPv6 "
#ifndef HAVE_GETOPT_LONG
"no-"
@@ -374,26 +325,21 @@ static char *compile_opts =
#ifdef HAVE_BROKEN_RTC
"no-RTC "
#endif
#ifdef NO_FORK
"no-MMU "
#endif
#ifndef HAVE_DBUS
"no-"
#endif
"DBus "
#ifndef HAVE_UBUS
"no-"
#endif
"UBus "
#ifndef LOCALEDIR
"no-"
#endif
"i18n "
#if defined(HAVE_LIBIDN2)
"IDN2 "
#else
#if !defined(HAVE_IDN)
#if !defined(LOCALEDIR) && !defined(HAVE_IDN)
"no-"
#endif
"IDN "
#endif
#endif
"IDN "
#ifndef HAVE_DHCP
"no-"
#endif
@@ -403,14 +349,14 @@ static char *compile_opts =
"no-"
# endif
"DHCPv6 "
#endif
#if !defined(HAVE_SCRIPT)
# if !defined(HAVE_SCRIPT)
"no-scripts "
#else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
# else
# if !defined(HAVE_LUASCRIPT)
"no-"
# endif
"Lua "
# endif
#endif
#ifndef HAVE_TFTP
"no-"
@@ -419,41 +365,9 @@ static char *compile_opts =
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack "
#ifndef HAVE_IPSET
"no-"
#endif
"ipset "
#ifndef HAVE_NFTSET
"no-"
#endif
"nftset "
#ifndef HAVE_AUTH
"no-"
#endif
"auth "
#if !defined(HAVE_CRYPTOHASH) && !defined(HAVE_DNSSEC)
"no-"
#endif
"cryptohash "
#ifndef HAVE_DNSSEC
"no-"
#endif
"DNSSEC "
#ifdef NO_ID
"no-ID "
#endif
#ifndef HAVE_LOOP
"no-"
#endif
"loop-detect "
#ifndef HAVE_INOTIFY
"no-"
#endif
"inotify "
#ifndef HAVE_DUMPFILE
"no-"
#endif
"dumpfile";
"conntrack";
#endif
#endif /* defined(HAVE_DHCP) */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ 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, union all_addr *local_addr, int istcp, unsigned int *markp)
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;
@@ -36,19 +36,21 @@ int get_incoming_mark(union mysockaddr *peer_addr, union all_addr *local_addr, i
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->addr6.s6_addr);
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->addr4.s_addr);
nfct_set_attr_u32(ct, ATTR_IPV4_DST, local_addr->addr.addr4.s_addr);
}
@@ -82,4 +84,7 @@ static int callback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, vo
return NFCT_CB_CONTINUE;
}
#endif /* HAVE_CONNTRACK */
#endif

View File

@@ -1,499 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
/* Minimal version of nettle */
/* bignum.h includes version.h and works on
earlier releases of nettle which don't have version.h */
#include <nettle/bignum.h>
#if !defined(NETTLE_VERSION_MAJOR)
# define NETTLE_VERSION_MAJOR 2
# define NETTLE_VERSION_MINOR 0
#endif
#define MIN_VERSION(major, minor) ((NETTLE_VERSION_MAJOR == (major) && NETTLE_VERSION_MINOR >= (minor)) || \
(NETTLE_VERSION_MAJOR > (major)))
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */
#if defined(HAVE_DNSSEC)
#include <nettle/rsa.h>
#include <nettle/ecdsa.h>
#include <nettle/ecc-curve.h>
#if MIN_VERSION(3, 1)
#include <nettle/eddsa.h>
#endif
#if MIN_VERSION(3, 6)
# include <nettle/gostdsa.h>
#endif
#if MIN_VERSION(3, 1)
/* Implement a "hash-function" to the nettle API, which simply returns
the input data, concatenated into a single, statically maintained, buffer.
Used for the EdDSA sigs, which operate on the whole message, rather
than a digest. */
struct null_hash_digest
{
uint8_t *buff;
size_t len;
};
struct null_hash_ctx
{
size_t len;
};
static size_t null_hash_buff_sz = 0;
static uint8_t *null_hash_buff = NULL;
#define BUFF_INCR 128
static void null_hash_init(void *ctx)
{
((struct null_hash_ctx *)ctx)->len = 0;
}
static void null_hash_update(void *ctxv, size_t length, const uint8_t *src)
{
struct null_hash_ctx *ctx = ctxv;
size_t new_len = ctx->len + length;
if (new_len > null_hash_buff_sz)
{
uint8_t *new;
if (!(new = whine_malloc(new_len + BUFF_INCR)))
return;
if (null_hash_buff)
{
if (ctx->len != 0)
memcpy(new, null_hash_buff, ctx->len);
free(null_hash_buff);
}
null_hash_buff_sz = new_len + BUFF_INCR;
null_hash_buff = new;
}
memcpy(null_hash_buff + ctx->len, src, length);
ctx->len += length;
}
static void null_hash_digest(void *ctx, size_t length, uint8_t *dst)
{
(void)length;
((struct null_hash_digest *)dst)->buff = null_hash_buff;
((struct null_hash_digest *)dst)->len = ((struct null_hash_ctx *)ctx)->len;
}
static struct nettle_hash null_hash = {
"null_hash",
sizeof(struct null_hash_ctx),
sizeof(struct null_hash_digest),
0,
(nettle_hash_init_func *) null_hash_init,
(nettle_hash_update_func *) null_hash_update,
(nettle_hash_digest_func *) null_hash_digest
};
#endif /* MIN_VERSION(3, 1) */
/* expand ctx and digest memory allocations if necessary and init hash function */
int hash_init(const struct nettle_hash *hash, void **ctxp, unsigned char **digestp)
{
static void *ctx = NULL;
static unsigned char *digest = NULL;
static unsigned int ctx_sz = 0;
static unsigned int digest_sz = 0;
void *new;
if (ctx_sz < hash->context_size)
{
if (!(new = whine_malloc(hash->context_size)))
return 0;
if (ctx)
free(ctx);
ctx = new;
ctx_sz = hash->context_size;
}
if (digest_sz < hash->digest_size)
{
if (!(new = whine_malloc(hash->digest_size)))
return 0;
if (digest)
free(digest);
digest = new;
digest_sz = hash->digest_size;
}
*ctxp = ctx;
*digestp = digest;
hash->init(ctx);
return 1;
}
static int dnsmasq_rsa_verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
size_t exp_len;
static struct rsa_public_key *key = NULL;
static mpz_t sig_mpz;
(void)digest_len;
if (key == NULL)
{
if (!(key = whine_malloc(sizeof(struct rsa_public_key))))
return 0;
nettle_rsa_public_key_init(key);
mpz_init(sig_mpz);
}
if ((key_len < 3) || !(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
key_len--;
if ((exp_len = *p++) == 0)
{
GETSHORT(exp_len, p);
key_len -= 2;
}
if (exp_len >= key_len)
return 0;
key->size = key_len - exp_len;
mpz_import(key->e, exp_len, 1, 1, 0, 0, p);
mpz_import(key->n, key->size, 1, 1, 0, 0, p + exp_len);
mpz_import(sig_mpz, sig_len, 1, 1, 0, 0, sig);
switch (algo)
{
case 5: case 7:
return nettle_rsa_sha1_verify_digest(key, digest, sig_mpz);
case 8:
return nettle_rsa_sha256_verify_digest(key, digest, sig_mpz);
case 10:
return nettle_rsa_sha512_verify_digest(key, digest, sig_mpz);
}
return 0;
}
static int dnsmasq_ecdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
unsigned int t;
struct ecc_point *key;
static struct ecc_point *key_256 = NULL, *key_384 = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
#if !MIN_VERSION(3, 4)
#define nettle_get_secp_256r1() (&nettle_secp_256r1)
#define nettle_get_secp_384r1() (&nettle_secp_384r1)
#endif
if (!sig_struct)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))))
return 0;
nettle_dsa_signature_init(sig_struct);
mpz_init(x);
mpz_init(y);
}
switch (algo)
{
case 13:
if (!key_256)
{
if (!(key_256 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_256, nettle_get_secp_256r1());
}
key = key_256;
t = 32;
break;
case 14:
if (!key_384)
{
if (!(key_384 = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_ecc_point_init(key_384, nettle_get_secp_384r1());
}
key = key_384;
t = 48;
break;
default:
return 0;
}
if (sig_len != 2*t || key_len != 2*t ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
mpz_import(x, t , 1, 1, 0, 0, p);
mpz_import(y, t , 1, 1, 0, 0, p + t);
if (!ecc_point_set(key, x, y))
return 0;
mpz_import(sig_struct->r, t, 1, 1, 0, 0, sig);
mpz_import(sig_struct->s, t, 1, 1, 0, 0, sig + t);
return nettle_ecdsa_verify(key, digest_len, digest, sig_struct);
}
#if MIN_VERSION(3, 6)
static int dnsmasq_gostdsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
static struct ecc_point *gost_key = NULL;
static mpz_t x, y;
static struct dsa_signature *sig_struct;
if (algo != 12 ||
sig_len != 64 || key_len != 64 ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
if (!sig_struct)
{
if (!(sig_struct = whine_malloc(sizeof(struct dsa_signature))) ||
!(gost_key = whine_malloc(sizeof(struct ecc_point))))
return 0;
nettle_dsa_signature_init(sig_struct);
nettle_ecc_point_init(gost_key, nettle_get_gost_gc256b());
mpz_init(x);
mpz_init(y);
}
mpz_import(x, 32 , 1, 1, 0, 0, p);
mpz_import(y, 32 , 1, 1, 0, 0, p + 32);
if (!ecc_point_set(gost_key, x, y))
return 0;
mpz_import(sig_struct->r, 32, 1, 1, 0, 0, sig);
mpz_import(sig_struct->s, 32, 1, 1, 0, 0, sig + 32);
return nettle_gostdsa_verify(gost_key, digest_len, digest, sig_struct);
}
#endif
#if MIN_VERSION(3, 1)
static int dnsmasq_eddsa_verify(struct blockdata *key_data, unsigned int key_len,
unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
unsigned char *p;
if (digest_len != sizeof(struct null_hash_digest) ||
!(p = blockdata_retrieve(key_data, key_len, NULL)))
return 0;
/* The "digest" returned by the null_hash function is simply a struct null_hash_digest
which has a pointer to the actual data and a length, because the buffer
may need to be extended during "hashing". */
switch (algo)
{
case 15:
if (key_len != ED25519_KEY_SIZE ||
sig_len != ED25519_SIGNATURE_SIZE)
return 0;
return ed25519_sha512_verify(p,
((struct null_hash_digest *)digest)->len,
((struct null_hash_digest *)digest)->buff,
sig);
#if MIN_VERSION(3, 6)
case 16:
if (key_len != ED448_KEY_SIZE ||
sig_len != ED448_SIGNATURE_SIZE)
return 0;
return ed448_shake256_verify(p,
((struct null_hash_digest *)digest)->len,
((struct null_hash_digest *)digest)->buff,
sig);
#endif
}
return 0;
}
#endif
static int (*verify_func(int algo))(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
/* Ensure at runtime that we have support for this digest */
if (!hash_find(algo_digest_name(algo)))
return NULL;
/* This switch defines which sig algorithms we support, can't introspect Nettle for that. */
switch (algo)
{
case 5: case 7: case 8: case 10:
return dnsmasq_rsa_verify;
#if MIN_VERSION(3, 6)
case 12:
return dnsmasq_gostdsa_verify;
#endif
case 13: case 14:
return dnsmasq_ecdsa_verify;
#if MIN_VERSION(3, 1)
case 15: case 16:
return dnsmasq_eddsa_verify;
#endif
}
return NULL;
}
int verify(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo)
{
int (*func)(struct blockdata *key_data, unsigned int key_len, unsigned char *sig, size_t sig_len,
unsigned char *digest, size_t digest_len, int algo);
func = verify_func(algo);
if (!func)
return 0;
return (*func)(key_data, key_len, sig, sig_len, digest, digest_len, algo);
}
/* Note the ds_digest_name(), algo_digest_name() and nsec3_digest_name()
define which algo numbers we support. If algo_digest_name() returns
non-NULL for an algorithm number, we assume that algorithm is
supported by verify(). */
/* http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
char *ds_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
case 2: return "sha256";
case 3: return "gosthash94";
case 4: return "sha384";
default: return NULL;
}
}
/* http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
char *algo_digest_name(int algo)
{
switch (algo)
{
case 1: return NULL; /* RSA/MD5 - Must Not Implement. RFC 6944 para 2.3. */
case 2: return NULL; /* Diffie-Hellman */
case 3: return NULL; ; /* DSA/SHA1 - Must Not Implement. RFC 8624 section 3.1 */
case 5: return "sha1"; /* RSA/SHA1 */
case 6: return NULL; /* DSA-NSEC3-SHA1 - Must Not Implement. RFC 8624 section 3.1 */
case 7: return "sha1"; /* RSASHA1-NSEC3-SHA1 */
case 8: return "sha256"; /* RSA/SHA-256 */
case 10: return "sha512"; /* RSA/SHA-512 */
case 12: return "gosthash94"; /* ECC-GOST */
case 13: return "sha256"; /* ECDSAP256SHA256 */
case 14: return "sha384"; /* ECDSAP384SHA384 */
case 15: return "null_hash"; /* ED25519 */
case 16: return "null_hash"; /* ED448 */
default: return NULL;
}
}
/* http://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */
char *nsec3_digest_name(int digest)
{
switch (digest)
{
case 1: return "sha1";
default: return NULL;
}
}
#endif /* defined(HAVE_DNSSEC) */
#if defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH)
/* Find pointer to correct hash function in nettle library */
const struct nettle_hash *hash_find(char *name)
{
if (!name)
return NULL;
#if MIN_VERSION(3,1) && defined(HAVE_DNSSEC)
/* We provide a "null" hash which returns the input data as digest. */
if (strcmp(null_hash.name, name) == 0)
return &null_hash;
#endif
/* libnettle >= 3.4 provides nettle_lookup_hash() which avoids nasty ABI
incompatibilities if sizeof(nettle_hashes) changes between library
versions. */
#if MIN_VERSION(3, 4)
return nettle_lookup_hash(name);
#else
{
int i;
for (i = 0; nettle_hashes[i]; i++)
if (strcmp(nettle_hashes[i]->name, name) == 0)
return nettle_hashes[i];
}
return NULL;
#endif
}
#endif /* defined(HAVE_DNSSEC) || defined(HAVE_CRYPTOHASH) */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -35,11 +35,6 @@ const char* introspection_xml_template =
" <method name=\"GetVersion\">\n"
" <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
" </method>\n"
#ifdef HAVE_LOOP
" <method name=\"GetLoopServers\">\n"
" <arg name=\"server\" direction=\"out\" type=\"as\"/>\n"
" </method>\n"
#endif
" <method name=\"SetServers\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"av\"/>\n"
" </method>\n"
@@ -49,15 +44,6 @@ const char* introspection_xml_template =
" <method name=\"SetServersEx\">\n"
" <arg name=\"servers\" direction=\"in\" type=\"aas\"/>\n"
" </method>\n"
" <method name=\"SetFilterWin2KOption\">\n"
" <arg name=\"filterwin2k\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"SetLocaliseQueriesOption\">\n"
" <arg name=\"localise-queries\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"SetBogusPrivOption\">\n"
" <arg name=\"boguspriv\" direction=\"in\" type=\"b\"/>\n"
" </method>\n"
" <signal name=\"DhcpLeaseAdded\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
@@ -73,24 +59,6 @@ const char* introspection_xml_template =
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"s\"/>\n"
" </signal>\n"
#ifdef HAVE_DHCP
" <method name=\"AddDhcpLease\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"hwaddr\" type=\"s\"/>\n"
" <arg name=\"hostname\" type=\"ay\"/>\n"
" <arg name=\"clid\" type=\"ay\"/>\n"
" <arg name=\"lease_duration\" type=\"u\"/>\n"
" <arg name=\"ia_id\" type=\"u\"/>\n"
" <arg name=\"is_temporary\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"DeleteDhcpLease\">\n"
" <arg name=\"ipaddr\" type=\"s\"/>\n"
" <arg name=\"success\" type=\"b\" direction=\"out\"/>\n"
" </method>\n"
#endif
" <method name=\"GetMetrics\">\n"
" <arg name=\"metrics\" direction=\"out\" type=\"a{su}\"/>\n"
" </method>\n"
" </interface>\n"
"</node>\n";
@@ -117,43 +85,138 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *data)
w->next = daemon->watches;
daemon->watches = w;
(void)data; /* no warning */
w = data; /* no warning */
return TRUE;
}
static void remove_watch(DBusWatch *watch, void *data)
{
struct watch **up, *w, *tmp;
struct watch **up, *w;
for (up = &(daemon->watches), w = daemon->watches; w; w = tmp)
{
tmp = w->next;
if (w->watch == watch)
{
*up = tmp;
free(w);
}
else
up = &(w->next);
}
for (up = &(daemon->watches), w = daemon->watches; w; w = w->next)
if (w->watch == watch)
{
*up = w->next;
free(w);
}
else
up = &(w->next);
(void)data; /* no warning */
w = data; /* no warning */
}
static DBusMessage* dbus_read_servers(DBusMessage *message)
static void add_update_server(union mysockaddr *addr,
union mysockaddr *source_addr,
const char *interface,
const char *domain)
{
struct server *serv;
/* See if there is a suitable candidate, and unmark */
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_FROM_DBUS) &&
(serv->flags & SERV_MARK))
{
if (domain)
{
if (!(serv->flags & SERV_HAS_DOMAIN) || !hostname_isequal(domain, serv->domain))
continue;
}
else
{
if (serv->flags & SERV_HAS_DOMAIN)
continue;
}
serv->flags &= ~SERV_MARK;
break;
}
if (!serv && (serv = whine_malloc(sizeof (struct server))))
{
/* Not found, create a new one. */
memset(serv, 0, sizeof(struct server));
if (domain && !(serv->domain = whine_malloc(strlen(domain)+1)))
{
free(serv);
serv = NULL;
}
else
{
serv->next = daemon->servers;
daemon->servers = serv;
serv->flags = SERV_FROM_DBUS;
if (domain)
{
strcpy(serv->domain, domain);
serv->flags |= SERV_HAS_DOMAIN;
}
}
}
if (serv)
{
if (interface)
strcpy(serv->interface, interface);
else
serv->interface[0] = 0;
if (source_addr->in.sin_family == AF_INET &&
addr->in.sin_addr.s_addr == 0 &&
serv->domain)
serv->flags |= SERV_NO_ADDR;
else
{
serv->flags &= ~SERV_NO_ADDR;
serv->addr = *addr;
serv->source_addr = *source_addr;
}
}
}
static void mark_dbus(void)
{
struct server *serv;
/* mark everything from DBUS */
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_FROM_DBUS)
serv->flags |= SERV_MARK;
}
static void cleanup_dbus()
{
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
server_gone(serv);
*up = serv->next;
if (serv->domain)
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
static void dbus_read_servers(DBusMessage *message)
{
DBusMessageIter iter;
union mysockaddr addr, source_addr;
char *domain;
if (!dbus_message_iter_init(message, &iter))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
}
dbus_message_iter_init(message, &iter);
mark_dbus();
mark_servers(SERV_FROM_DBUS);
while (1)
{
int skip = 0;
@@ -186,13 +249,13 @@ static DBusMessage* dbus_read_servers(DBusMessage *message)
dbus_message_iter_get_basic(&iter, &p[i]);
dbus_message_iter_next (&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BYTE)
{
i++;
break;
}
break;
}
if (i == sizeof(struct in6_addr))
#ifndef HAVE_IPV6
my_syslog(LOG_WARNING, _("attempt to set an IPv6 server address via DBus - no IPv6 support"));
#else
if (i == sizeof(struct in6_addr)-1)
{
memcpy(&addr.in6.sin6_addr, p, sizeof(struct in6_addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -206,6 +269,7 @@ static DBusMessage* dbus_read_servers(DBusMessage *message)
source_addr.in6.sin6_port = htons(daemon->query_port);
skip = 0;
}
#endif
}
else
/* At the end */
@@ -222,39 +286,15 @@ static DBusMessage* dbus_read_servers(DBusMessage *message)
domain = NULL;
if (!skip)
add_update_server(SERV_FROM_DBUS, &addr, &source_addr, NULL, domain, NULL);
add_update_server(&addr, &source_addr, NULL, domain);
} while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
}
/* unlink and free anything still marked. */
cleanup_servers();
return NULL;
cleanup_dbus();
}
#ifdef HAVE_LOOP
static DBusMessage *dbus_reply_server_loop(DBusMessage *message)
{
DBusMessageIter args, args_iter;
struct server *serv;
DBusMessage *reply = dbus_message_new_method_return(message);
dbus_message_iter_init_append (reply, &args);
dbus_message_iter_open_container (&args, DBUS_TYPE_ARRAY,DBUS_TYPE_STRING_AS_STRING, &args_iter);
for (serv = daemon->servers; serv; serv = serv->next)
if (serv->flags & SERV_LOOP)
{
(void)prettyprint_addr(&serv->addr, daemon->addrbuff);
dbus_message_iter_append_basic (&args_iter, DBUS_TYPE_STRING, &daemon->addrbuff);
}
dbus_message_iter_close_container (&args, &args_iter);
return reply;
}
#endif
static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
{
DBusMessageIter iter, array_iter, string_iter;
@@ -262,6 +302,8 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
const char *addr_err;
char *dup = NULL;
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
if (!dbus_message_iter_init(message, &iter))
{
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
@@ -276,7 +318,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
strings ? "Expected array of string" : "Expected array of string arrays");
}
mark_servers(SERV_FROM_DBUS);
mark_dbus();
/* array_iter points to each "as" element in the outer array */
dbus_message_iter_recurse(&iter, &array_iter);
@@ -284,7 +326,6 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
{
const char *str = NULL;
union mysockaddr addr, source_addr;
u16 flags = 0;
char interface[IF_NAMESIZE];
char *str_addr, *str_domain = NULL;
@@ -299,11 +340,9 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
}
/* dup the string because it gets modified during parsing */
if (dup)
free(dup);
if (!(dup = str_domain = whine_malloc(strlen(str)+1)))
break;
strcpy(str_domain, str);
/* point to address part of old string for error message */
@@ -361,28 +400,27 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
}
/* dup the string because it gets modified during parsing */
if (dup)
free(dup);
if (!(dup = str_addr = whine_malloc(strlen(str)+1)))
break;
strcpy(str_addr, str);
}
memset(&addr, 0, sizeof(addr));
memset(&source_addr, 0, sizeof(source_addr));
memset(&interface, 0, sizeof(interface));
/* parse the IP address */
if ((addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, &flags)))
{
addr_err = parse_server(str_addr, &addr, &source_addr, (char *) &interface, NULL);
if (addr_err)
{
error = dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s': %s",
str, addr_err);
break;
}
/* 0.0.0.0 for server address == NULL, for Dbus */
if (addr.in.sin_family == AF_INET &&
addr.in.sin_addr.s_addr == 0)
flags |= SERV_LITERAL_ADDRESS;
if (strings)
{
char *p;
@@ -396,7 +434,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
else
p = NULL;
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str_domain, NULL);
add_update_server(&addr, &source_addr, interface, str_domain);
} while ((str_domain = p));
}
else
@@ -411,7 +449,7 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
dbus_message_iter_get_basic(&string_iter, &str);
dbus_message_iter_next (&string_iter);
add_update_server(flags | SERV_FROM_DBUS, &addr, &source_addr, interface, str, NULL);
add_update_server(&addr, &source_addr, interface, str);
} while (dbus_message_iter_get_arg_type(&string_iter) == DBUS_TYPE_STRING);
}
@@ -419,238 +457,20 @@ static DBusMessage* dbus_read_servers_ex(DBusMessage *message, int strings)
dbus_message_iter_next(&array_iter);
}
cleanup_servers();
cleanup_dbus();
if (dup)
free(dup);
return error;
}
static DBusMessage *dbus_set_bool(DBusMessage *message, int flag, char *name)
{
DBusMessageIter iter;
dbus_bool_t enabled;
if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Expected boolean argument");
dbus_message_iter_get_basic(&iter, &enabled);
if (enabled)
{
my_syslog(LOG_INFO, _("Enabling --%s option from D-Bus"), name);
set_option_bool(flag);
}
else
{
my_syslog(LOG_INFO, _("Disabling --%s option from D-Bus"), name);
reset_option_bool(flag);
}
return NULL;
}
#ifdef HAVE_DHCP
static DBusMessage *dbus_add_lease(DBusMessage* message)
{
struct dhcp_lease *lease;
const char *ipaddr, *hwaddr, *hostname, *tmp;
const unsigned char* clid;
int clid_len, hostname_len, hw_len, hw_type;
dbus_uint32_t expires, ia_id;
dbus_bool_t is_temporary;
union all_addr addr;
time_t now = dnsmasq_time();
unsigned char dhcp_chaddr[DHCP_CHADDR_MAX];
DBusMessageIter iter, array_iter;
if (!dbus_message_iter_init(message, &iter))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as first argument");
dbus_message_iter_get_basic(&iter, &ipaddr);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as second argument");
dbus_message_iter_get_basic(&iter, &hwaddr);
dbus_message_iter_next(&iter);
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected byte array as third argument");
dbus_message_iter_recurse(&iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &hostname, &hostname_len);
tmp = memchr(hostname, '\0', hostname_len);
if (tmp)
{
if (tmp == &hostname[hostname_len - 1])
hostname_len--;
else
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Hostname contains an embedded NUL character");
}
dbus_message_iter_next(&iter);
if ((dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) ||
(dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_BYTE))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected byte array as fourth argument");
dbus_message_iter_recurse(&iter, &array_iter);
dbus_message_iter_get_fixed_array(&array_iter, &clid, &clid_len);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as fifth argument");
dbus_message_iter_get_basic(&iter, &expires);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as sixth argument");
dbus_message_iter_get_basic(&iter, &ia_id);
dbus_message_iter_next(&iter);
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected uint32 as sixth argument");
dbus_message_iter_get_basic(&iter, &is_temporary);
if (inet_pton(AF_INET, ipaddr, &addr.addr4))
{
if (ia_id != 0 || is_temporary)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"ia_id and is_temporary must be zero for IPv4 lease");
if (!(lease = lease_find_by_addr(addr.addr4)))
lease = lease4_allocate(addr.addr4);
}
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
{
if (!(lease = lease6_find_by_addr(&addr.addr6, 128, 0)))
lease = lease6_allocate(&addr.addr6,
is_temporary ? LEASE_TA : LEASE_NA);
lease_set_iaid(lease, ia_id);
}
#endif
else
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s'", ipaddr);
hw_len = parse_hex((char*)hwaddr, dhcp_chaddr, DHCP_CHADDR_MAX, NULL, &hw_type);
if (hw_len < 0)
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid HW address '%s'", hwaddr);
if (hw_type == 0 && hw_len != 0)
hw_type = ARPHRD_ETHER;
lease_set_hwaddr(lease, dhcp_chaddr, clid, hw_len, hw_type,
clid_len, now, 0);
lease_set_expires(lease, expires, now);
if (hostname_len != 0)
lease_set_hostname(lease, hostname, 0, get_domain(lease->addr), NULL);
lease_update_file(now);
lease_update_dns(0);
return NULL;
}
static DBusMessage *dbus_del_lease(DBusMessage* message)
{
struct dhcp_lease *lease;
DBusMessageIter iter;
const char *ipaddr;
DBusMessage *reply;
union all_addr addr;
dbus_bool_t ret = 1;
time_t now = dnsmasq_time();
if (!dbus_message_iter_init(message, &iter))
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Failed to initialize dbus message iter");
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
"Expected string as first argument");
dbus_message_iter_get_basic(&iter, &ipaddr);
if (inet_pton(AF_INET, ipaddr, &addr.addr4))
lease = lease_find_by_addr(addr.addr4);
#ifdef HAVE_DHCP6
else if (inet_pton(AF_INET6, ipaddr, &addr.addr6))
lease = lease6_find_by_addr(&addr.addr6, 128, 0);
#endif
else
return dbus_message_new_error_printf(message, DBUS_ERROR_INVALID_ARGS,
"Invalid IP address '%s'", ipaddr);
if (lease)
{
lease_prune(lease, now);
lease_update_file(now);
lease_update_dns(0);
}
else
ret = 0;
if ((reply = dbus_message_new_method_return(message)))
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &ret,
DBUS_TYPE_INVALID);
return reply;
}
#endif
static DBusMessage *dbus_get_metrics(DBusMessage* message)
{
DBusMessage *reply = dbus_message_new_method_return(message);
DBusMessageIter array, dict, iter;
int i;
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{su}", &array);
for (i = 0; i < __METRIC_MAX; i++) {
const char *key = get_metric_name(i);
dbus_uint32_t value = daemon->metrics[i];
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &dict);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, &key);
dbus_message_iter_append_basic(&dict, DBUS_TYPE_UINT32, &value);
dbus_message_iter_close_container(&array, &dict);
}
dbus_message_iter_close_container(&iter, &array);
return reply;
}
DBusHandlerResult message_handler(DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
char *method = (char *)dbus_message_get_member(message);
DBusMessage *reply = NULL;
int clear_cache = 0, new_servers = 0;
if (dbus_message_is_method_call(message, DBUS_INTERFACE_INTROSPECTABLE, "Introspect"))
{
@@ -672,70 +492,28 @@ DBusHandlerResult message_handler(DBusConnection *connection,
dbus_message_append_args(reply, DBUS_TYPE_STRING, &v, DBUS_TYPE_INVALID);
}
#ifdef HAVE_LOOP
else if (strcmp(method, "GetLoopServers") == 0)
{
reply = dbus_reply_server_loop(message);
}
#endif
else if (strcmp(method, "SetServers") == 0)
{
reply = dbus_read_servers(message);
new_servers = 1;
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
dbus_read_servers(message);
check_servers();
}
else if (strcmp(method, "SetServersEx") == 0)
{
reply = dbus_read_servers_ex(message, 0);
new_servers = 1;
check_servers();
}
else if (strcmp(method, "SetDomainServers") == 0)
{
reply = dbus_read_servers_ex(message, 1);
new_servers = 1;
}
else if (strcmp(method, "SetFilterWin2KOption") == 0)
{
reply = dbus_set_bool(message, OPT_FILTER, "filterwin2k");
}
else if (strcmp(method, "SetLocaliseQueriesOption") == 0)
{
reply = dbus_set_bool(message, OPT_LOCALISE, "localise-queries");
}
else if (strcmp(method, "SetBogusPrivOption") == 0)
{
reply = dbus_set_bool(message, OPT_BOGUSPRIV, "bogus-priv");
}
#ifdef HAVE_DHCP
else if (strcmp(method, "AddDhcpLease") == 0)
{
reply = dbus_add_lease(message);
}
else if (strcmp(method, "DeleteDhcpLease") == 0)
{
reply = dbus_del_lease(message);
}
#endif
else if (strcmp(method, "GetMetrics") == 0)
{
reply = dbus_get_metrics(message);
check_servers();
}
else if (strcmp(method, "ClearCache") == 0)
clear_cache = 1;
clear_cache_and_reload(dnsmasq_time());
else
return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
if (new_servers)
{
my_syslog(LOG_INFO, _("setting upstream servers from DBus"));
check_servers(0);
if (option_bool(OPT_RELOAD))
clear_cache = 1;
}
if (clear_cache)
clear_cache_and_reload(dnsmasq_time());
(void)user_data; /* no warning */
method = user_data; /* no warning */
/* If no reply or no error, return nothing */
if (!reply)
@@ -761,11 +539,8 @@ char *dbus_init(void)
dbus_error_init (&dbus_error);
if (!(connection = dbus_bus_get (DBUS_BUS_SYSTEM, &dbus_error)))
{
dbus_error_free(&dbus_error);
return NULL;
}
return NULL;
dbus_connection_set_exit_on_disconnect(connection, FALSE);
dbus_connection_set_watch_functions(connection, add_watch, remove_watch,
NULL, NULL, NULL);
@@ -790,7 +565,8 @@ char *dbus_init(void)
}
void set_dbus_listeners(void)
void set_dbus_listeners(int *maxfdp,
fd_set *rset, fd_set *wset, fd_set *eset)
{
struct watch *w;
@@ -800,17 +576,19 @@ void set_dbus_listeners(void)
unsigned int flags = dbus_watch_get_flags(w->watch);
int fd = dbus_watch_get_unix_fd(w->watch);
bump_maxfd(fd, maxfdp);
if (flags & DBUS_WATCH_READABLE)
poll_listen(fd, POLLIN);
FD_SET(fd, rset);
if (flags & DBUS_WATCH_WRITABLE)
poll_listen(fd, POLLOUT);
FD_SET(fd, wset);
poll_listen(fd, POLLERR);
FD_SET(fd, eset);
}
}
void check_dbus_listeners()
void check_dbus_listeners(fd_set *rset, fd_set *wset, fd_set *eset)
{
DBusConnection *connection = (DBusConnection *)daemon->dbus;
struct watch *w;
@@ -821,13 +599,13 @@ void check_dbus_listeners()
unsigned int flags = 0;
int fd = dbus_watch_get_unix_fd(w->watch);
if (poll_check(fd, POLLIN))
if (FD_ISSET(fd, rset))
flags |= DBUS_WATCH_READABLE;
if (poll_check(fd, POLLOUT))
if (FD_ISSET(fd, wset))
flags |= DBUS_WATCH_WRITABLE;
if (poll_check(fd, POLLERR))
if (FD_ISSET(fd, eset))
flags |= DBUS_WATCH_ERROR;
if (flags != 0)
@@ -862,7 +640,7 @@ void emit_dbus_signal(int action, struct dhcp_lease *lease, char *hostname)
if (lease->flags & (LEASE_TA | LEASE_NA))
{
print_mac(mac, lease->clid, lease->clid_len);
inet_ntop(AF_INET6, &lease->addr6, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, lease->hwaddr, daemon->addrbuff, ADDRSTRLEN);
}
else
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,11 +20,11 @@
void dhcp_common_init(void)
{
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(DHCP_BUFF_SZ);
daemon->dhcp_buff2 = safe_malloc(DHCP_BUFF_SZ);
daemon->dhcp_buff3 = safe_malloc(DHCP_BUFF_SZ);
/* These each hold a DHCP option max size 255
and get a terminating zero added */
daemon->dhcp_buff = safe_malloc(256);
daemon->dhcp_buff2 = safe_malloc(256);
daemon->dhcp_buff3 = safe_malloc(256);
/* dhcp_packet is used by v4 and v6, outpacket only by v6
sizeof(struct dhcp_packet) is as good an initial size as any,
@@ -38,7 +38,7 @@ void dhcp_common_init(void)
ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
{
ssize_t sz, new_sz;
ssize_t sz;
while (1)
{
@@ -65,48 +65,9 @@ ssize_t recv_dhcp_packet(int fd, struct msghdr *msg)
}
}
while ((new_sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
/* Some kernels seem to ignore MSG_PEEK, and dequeue the packet anyway.
If that happens we get EAGAIN here because the socket is non-blocking.
Use the result of the original testing recvmsg as long as the buffer
was big enough. There's a small race here that may lose the odd packet,
but it's UDP anyway. */
while ((sz = recvmsg(fd, msg, 0)) == -1 && errno == EINTR);
if (new_sz == -1 && (errno == EWOULDBLOCK || errno == EAGAIN))
new_sz = sz;
return (msg->msg_flags & MSG_TRUNC) ? -1 : new_sz;
}
/* like match_netid() except that the check can have a trailing * for wildcard */
/* started as a direct copy of match_netid() */
int match_netid_wild(struct dhcp_netid *check, struct dhcp_netid *pool)
{
struct dhcp_netid *tmp1;
for (; check; check = check->next)
{
const int check_len = strlen(check->net);
const int is_wc = (check_len > 0 && check->net[check_len - 1] == '*');
/* '#' for not is for backwards compat. */
if (check->net[0] != '!' && check->net[0] != '#')
{
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp(check->net, tmp1->net, check_len-1) == 0) :
(strcmp(check->net, tmp1->net) == 0))
break;
if (!tmp1)
return 0;
}
else
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
if (is_wc ? (strncmp((check->net)+1, tmp1->net, check_len-2) == 0) :
(strcmp((check->net)+1, tmp1->net) == 0))
return 0;
}
return 1;
return (msg->msg_flags & MSG_TRUNC) ? -1 : sz;
}
struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
@@ -114,11 +75,8 @@ struct dhcp_netid *run_tag_if(struct dhcp_netid *tags)
struct tag_if *exprs;
struct dhcp_netid_list *list;
/* this now uses match_netid_wild() above so that tag_if can
* be used to set a 'group of interfaces' tag.
*/
for (exprs = daemon->tag_if; exprs; exprs = exprs->next)
if (match_netid_wild(exprs->tag, tags))
if (match_netid(exprs->tag, tags, 1))
for (list = exprs->set; list; list = list->next)
{
list->list->next = tags;
@@ -133,7 +91,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
{
struct dhcp_netid *tagif = run_tag_if(tags);
struct dhcp_opt *opt;
struct dhcp_opt *tmp;
/* flag options which are valid with the current tag set (sans context tags) */
for (opt = opts; opt; opt = opt->next)
@@ -178,6 +135,7 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
for (opt = opts; opt; opt = opt->next)
if (!(opt->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR | DHOPT_RFC3925 | DHOPT_TAGOK)) && !opt->netid)
{
struct dhcp_opt *tmp;
for (tmp = opts; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt && (tmp->flags & DHOPT_TAGOK))
break;
@@ -187,13 +145,6 @@ struct dhcp_netid *option_filter(struct dhcp_netid *tags, struct dhcp_netid *con
my_syslog(MS_DHCP | LOG_WARNING, _("Ignoring duplicate dhcp-option %d"), tmp->opt);
}
/* Finally, eliminate duplicate options later in the chain, and therefore earlier in the config file. */
for (opt = opts; opt; opt = opt->next)
if (opt->flags & DHOPT_TAGOK)
for (tmp = opt->next; tmp; tmp = tmp->next)
if (tmp->opt == opt->opt)
tmp->flags &= ~DHOPT_TAGOK;
return tagif;
}
@@ -295,139 +246,6 @@ int match_bytes(struct dhcp_opt *o, unsigned char *p, int len)
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
static int is_config_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & (CONFIG_ADDR | CONFIG_ADDR6)))
return 1;
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_V6)
{
struct addrlist *addr_list;
if (config->flags & CONFIG_ADDR6)
for (; context; context = context->current)
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
{
if ((addr_list->flags & ADDRLIST_WILDCARD) && context->prefix == 64)
return 1;
if (is_same_net6(&addr_list->addr.addr6, &context->start6, context->prefix))
return 1;
}
}
else
#endif
{
for (; context; context = context->current)
if ((config->flags & CONFIG_ADDR) && is_same_net(config->addr, context->start, context->netmask))
return 1;
}
return 0;
}
static struct dhcp_config *find_config_match(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname,
struct dhcp_netid *tags, int tag_not_needed)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here. This is IPv4 only. context==NULL implies IPv4,
see lease_update_from_configs() */
if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
}
if (hwaddr)
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
return config;
if (!hwaddr)
return NULL;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_config_in_context(context, config) &&
match_netid(config->filter, tags, tag_not_needed))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
/* Find tagged configs first. */
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname, struct dhcp_netid *tags)
{
struct dhcp_config *ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 0);
if (!ret)
ret = find_config_match(configs, context, clid, clid_len, hwaddr, hw_len, hw_type, hostname, tags, 1);
return ret;
}
void dhcp_update_configs(struct dhcp_config *configs)
{
/* Some people like to keep all static IP addresses in /etc/hosts.
@@ -442,14 +260,8 @@ void dhcp_update_configs(struct dhcp_config *configs)
int prot = AF_INET;
for (config = configs; config; config = config->next)
{
if (config->flags & CONFIG_ADDR_HOSTS)
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR_HOSTS);
#ifdef HAVE_DHCP6
if (config->flags & CONFIG_ADDR6_HOSTS)
config->flags &= ~(CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS);
#endif
}
config->flags &= ~(CONFIG_ADDR | CONFIG_ADDR6 | CONFIG_ADDR_HOSTS);
#ifdef HAVE_DHCP6
again:
@@ -476,45 +288,34 @@ void dhcp_update_configs(struct dhcp_config *configs)
if (cache_find_by_name(crec, config->hostname, 0, cacheflags))
{
/* use primary (first) address */
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
if (!crec)
continue; /* should be never */
inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, daemon->addrbuff);
while (crec && !(crec->flags & F_REVERSE))
crec = cache_find_by_name(crec, config->hostname, 0, cacheflags);
if (!crec)
continue; /* should be never */
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("%s has more than one address in hostsfile, using %s for DHCP"),
config->hostname, daemon->addrbuff);
}
if (prot == AF_INET &&
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr4)) || conf_tmp == config))
(!(conf_tmp = config_find_by_address(configs, crec->addr.addr.addr.addr4)) || conf_tmp == config))
{
config->addr = crec->addr.addr4;
config->addr = crec->addr.addr.addr.addr4;
config->flags |= CONFIG_ADDR | CONFIG_ADDR_HOSTS;
continue;
}
#ifdef HAVE_DHCP6
if (prot == AF_INET6 &&
(!(conf_tmp = config_find_by_address6(configs, NULL, 0, &crec->addr.addr6)) || conf_tmp == config))
(!(conf_tmp = config_find_by_address6(configs, &crec->addr.addr.addr.addr6, 128, 0)) || conf_tmp == config))
{
/* host must have exactly one address if comming from /etc/hosts. */
if (!config->addr6 && (config->addr6 = whine_malloc(sizeof(struct addrlist))))
{
config->addr6->next = NULL;
config->addr6->flags = 0;
}
if (config->addr6 && !config->addr6->next && !(config->addr6->flags & (ADDRLIST_WILDCARD|ADDRLIST_PREFIX)))
{
memcpy(&config->addr6->addr.addr6, &crec->addr.addr6, IN6ADDRSZ);
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR6_HOSTS;
}
memcpy(&config->addr6, &crec->addr.addr.addr.addr6, IN6ADDRSZ);
config->flags |= CONFIG_ADDR6 | CONFIG_ADDR_HOSTS;
continue;
}
#endif
inet_ntop(prot, &crec->addr, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(prot, &crec->addr.addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("duplicate IP address %s (%s) in dhcp-config directive"),
daemon->addrbuff, config->hostname);
@@ -532,84 +333,116 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void)
void bindtodevice(int fd)
{
/* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE
to that device. This is for the use case of (eg) OpenStack, which runs a new
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
individual processes don't always see the packets they should.
SO_BINDTODEVICE is only available Linux.
Note that if wildcards are used in --interface, or --interface is not used at all,
or a configured interface doesn't yet exist, then more interfaces may arrive later,
so we can't safely assert there is only one interface and proceed.
*/
SO_BINDTODEVICE is only available Linux. */
struct irec *iface, *found;
struct iname *if_tmp;
if (!daemon->if_names)
return NULL;
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
return NULL;
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok)
{
if (!found)
found = iface;
else if (strcmp(found->name, iface->name) != 0)
return NULL; /* more than one. */
{
/* more than one. */
found = NULL;
break;
}
}
if (found)
{
char *ret = safe_malloc(strlen(found->name)+1);
strcpy(ret, found->name);
return ret;
struct ifreq ifr;
strcpy(ifr.ifr_name, found->name);
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 &&
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
}
return NULL;
}
static int bindtodevice(char *device, int fd)
{
size_t len = strlen(device)+1;
if (len > IFNAMSIZ)
len = IFNAMSIZ;
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
errno != EPERM)
return 2;
return 1;
}
int bind_dhcp_devices(char *bound_device)
{
int ret = 0;
if (bound_device)
{
if (daemon->dhcp)
{
if (!daemon->relay4)
ret |= bindtodevice(bound_device, daemon->dhcpfd);
if (daemon->enable_pxe && daemon->pxefd != -1)
ret |= bindtodevice(bound_device, daemon->pxefd);
}
#if defined(HAVE_DHCP6)
if (daemon->doing_dhcp6 && !daemon->relay6)
ret |= bindtodevice(bound_device, daemon->dhcp6fd);
#endif
}
return ret;
}
#endif
@@ -663,8 +496,8 @@ static const struct opttab_t {
{ "parameter-request", 55, OT_INTERNAL },
{ "message", 56, OT_INTERNAL },
{ "max-message-size", 57, OT_INTERNAL },
{ "T1", 58, OT_TIME},
{ "T2", 59, OT_TIME},
{ "T1", 58, OT_INTERNAL | OT_TIME},
{ "T2", 59, OT_INTERNAL | OT_TIME},
{ "vendor-class", 60, 0 },
{ "client-id", 61, OT_INTERNAL },
{ "nis+-domain", 64, OT_NAME },
@@ -677,21 +510,16 @@ static const struct opttab_t {
{ "nntp-server", 71, OT_ADDR_LIST },
{ "irc-server", 74, OT_ADDR_LIST },
{ "user-class", 77, 0 },
{ "rapid-commit", 80, 0 },
{ "FQDN", 81, OT_INTERNAL },
{ "agent-id", 82, OT_INTERNAL },
{ "client-arch", 93, 2 | OT_DEC },
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "posix-timezone", 100, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "tzdb-timezone", 101, OT_NAME }, /* RFC 4833, Sec. 2 */
{ "ipv6-only", 108, 4 | OT_DEC }, /* RFC 8925 */
{ "subnet-select", 118, OT_INTERNAL },
{ "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "vendor-id-encap", 125, 0 },
{ "tftp-server-address", 150, OT_ADDR_LIST },
{ "server-ip-address", 255, OT_ADDR_LIST }, /* special, internal only, sets siaddr */
{ NULL, 0, 0 }
};
@@ -722,7 +550,7 @@ static const struct opttab_t opttab6[] = {
{ "sntp-server", 31, OT_ADDR_LIST },
{ "information-refresh-time", 32, OT_TIME },
{ "FQDN", 39, OT_INTERNAL | OT_RFC1035_NAME },
{ "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
{ "ntp-server", 56, OT_ADDR_LIST },
{ "bootfile-url", 59, OT_NAME },
{ "bootfile-param", 60, OT_CSTRING },
{ NULL, 0, 0 }
@@ -754,13 +582,11 @@ void display_opts6(void)
}
#endif
int lookup_dhcp_opt(int prot, char *name)
u16 lookup_dhcp_opt(int prot, char *name)
{
const struct opttab_t *t;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -769,19 +595,18 @@ int lookup_dhcp_opt(int prot, char *name)
t = opttab;
for (i = 0; t[i].name; i++)
if (strcasecmp(t[i].name, name) == 0)
if (!(t[i].size & OT_INTERNAL) &&
strcasecmp(t[i].name, name) == 0)
return t[i].val;
return -1;
return 0;
}
int lookup_dhcp_len(int prot, int val)
u16 lookup_dhcp_len(int prot, u16 val)
{
const struct opttab_t *t;
int i;
(void)prot;
#ifdef HAVE_DHCP6
if (prot == AF_INET6)
t = opttab6;
@@ -791,9 +616,14 @@ int lookup_dhcp_len(int prot, int val)
for (i = 0; t[i].name; i++)
if (val == t[i].val)
return t[i].size & ~OT_DEC;
return 0;
{
if (t[i].size & OT_INTERNAL)
return 0;
return t[i].size & ~OT_DEC;
}
return 0;
}
char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len, char *buf, int buf_len)
@@ -815,7 +645,7 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
if (ot[o].size & OT_ADDR_LIST)
{
union all_addr addr;
struct all_addr addr;
int addr_len = INADDRSZ;
#ifdef HAVE_DHCP6
@@ -920,132 +750,4 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
}
void log_context(int family, struct dhcp_context *context)
{
/* Cannot use dhcp_buff* for RA contexts */
void *start = &context->start;
void *end = &context->end;
char *template = "", *p = daemon->namebuff;
*p = 0;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
struct in6_addr subnet = context->start6;
if (!(context->flags & CONTEXT_TEMPLATE))
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
start = &context->start6;
end = &context->end6;
}
#endif
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _(", prefix deprecated"));
else
{
p += sprintf(p, _(", lease time "));
prettyprint_time(p, context->lease_time);
p += strlen(p);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_CONSTRUCTED)
{
char ifrn_name[IFNAMSIZ];
template = p;
p += sprintf(p, ", ");
if (indextoname(daemon->icmp6fd, context->if_index, ifrn_name))
sprintf(p, "%s for %s", (context->flags & CONTEXT_OLD) ? "old prefix" : "constructed", ifrn_name);
}
else if (context->flags & CONTEXT_TEMPLATE && !(context->flags & CONTEXT_RA_STATELESS))
{
template = p;
p += sprintf(p, ", ");
sprintf(p, "template for %s", context->template_interface);
}
#endif
if (!(context->flags & CONTEXT_OLD) &&
((context->flags & CONTEXT_DHCP) || family == AF_INET))
{
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_STATELESS)
{
if (context->flags & CONTEXT_TEMPLATE)
strncpy(daemon->dhcp_buff, context->template_interface, DHCP_BUFF_SZ);
else
strcpy(daemon->dhcp_buff, daemon->addrbuff);
}
else
#endif
inet_ntop(family, start, daemon->dhcp_buff, DHCP_BUFF_SZ);
inet_ntop(family, end, daemon->dhcp_buff3, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s%s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s%.0s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s%.0s") :
_("%s, IP range %s -- %s%s%.0s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff, template);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_TEMPLATE)
{
strcpy(daemon->addrbuff, context->template_interface);
template = "";
}
if ((context->flags & CONTEXT_RA_NAME) && !(context->flags & CONTEXT_OLD))
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"), daemon->addrbuff, template);
if ((context->flags & CONTEXT_RA) || (option_bool(OPT_RA) && (context->flags & CONTEXT_DHCP) && family == AF_INET6))
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s"), daemon->addrbuff, template);
#endif
}
void log_relay(int family, struct dhcp_relay *relay)
{
int broadcast = relay->server.addr4.s_addr == 0;
inet_ntop(family, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(family, &relay->server, daemon->namebuff, ADDRSTRLEN);
if (family == AF_INET && relay->port != DHCP_SERVER_PORT)
sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
#ifdef HAVE_DHCP6
struct in6_addr multicast;
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
if (family == AF_INET6)
{
broadcast = IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast);
if (relay->port != DHCPV6_SERVER_PORT)
sprintf(daemon->namebuff + strlen(daemon->namebuff), "#%u", relay->port);
}
#endif
if (relay->interface)
{
if (broadcast)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s via %s"), daemon->addrbuff, relay->interface);
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, relay->interface);
}
else
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s"), daemon->addrbuff, daemon->namebuff);
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,10 +19,6 @@
#define DHCP_CLIENT_ALTPORT 1068
#define PXE_PORT 4011
/* These each hold a DHCP option max size 255
and get a terminating zero added */
#define DHCP_BUFF_SZ 256
#define BOOTREQUEST 1
#define BOOTREPLY 2
#define DHCP_COOKIE 0x63825363
@@ -54,7 +50,6 @@
#define OPTION_SNAME 66
#define OPTION_FILENAME 67
#define OPTION_USER_CLASS 77
#define OPTION_RAPID_COMMIT 80
#define OPTION_CLIENT_FQDN 81
#define OPTION_AGENT_ID 82
#define OPTION_ARCH 93
@@ -64,7 +59,6 @@
#define OPTION_SIP_SERVER 120
#define OPTION_VENDOR_IDENT 124
#define OPTION_VENDOR_IDENT_OPT 125
#define OPTION_MUD_URL_V4 161
#define OPTION_END 255
#define SUBOPT_CIRCUIT_ID 1

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,12 +28,10 @@ struct match_param {
struct in_addr netmask, broadcast, addr;
};
static int complete_context(struct in_addr local, int if_index, char *label,
static int complete_context(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
static int check_listen_addrs(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz);
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface);
static int make_fd(int port)
{
@@ -65,24 +63,16 @@ static int make_fd(int port)
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &oneopt, sizeof(oneopt)) == -1)
die(_("failed to set options on DHCP socket: %s"), NULL, EC_BADNET);
/* When bind-interfaces is set, there might be more than one dnsmasq
/* 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|REUSEPORT to make this possible.
Handle the case that REUSEPORT is defined, but the kernel doesn't
support it. This handles the introduction of REUSEPORT on Linux. */
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno == ENOPROTOOPT)
rc = 0;
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
#else
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
#endif
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCP socket: %s"), NULL, EC_BADNET);
}
@@ -134,8 +124,6 @@ void dhcp_packet(time_t now, int pxe_fd)
int fd = pxe_fd ? daemon->pxefd : daemon->dhcpfd;
struct dhcp_packet *mess;
struct dhcp_context *context;
struct dhcp_relay *relay;
int is_relay_reply = 0;
struct iname *tmp;
struct ifreq ifr;
struct msghdr msg;
@@ -143,14 +131,11 @@ void dhcp_packet(time_t now, int pxe_fd)
struct cmsghdr *cmptr;
struct iovec iov;
ssize_t sz;
int iface_index = 0, unicast_dest = 0, is_inform = 0, loopback = 0;
int rcvd_iface_index;
int iface_index = 0, unicast_dest = 0, is_inform = 0;
struct in_addr iface_addr;
struct iface_param parm;
time_t recvtime = now;
#ifdef HAVE_LINUX_NETWORK
struct arpreq arp_req;
struct timeval tv;
#endif
union {
@@ -175,15 +160,8 @@ void dhcp_packet(time_t now, int pxe_fd)
if ((sz = recv_dhcp_packet(fd, &msg)) == -1 ||
(sz < (ssize_t)(sizeof(*mess) - sizeof(mess->options))))
return;
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL, fd);
#endif
#if defined (HAVE_LINUX_NETWORK)
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
recvtime = tv.tv_sec;
#if defined (HAVE_LINUX_NETWORK)
if (msg.msg_controllen >= sizeof(struct cmsghdr))
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO)
@@ -225,39 +203,31 @@ void dhcp_packet(time_t now, int pxe_fd)
}
#endif
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name) ||
ioctl(daemon->dhcpfd, SIOCGIFFLAGS, &ifr) != 0)
if (!indextoname(daemon->dhcpfd, iface_index, ifr.ifr_name))
return;
mess = (struct dhcp_packet *)daemon->dhcp_packet.iov_base;
loopback = !mess->giaddr.s_addr && (ifr.ifr_flags & IFF_LOOPBACK);
#ifdef HAVE_LINUX_NETWORK
/* ARP fiddling uses original interface even if we pretend to use a different one. */
safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
#endif
/* If the interface on which the DHCP request was received is an
alias of some other interface (as specified by the
--bridge-interface option), change ifr.ifr_name so that we look
for DHCP contexts associated with the aliased interface instead
of with the aliasing one. */
rcvd_iface_index = iface_index;
/* One form of bridging on BSD has the property that packets
can be recieved on bridge interfaces which do not have an IP address.
We allow these to be treated as aliases of another interface which does have
an IP address with --dhcp-bridge=interface,alias,alias */
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
if (strncmp(ifr.ifr_name, alias->iface, IF_NAMESIZE) == 0)
{
if (!(iface_index = if_nametoindex(bridge->iface)))
{
my_syslog(MS_DHCP | LOG_WARNING,
_("unknown interface %s in bridge-interface"),
bridge->iface);
my_syslog(LOG_WARNING, _("unknown interface %s in bridge-interface"), ifr.ifr_name);
return;
}
else
{
safe_strncpy(ifr.ifr_name, bridge->iface, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, bridge->iface, IF_NAMESIZE);
break;
}
}
@@ -272,87 +242,58 @@ void dhcp_packet(time_t now, int pxe_fd)
unicast_dest = 1;
#endif
if ((relay = relay_reply4((struct dhcp_packet *)daemon->dhcp_packet.iov_base, ifr.ifr_name)))
{
/* Reply from server, using us as relay. */
rcvd_iface_index = relay->iface_index;
if (!indextoname(daemon->dhcpfd, rcvd_iface_index, ifr.ifr_name))
return;
is_relay_reply = 1;
iov.iov_len = sz;
#ifdef HAVE_LINUX_NETWORK
safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
#endif
}
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
else
{
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(daemon->dhcpfd, SIOCGIFADDR, &ifr) != -1 )
iface_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
else
{
if (iface_check(AF_INET, NULL, ifr.ifr_name, NULL))
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
/* unlinked contexts/relays are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
parm.current = NULL;
parm.ind = iface_index;
if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
match.matched = 0;
match.ind = iface_index;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
if (relay_upstream4(iface_index, mess, (size_t)sz))
return;
if (!iface_enumerate(AF_INET, &parm, complete_context))
return;
/* Check for a relay again after iface_enumerate/complete_context has had
chance to fill in relay->iface_index fields. This handles first time through
and any changes in interface config. */
if (relay_upstream4(iface_index, mess, (size_t)sz))
return;
/* May have configured relay, but not DHCP server */
if (!daemon->dhcp)
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, loopback, &is_inform, pxe_fd, iface_addr, recvtime);
lease_update_file(now);
lease_update_dns(0);
if (iov.iov_len == 0)
return;
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP packet received on %s which has no address"), ifr.ifr_name);
return;
}
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
/* unlinked contexts are marked by context->current == context */
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
parm.current = NULL;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */
struct match_param match;
match.matched = 0;
match.ind = iface_index;
if (!daemon->if_addrs ||
!iface_enumerate(AF_INET, &match, check_listen_addrs) ||
!match.matched)
return;
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
}
if (!iface_enumerate(AF_INET, &parm, complete_context))
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, iface_addr);
lease_update_file(now);
lease_update_dns(0);
if (iov.iov_len == 0)
return;
msg.msg_name = &dest;
msg.msg_namelen = sizeof(dest);
msg.msg_control = NULL;
@@ -372,7 +313,7 @@ void dhcp_packet(time_t now, int pxe_fd)
if (mess->ciaddr.s_addr != 0)
dest.sin_addr = mess->ciaddr;
}
else if (mess->giaddr.s_addr && !is_relay_reply)
else if (mess->giaddr.s_addr)
{
/* Send to BOOTP relay */
dest.sin_port = htons(daemon->dhcp_server_port);
@@ -385,49 +326,42 @@ void dhcp_packet(time_t now, int pxe_fd)
source port too, and send back to that. If we're replying
to a DHCPINFORM, trust the source address always. */
if ((!is_inform && dest.sin_addr.s_addr != mess->ciaddr.s_addr) ||
dest.sin_port == 0 || dest.sin_addr.s_addr == 0 || is_relay_reply)
dest.sin_port == 0 || dest.sin_addr.s_addr == 0)
{
dest.sin_port = htons(daemon->dhcp_client_port);
dest.sin_addr = mess->ciaddr;
}
}
#if defined(HAVE_LINUX_NETWORK)
else
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{
/* fill cmsg for outbound interface (both broadcast & unicast) */
/* broadcast to 255.255.255.255 (or mac address invalid) */
struct in_pktinfo *pkt;
msg.msg_control = control_u.control;
msg.msg_controllen = sizeof(control_u);
cmptr = CMSG_FIRSTHDR(&msg);
pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
pkt->ipi_ifindex = rcvd_iface_index;
pkt->ipi_ifindex = iface_index;
pkt->ipi_spec_dst.s_addr = 0;
msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
cmptr->cmsg_level = IPPROTO_IP;
cmptr->cmsg_type = IP_PKTINFO;
if ((ntohs(mess->flags) & 0x8000) || mess->hlen == 0 ||
mess->hlen > sizeof(ifr.ifr_addr.sa_data) || mess->htype == 0)
{
/* broadcast to 255.255.255.255 (or mac address invalid) */
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
struct sockaddr limits size to 14 bytes. */
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
arp_req.arp_ha.sa_family = mess->htype;
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
/* interface name already copied in */
arp_req.arp_flags = ATF_COM;
if (ioctl(daemon->dhcpfd, SIOCSARP, &arp_req) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("ARP-cache injection failed: %s"), strerror(errno));
}
cmptr->cmsg_type = IP_PKTINFO;
dest.sin_addr.s_addr = INADDR_BROADCAST;
dest.sin_port = htons(daemon->dhcp_client_port);
}
else
{
/* unicast to unconfigured client. Inject mac address direct into ARP cache.
struct sockaddr limits size to 14 bytes. */
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
memcpy(&arp_req.arp_pa, &dest, sizeof(struct sockaddr_in));
arp_req.arp_ha.sa_family = mess->htype;
memcpy(arp_req.arp_ha.sa_data, mess->chaddr, mess->hlen);
/* interface name already copied in */
arp_req.arp_flags = ATF_COM;
ioctl(daemon->dhcpfd, SIOCSARP, &arp_req);
}
#elif defined(HAVE_SOLARIS_NETWORK)
else if ((ntohs(mess->flags) & 0x8000) || mess->hlen != ETHER_ADDR_LEN || mess->htype != ARPHRD_ETHER)
@@ -456,17 +390,6 @@ void dhcp_packet(time_t now, int pxe_fd)
#elif defined(HAVE_BSD_NETWORK)
else
{
#ifdef HAVE_DUMPFILE
if (ntohs(mess->flags) & 0x8000)
dest.sin_addr.s_addr = INADDR_BROADCAST;
else
dest.sin_addr = mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
(union mysockaddr *)&dest, fd);
#endif
send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
return;
}
@@ -475,32 +398,17 @@ void dhcp_packet(time_t now, int pxe_fd)
#ifdef HAVE_SOLARIS_NETWORK
setsockopt(fd, IPPROTO_IP, IP_BOUND_IF, &iface_index, sizeof(iface_index));
#endif
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
(union mysockaddr *)&dest, fd);
#endif
while(retry_send(sendmsg(fd, &msg, 0)));
/* This can fail when, eg, iptables DROPS destination 255.255.255.255 */
if (errno != 0)
{
inet_ntop(AF_INET, &dest.sin_addr, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("Error sending DHCP packet to %s: %s"),
daemon->addrbuff, strerror(errno));
}
while(sendmsg(fd, &msg, 0) == -1 && retry_send());
}
/* check against secondary interface addresses */
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
static int check_listen_addrs(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct match_param *param = vparam;
struct iname *tmp;
(void) label;
if (if_index == param->ind)
{
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
@@ -526,86 +434,32 @@ static int check_listen_addrs(struct in_addr local, int if_index, char *label,
3) Fills in local (this host) and router (this host or relay) addresses.
4) Links contexts which are valid for hosts directly connected to the arrival interface on ->current.
Note that the current chain may be superseded later for configured hosts or those coming via gateways. */
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
static void guess_range_netmask(struct in_addr addr, struct in_addr netmask)
{
struct dhcp_context *context;
for (context = daemon->dhcp; context; context = context->next)
if (!(context->flags & CONTEXT_NETMASK) &&
(is_same_net(addr, context->start, netmask) ||
is_same_net(addr, context->end, netmask)))
{
if (context->netmask.s_addr != netmask.s_addr &&
!(is_same_net(addr, context->start, netmask) &&
is_same_net(addr, context->end, netmask)))
{
inet_ntop(AF_INET, &context->start, daemon->dhcp_buff, DHCP_BUFF_SZ);
inet_ntop(AF_INET, &context->end, daemon->dhcp_buff2, DHCP_BUFF_SZ);
inet_ntop(AF_INET, &netmask, daemon->addrbuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, daemon->addrbuff);
}
context->netmask = netmask;
}
}
static int complete_context(struct in_addr local, int if_index, char *label,
static int complete_context(struct in_addr local, int if_index,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct shared_network *share;
(void)label;
for (share = daemon->shared_networks; share; share = share->next)
{
#ifdef HAVE_DHCP6
if (share->shared_addr.s_addr == 0)
continue;
#endif
if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (share->match_addr.s_addr != local.s_addr)
continue;
}
for (context = daemon->dhcp; context; context = context->next)
{
if (context->netmask.s_addr != 0 &&
is_same_net(share->shared_addr, context->start, context->netmask) &&
is_same_net(share->shared_addr, context->end, context->netmask))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
/* For a shared network, we have no way to guess what the default route should be. */
context->router.s_addr = 0;
context->local = local; /* Use configured address for Server Identifier */
context->current = param->current;
param->current = context;
}
if (!(context->flags & CONTEXT_BRDCAST))
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
}
}
}
guess_range_netmask(local, netmask);
for (context = daemon->dhcp; context; context = context->next)
{
if (!(context->flags & CONTEXT_NETMASK) &&
(is_same_net(local, context->start, netmask) ||
is_same_net(local, context->end, netmask)))
{
if (context->netmask.s_addr != netmask.s_addr &&
!(is_same_net(local, context->start, netmask) &&
is_same_net(local, context->end, netmask)))
{
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"),
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask));
}
context->netmask = netmask;
}
if (context->netmask.s_addr != 0 &&
is_same_net(local, context->start, context->netmask) &&
is_same_net(local, context->end, context->netmask))
@@ -629,10 +483,6 @@ static int complete_context(struct in_addr local, int if_index, char *label,
}
}
for (relay = daemon->relay4; relay; relay = relay->next)
if (relay->local.addr4.s_addr == local.s_addr)
relay->iface_index = if_index;
return 1;
}
@@ -672,7 +522,7 @@ struct dhcp_context *narrow_context(struct dhcp_context *context,
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context corresponding to that
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
@@ -714,69 +564,9 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
return NULL;
}
/* Check if and address is in use by sending ICMP ping.
This wrapper handles a cache and load-limiting.
Return is NULL is address in use, or a pointer to a cache entry
recording that it isn't. */
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash, int loopback)
{
static struct ping_result dummy;
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
((float)PING_WAIT)));
/* 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
on us repeatedly. As a final check, if we did more
than 60% of the possible ping checks in the last
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */
else
{
count++;
if (r->addr.s_addr == addr.s_addr)
return r;
}
/* didn't find cached entry */
if ((count >= max) || option_bool(OPT_NO_PING) || loopback)
{
/* overloaded, or configured not to check, loopback interface, return "not in use" */
dummy.hash = hash;
return &dummy;
}
else if (icmp_ping(addr))
return NULL; /* address in use. */
else
{
/* at this point victim may hold an expired record */
if (!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 = hash;
}
return victim;
}
}
int address_allocate(struct dhcp_context *context,
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
struct dhcp_netid *netids, time_t now, int loopback)
struct dhcp_netid *netids, time_t now)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -790,11 +580,7 @@ int address_allocate(struct dhcp_context *context,
/* hash hwaddr: use the SDBM hashing algorithm. Seems to give good
dispersal even with similarly-valued "strings". */
for (j = 0, i = 0; i < hw_len; i++)
j = hwaddr[i] + (j << 6) + (j << 16) - j;
/* j == 0 is marker */
if (j == 0)
j = 1;
j += hwaddr[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
@@ -832,36 +618,69 @@ int address_allocate(struct dhcp_context *context,
(!IN_CLASSC(ntohl(addr.s_addr)) ||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
{
/* in consec-ip mode, skip addresses equal to
the number of addresses rejected by clients. This
should avoid the same client being offered the same
address after it has rjected it. */
if (option_bool(OPT_CONSEC_ADDR) && c->addr_epoch)
c->addr_epoch--;
else
struct ping_result *r, *victim = NULL;
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
((float)PING_WAIT)));
*addrp = addr;
/* 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
on us repeatedly. As a final check, if we did more
than 60% of the possible ping checks in the last
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
for (count = 0, r = daemon->ping_results; r; r = r->next)
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
victim = r; /* old record */
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)
{
struct ping_result *r;
if ((r = do_icmp_ping(now, addr, j, loopback)))
{
/* 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)
{
*addrp = addr;
return 1;
}
}
else
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
{
/* 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)
{
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;
}
}
}
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
if (addr.s_addr == htonl(ntohl(c->end.s_addr) + 1))
@@ -873,6 +692,89 @@ int address_allocate(struct dhcp_context *context,
return 0;
}
static int is_addr_in_context(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR))
return 1;
for (; context; context = context->current)
if (is_same_net(config->addr, context->start, context->netmask))
return 1;
return 0;
}
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type)
{
struct hwaddr_config *conf_addr;
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask == 0 &&
conf_addr->hwaddr_len == len &&
(conf_addr->hwaddr_type == type || conf_addr->hwaddr_type == 0) &&
memcmp(conf_addr->hwaddr, hwaddr, len) == 0)
return 1;
return 0;
}
struct dhcp_config *find_config(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *clid, int clid_len,
unsigned char *hwaddr, int hw_len,
int hw_type, char *hostname)
{
int count, new;
struct dhcp_config *config, *candidate;
struct hwaddr_config *conf_addr;
if (clid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == clid_len &&
memcmp(config->clid, clid, clid_len) == 0 &&
is_addr_in_context(context, config))
return config;
/* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
cope with that here */
if (*clid == 0 && config->clid_len == clid_len-1 &&
memcmp(config->clid, clid+1, clid_len-1) == 0 &&
is_addr_in_context(context, config))
return config;
}
for (config = configs; config; config = config->next)
if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
is_addr_in_context(context, config))
return config;
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_addr_in_context(context, config))
return config;
/* use match with fewest wildcard octets */
for (candidate = NULL, count = 0, config = configs; config; config = config->next)
if (is_addr_in_context(context, config))
for (conf_addr = config->hwaddr; conf_addr; conf_addr = conf_addr->next)
if (conf_addr->wildcard_mask != 0 &&
conf_addr->hwaddr_len == hw_len &&
(conf_addr->hwaddr_type == hw_type || conf_addr->hwaddr_type == 0) &&
(new = memcmp_masked(conf_addr->hwaddr, hwaddr, hw_len, conf_addr->wildcard_mask)) > count)
{
count = new;
candidate = config;
}
return candidate;
}
void dhcp_read_ethers(void)
{
FILE *f = fopen(ETHERSFILE, "r");
@@ -938,7 +840,7 @@ void dhcp_read_ethers(void)
if (!*cp)
{
if (inet_pton(AF_INET, ip, &addr.s_addr) < 1)
if ((addr.s_addr = inet_addr(ip)) == (in_addr_t)-1)
{
my_syslog(MS_DHCP | LOG_ERR, _("bad address at %s line %d"), ETHERSFILE, lineno);
continue;
@@ -1047,7 +949,7 @@ char *host_from_dns(struct in_addr addr)
if (daemon->port == 0)
return NULL; /* DNS disabled. */
lookup = cache_find_by_addr(NULL, (union all_addr *)&addr, 0, F_IPV4);
lookup = cache_find_by_addr(NULL, (struct all_addr *)&addr, 0, F_IPV4);
if (lookup && (lookup->flags & F_HOSTS))
{
@@ -1064,7 +966,8 @@ char *host_from_dns(struct in_addr addr)
if (!legal_hostname(hostname))
return NULL;
safe_strncpy(daemon->dhcp_buff, hostname, 256);
strncpy(daemon->dhcp_buff, hostname, 256);
daemon->dhcp_buff[255] = 0;
strip_hostname(daemon->dhcp_buff);
return daemon->dhcp_buff;
@@ -1073,118 +976,5 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
{
struct in_addr giaddr = mess->giaddr;
u8 hops = mess->hops;
struct dhcp_relay *relay;
if (mess->op != BOOTREQUEST)
return 0;
for (relay = daemon->relay4; relay; relay = relay->next)
if (relay->iface_index != 0 && relay->iface_index == iface_index)
break;
/* No relay config. */
if (!relay)
return 0;
for (; relay; relay = relay->next)
if (relay->iface_index != 0 && relay->iface_index == iface_index)
{
union mysockaddr to;
union all_addr from;
mess->hops = hops;
mess->giaddr = giaddr;
if ((mess->hops++) > 20)
continue;
/* source address == relay address */
from.addr4 = relay->local.addr4;
/* already gatewayed ? */
if (giaddr.s_addr)
{
/* if so check if by us, to stomp on loops. */
if (giaddr.s_addr == relay->local.addr4.s_addr)
continue;
}
else
{
/* plug in our address */
mess->giaddr.s_addr = relay->local.addr4.s_addr;
}
to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr4;
to.in.sin_port = htons(relay->port);
/* Broadcasting to server. */
if (relay->server.addr4.s_addr == 0)
{
struct ifreq ifr;
if (relay->interface)
safe_strncpy(ifr.ifr_name, relay->interface, IF_NAMESIZE);
if (!relay->interface || strchr(relay->interface, '*') ||
ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) == -1)
{
my_syslog(MS_DHCP | LOG_ERR, _("Cannot broadcast DHCP relay via interface %s"), relay->interface);
continue;
}
to.in.sin_addr = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
}
#ifdef HAVE_DUMPFILE
{
union mysockaddr fromsock;
fromsock.in.sin_port = htons(daemon->dhcp_server_port);
fromsock.in.sin_addr = from.addr4;
fromsock.sa.sa_family = AF_INET;
dump_packet_udp(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, -1);
}
#endif
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
if (relay->server.addr4.s_addr == 0)
snprintf(daemon->dhcp_buff2, DHCP_BUFF_SZ, _("broadcast via %s"), relay->interface);
else
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
}
}
return 1;
}
static struct dhcp_relay *relay_reply4(struct dhcp_packet *mess, char *arrival_interface)
{
struct dhcp_relay *relay;
if (mess->giaddr.s_addr == 0 || mess->op != BOOTREPLY)
return NULL;
for (relay = daemon->relay4; relay; relay = relay->next)
{
if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
{
if (!relay->interface || wildcard_match(relay->interface, arrival_interface))
return relay->iface_index != 0 ? relay : NULL;
}
}
return NULL;
}
#endif

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -55,19 +55,9 @@
#define OPTION6_RECONF_ACCEPT 20
#define OPTION6_DNS_SERVER 23
#define OPTION6_DOMAIN_SEARCH 24
#define OPTION6_IA_PD 25
#define OPTION6_IAPREFIX 26
#define OPTION6_REFRESH_TIME 32
#define OPTION6_REMOTE_ID 37
#define OPTION6_SUBSCRIBER_ID 38
#define OPTION6_FQDN 39
#define OPTION6_NTP_SERVER 56
#define OPTION6_CLIENT_MAC 79
#define OPTION6_MUD_URL 112
#define NTP_SUBOPTION_SRV_ADDR 1
#define NTP_SUBOPTION_MC_ADDR 2
#define NTP_SUBOPTION_SRV_FQDN 3
#define DHCP6SUCCESS 0
#define DHCP6UNSPEC 1
@@ -75,3 +65,4 @@
#define DHCP6NOBINDING 3
#define DHCP6NOTONLINK 4
#define DHCP6USEMULTI 5

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,18 +18,15 @@
#ifdef HAVE_DHCP6
#include <netinet/icmp6.h>
struct iface_param {
struct dhcp_context *current;
struct in6_addr fallback, ll_addr, ula_addr;
struct in6_addr fallback;
int ind, addr_match;
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
int scope, int if_index, int dad, void *vparam);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
void dhcp6_init(void)
@@ -50,24 +47,16 @@ void dhcp6_init(void)
!set_ipv6pktinfo(fd))
die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
/* When bind-interfaces is set, there might be more than one dnsmasq
/* When bind-interfaces is set, there might be more than one dnmsasq
instance binding port 547. That's OK if they serve different networks.
Need to set REUSEADDR|REUSEPORT to make this possible.
Handle the case that REUSEPORT is defined, but the kernel doesn't
support it. This handles the introduction of REUSEPORT on Linux. */
Need to set REUSEADDR to make this posible, or REUSEPORT on *BSD. */
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
{
int rc = 0;
#ifdef SO_REUSEPORT
if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
errno == ENOPROTOOPT)
rc = 0;
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt));
#else
int rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
#endif
if (rc != -1)
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
if (rc == -1)
die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
}
@@ -102,10 +91,6 @@ void dhcp6_packet(time_t now)
struct ifreq ifr;
struct iname *tmp;
unsigned short port;
struct in6_addr dst_addr;
struct in6_addr all_servers;
memset(&dst_addr, 0, sizeof(dst_addr));
msg.msg_control = control_u.control6;
msg.msg_controllen = sizeof(control_u);
@@ -118,11 +103,6 @@ void dhcp6_packet(time_t now)
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
return;
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz,
(union mysockaddr *)&from, NULL, daemon->dhcp6fd);
#endif
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
@@ -133,318 +113,135 @@ void dhcp6_packet(time_t now)
p.c = CMSG_DATA(cmptr);
if_index = p.p->ipi6_ifindex;
dst_addr = p.p->ipi6_addr;
}
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
if (relay_reply6(&from, sz, ifr.ifr_name))
{
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL,
(union mysockaddr *)&from, daemon->dhcp6fd);
#endif
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
}
else
{
struct dhcp_bridge *bridge, *alias;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
return;
parm.current = NULL;
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
memset(&parm.ll_addr, 0, IN6ADDRSZ);
memset(&parm.ula_addr, 0, IN6ADDRSZ);
/* If the interface on which the DHCPv6 request was received is
an alias of some other interface (as specified by the
--bridge-interface option), change parm.ind so that we look
for DHCPv6 contexts associated with the aliased interface
instead of with the aliasing one. */
for (bridge = daemon->bridges; bridge; bridge = bridge->next)
{
for (alias = bridge->alias; alias; alias = alias->next)
if (wildcard_matchn(alias->iface, ifr.ifr_name, IF_NAMESIZE))
{
parm.ind = if_nametoindex(bridge->iface);
if (!parm.ind)
{
my_syslog(MS_DHCP | LOG_WARNING,
_("unknown interface %s in bridge-interface"),
bridge->iface);
return;
}
break;
}
if (alias)
break;
}
for (context = daemon->dhcp6; context; context = context->next)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
we're listening there for DHCPv6 server reasons. */
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers) &&
relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
return;
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
/* Check for a relay again after iface_enumerate/complete_context has had
chance to fill in relay->iface_index fields. This handles first time through
and any changes in interface config. */
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers) &&
relay_upstream6(if_index, (size_t)sz, &from.sin6_addr, from.sin6_scope_id, now))
return;
if (daemon->if_names || daemon->if_addrs)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
break;
if (!tmp && !parm.addr_match)
return;
}
/* May have configured relay, but not DHCP server */
if (!daemon->doing_dhcp6)
return;
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
&parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
server port to a relay. */
if (port != 0)
{
from.sin6_port = htons(port);
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1),
NULL, (union mysockaddr *)&from, daemon->dhcp6fd);
#endif
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from, sizeof(from))));
}
/* These need to be called _after_ we send DHCPv6 packet, since lease_update_file()
may trigger sending an RA packet, which overwrites our buffer. */
lease_update_file(now);
lease_update_dns(0);
}
}
void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep, time_t now)
{
/* Receiving a packet from a host does not populate the neighbour
cache, so we send a neighbour discovery request if we can't
find the sender. Repeat a few times in case of packet loss. */
struct neigh_packet neigh;
union mysockaddr addr;
int i, maclen;
neigh.type = ND_NEIGHBOR_SOLICIT;
neigh.code = 0;
neigh.reserved = 0;
neigh.target = *client;
/* RFC4443 section-2.3: checksum has to be zero to be calculated */
neigh.checksum = 0;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
#endif
addr.in6.sin6_family = AF_INET6;
addr.in6.sin6_port = htons(IPPROTO_ICMPV6);
addr.in6.sin6_addr = *client;
addr.in6.sin6_scope_id = iface;
for (i = 0; i < 5; i++)
{
struct timespec ts;
if ((maclen = find_mac(&addr, mac, 0, now)) != 0)
break;
while(retry_send(sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, &addr.sa, sizeof(addr))));
ts.tv_sec = 0;
ts.tv_nsec = 100000000; /* 100ms */
nanosleep(&ts, NULL);
}
*maclenp = maclen;
*mactypep = ARPHRD_ETHER;
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int flags, unsigned int preferred,
unsigned int valid, void *vparam)
{
struct dhcp_context *context;
struct shared_network *share;
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
int match = !daemon->if_addrs;
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
return;
(void)scope; /* warning */
if (if_index != param->ind)
return 1;
if (IN6_IS_ADDR_LINKLOCAL(local))
param->ll_addr = *local;
else if (IN6_IS_ADDR_ULA(local))
param->ula_addr = *local;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
match = param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
parm.current = NULL;
parm.ind = if_index;
parm.addr_match = 0;
memset(&parm.fallback, 0, IN6ADDRSZ);
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_DHCP) &&
!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
prefix <= context->prefix &&
context->current == context)
if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
{
if (is_same_net6(local, &context->start6, context->prefix) &&
is_same_net6(local, &context->end6, context->prefix))
{
struct dhcp_context *tmp, **up;
/* use interface values only for constructed contexts */
if (!(context->flags & CONTEXT_CONSTRUCTED))
preferred = valid = 0xffffffff;
else if (flags & IFACE_DEPRECATED)
preferred = 0;
if (context->flags & CONTEXT_DEPRECATE)
preferred = 0;
/* order chain, longest preferred time first */
for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
if (tmp->preferred <= preferred)
break;
else
up = &tmp->current;
context->current = *up;
*up = context;
context->local6 = *local;
context->preferred = preferred;
context->valid = valid;
}
else
{
for (share = daemon->shared_networks; share; share = share->next)
{
/* IPv4 shared_address - ignore */
if (share->shared_addr.s_addr != 0)
continue;
if (share->if_index != 0)
{
if (share->if_index != if_index)
continue;
}
else
{
if (!IN6_ARE_ADDR_EQUAL(&share->match_addr6, local))
continue;
}
if (is_same_net6(&share->shared_addr6, &context->start6, context->prefix) &&
is_same_net6(&share->shared_addr6, &context->end6, context->prefix))
{
context->current = param->current;
param->current = context;
context->local6 = *local;
context->preferred = context->flags & CONTEXT_DEPRECATE ? 0 :0xffffffff;
context->valid = 0xffffffff;
}
}
}
/* wildcard context for DHCP-stateless only */
parm.current = context;
context->current = NULL;
}
else
{
/* unlinked contexts are marked by context->current == context */
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
if (match)
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
relay->iface_index = if_index;
if (!iface_enumerate(AF_INET6, &parm, complete_context6))
return;
if (daemon->if_names || daemon->if_addrs)
{
for (tmp = daemon->if_names; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
break;
if (!tmp && !parm.addr_match)
return;
}
lease_prune(NULL, now); /* lose any expired leases */
port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,
sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
lease_update_file(now);
lease_update_dns(0);
/* The port in the source address of the original request should
be correct, but at least once client sends from the server port,
so we explicitly send to the client port to a client, and the
server port to a relay. */
if (port != 0)
{
from.sin6_port = htons(port);
while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0),
0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
retry_send());
}
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
(void)dad;
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
/* if we have --listen-address config, see if the
arrival interface has a matching address. */
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
param->addr_match = 1;
/* Determine a globally address on the arrival interface, even
if we have no matching dhcp-context, because we're only
allocating on remote subnets via relays. This
is used as a default for the DNS server option. */
param->fallback = *local;
for (context = daemon->dhcp6; context; context = context->next)
{
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
/* link it onto the current chain if we've not seen it before */
if (context->current == context)
{
context->current = param->current;
param->current = context;
context->local6 = *local;
}
}
}
}
return 1;
}
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, struct in6_addr *addr)
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
{
struct dhcp_config *config;
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_ADDR6)
{
struct addrlist *addr_list;
for (addr_list = config->addr6; addr_list; addr_list = addr_list->next)
if ((!net || is_same_net6(&addr_list->addr.addr6, net, prefix) || ((addr_list->flags & ADDRLIST_WILDCARD) && prefix == 64)) &&
is_same_net6(&addr_list->addr.addr6, addr, (addr_list->flags & ADDRLIST_PREFIX) ? addr_list->prefixlen : 128))
return config;
}
if ((config->flags & CONFIG_ADDR6) &&
is_same_net6(&config->addr6, net, prefix) &&
(prefix == 128 || addr6part(&config->addr6) == addr))
return config;
return NULL;
}
struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len, int temp_addr,
unsigned int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)
int address6_allocate(struct dhcp_context *context, unsigned char *clid, int clid_len,
int serial, struct dhcp_netid *netids, struct in6_addr *ans)
{
/* Find a free address: exclude anything in use and anything allocated to
a particular hwaddr/clientid/hostname in our configuration.
@@ -460,43 +257,23 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
u64 j;
/* hash hwaddr: use the SDBM hashing algorithm. This works
for MAC addresses, let's see how it manages with client-ids!
For temporary addresses, we generate a new random one each time. */
if (temp_addr)
j = rand64();
else
for (j = iaid, i = 0; i < clid_len; i++)
j = clid[i] + (j << 6) + (j << 16) - j;
for MAC addresses, let's see how it manages with client-ids! */
for (j = 0, i = 0; i < clid_len; i++)
j += clid[i] + (j << 6) + (j << 16) - j;
for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
continue;
else if (!match_netid(c->filter, netids, pass))
continue;
else
{
if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
{
/* seed is largest extant lease addr in this context,
skip addresses equal to the number of addresses rejected
by clients. This should avoid the same client being offered the same
address after it has rjected it. */
start = lease_find_max_addr6(c) + 1 + serial + c->addr_epoch;
if (c->addr_epoch)
c->addr_epoch--;
}
if (option_bool(OPT_CONSEC_ADDR))
/* seed is largest extant lease addr in this context */
start = lease_find_max_addr6(c) + serial;
else
{
u64 range = 1 + addr6part(&c->end6) - addr6part(&c->start6);
u64 offset = j + c->addr_epoch;
/* don't divide by zero if range is whole 2^64 */
if (range != 0)
offset = offset % range;
start = addr6part(&c->start6) + offset;
}
start = addr6part(&c->start6) + ((j + c->addr_epoch + serial) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
/* iterate until we find a free address. */
addr = start;
@@ -506,15 +283,16 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
for (d = context; d; d = d->current)
if (addr == addr6part(&d->local6))
break;
*ans = c->start6;
setaddr6part (ans, addr);
if (!d &&
!lease6_find_by_addr(&c->start6, c->prefix, addr) &&
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, ans))
return c;
!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
{
*ans = c->start6;
setaddr6part (ans, addr);
return 1;
}
addr++;
if (addr == addr6part(&c->end6) + 1)
@@ -522,15 +300,13 @@ struct dhcp_context *address6_allocate(struct dhcp_context *context, unsigned c
} while (addr != start);
}
return NULL;
return 0;
}
/* can dynamically allocate addr */
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
int plain_range)
struct dhcp_netid *netids)
{
u64 start, end, addr = addr6part(taddr);
struct dhcp_context *tmp;
@@ -545,33 +321,100 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, plain_range))
match_netid(tmp->filter, netids, 1))
return tmp;
}
return NULL;
}
/* address OK if configured */
struct dhcp_context *address6_valid(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids,
int plain_range)
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
{
/* We start of with a set of possible contexts, all on the current physical interface.
These are chained on ->current.
Here we have an address, and return the actual context correponding to that
address. Note that none may fit, if the address came a dhcp-host and is outside
any dhcp-range. In that case we return a static range if possible, or failing that,
any context on the correct subnet. (If there's more than one, this is a dodgy
configuration: maybe there should be a warning.) */
struct dhcp_context *tmp;
for (tmp = context; tmp; tmp = tmp->current)
if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
match_netid(tmp->filter, netids, plain_range))
return tmp;
if (!(tmp = address6_available(context, taddr, netids)))
{
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
(tmp->flags & CONTEXT_STATIC))
break;
if (!tmp)
for (tmp = context; tmp; tmp = tmp->current)
if (match_netid(tmp->filter, netids, 1) &&
is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
!(tmp->flags & CONTEXT_PROXY))
break;
}
/* Only one context allowed now */
if (tmp)
tmp->current = NULL;
return tmp;
}
static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
{
if (!context) /* called via find_config() from lease_update_from_configs() */
return 1;
if (!(config->flags & CONFIG_ADDR6) || is_addr_in_context6(context, &config->addr6))
return 1;
return 0;
}
int is_addr_in_context6(struct dhcp_context *context, struct in6_addr *addr)
{
for (; context; context = context->current)
if (is_same_net6(addr, &context->start6, context->prefix))
return 1;
return 0;
}
struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_context *context,
unsigned char *duid, int duid_len,
char *hostname)
{
struct dhcp_config *config;
if (duid)
for (config = configs; config; config = config->next)
if (config->flags & CONFIG_CLID)
{
if (config->clid_len == duid_len &&
memcmp(config->clid, duid, duid_len) == 0 &&
is_config_in_context6(context, config))
return config;
}
if (hostname && context)
for (config = configs; config; config = config->next)
if ((config->flags & CONFIG_NAME) &&
hostname_isequal(config->hostname, hostname) &&
is_config_in_context6(context, config))
return config;
return NULL;
}
void make_duid(time_t now)
{
(void)now;
if (daemon->duid_config)
{
unsigned char *p;
@@ -584,14 +427,8 @@ void make_duid(time_t now)
}
else
{
time_t newnow = 0;
/* If we have no persistent lease database, or a non-stable RTC, use DUID_LL (newnow == 0) */
#ifndef HAVE_BROKEN_RTC
/* rebase epoch to 1/1/2000 */
if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
newnow = now - 946684800;
#endif
time_t newnow = now - 946684800;
iface_enumerate(AF_LOCAL, &newnow, make_duid1);
@@ -609,227 +446,27 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
unsigned char *p;
(void)index;
(void)parm;
time_t newnow = *((time_t *)parm);
if (type >= 256)
return 1;
if (newnow == 0)
{
daemon->duid = p = safe_malloc(maclen + 4);
daemon->duid_len = maclen + 4;
PUTSHORT(3, p); /* DUID_LL */
PUTSHORT(type, p); /* address type */
}
else
{
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
PUTSHORT(1, p); /* DUID_LLT */
PUTSHORT(type, p); /* address type */
PUTLONG(*((time_t *)parm), p); /* time */
}
#ifdef HAVE_BROKEN_RTC
daemon->duid = p = safe_malloc(maclen + 4);
daemon->duid_len = maclen + 4;
PUTSHORT(3, p); /* DUID_LL */
PUTSHORT(type, p); /* address type */
#else
daemon->duid = p = safe_malloc(maclen + 8);
daemon->duid_len = maclen + 8;
PUTSHORT(1, p); /* DUID_LLT */
PUTSHORT(type, p); /* address type */
PUTLONG(*((time_t *)parm), p); /* time */
#endif
memcpy(p, mac, maclen);
return 0;
}
#endif
struct cparam {
time_t now;
int newone, newname;
};
static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct in6_addr start6, end6;
struct dhcp_context *template, *context;
struct iname *tmp;
(void)scope;
(void)flags;
(void)valid;
(void)preferred;
struct cparam *param = vparam;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
if (!(flags & IFACE_PERMANENT))
return 1;
if (flags & IFACE_DEPRECATED)
return 1;
/* Ignore interfaces where we're not doing RA/DHCP6 */
if (!indextoname(daemon->icmp6fd, if_index, ifrn_name) ||
!iface_check(AF_LOCAL, NULL, ifrn_name, NULL))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && wildcard_match(tmp->name, ifrn_name))
return 1;
for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & (CONTEXT_TEMPLATE | CONTEXT_CONSTRUCTED)))
{
/* non-template entries, just fill in interface and local addresses */
if (prefix <= template->prefix &&
is_same_net6(local, &template->start6, template->prefix) &&
is_same_net6(local, &template->end6, template->prefix))
{
/* First time found, do fast RA. */
if (template->if_index == 0)
{
ra_start_unsolicited(param->now, template);
param->newone = 1;
}
template->if_index = if_index;
template->local6 = *local;
}
}
else if (wildcard_match(template->template_interface, ifrn_name) &&
template->prefix >= prefix)
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
end6 = *local;
setaddr6part(&end6, addr6part(&template->end6));
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
/* If there's an absolute address context covering this address
then don't construct one as well. */
if (!(context->flags & CONTEXT_CONSTRUCTED))
break;
if (context->if_index == if_index)
{
int cflags = context->flags;
context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
if (cflags & CONTEXT_OLD)
{
/* address went, now it's back, and on the same interface */
log_context(AF_INET6, context);
/* fast RAs for a while */
ra_start_unsolicited(param->now, context);
param->newone = 1;
/* Add address to name again */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
}
break;
}
}
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
{
*context = *template;
context->start6 = start6;
context->end6 = end6;
context->flags &= ~CONTEXT_TEMPLATE;
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->saved_valid = 0;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
ra_start_unsolicited(param->now, context);
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
/* Will need to add new putative SLAAC addresses to existing leases */
if (context->flags & CONTEXT_RA_NAME)
param->newname = 1;
log_context(AF_INET6, context);
}
}
return 1;
}
void dhcp_construct_contexts(time_t now)
{
struct dhcp_context *context, *tmp, **up;
struct cparam param;
param.newone = 0;
param.newname = 0;
param.now = now;
for (context = daemon->dhcp6; context; context = context->next)
if (context->flags & CONTEXT_CONSTRUCTED)
context->flags |= CONTEXT_GC;
iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
{
if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
{
/* previously constructed context has gone. advertise it's demise */
context->flags |= CONTEXT_OLD;
context->address_lost_time = now;
/* Apply same ceiling of configured lease time as in radv.c */
if (context->saved_valid > context->lease_time)
context->saved_valid = context->lease_time;
/* maximum time is 2 hours, from RFC */
if (context->saved_valid > 7200) /* 2 hours */
context->saved_valid = 7200;
ra_start_unsolicited(now, context);
param.newone = 1; /* include deletion */
if (context->flags & CONTEXT_RA_NAME)
param.newname = 1;
log_context(AF_INET6, context);
up = &context->next;
}
else
{
/* we were never doing RA for this, so free now */
*up = context->next;
free(context);
}
}
else
up = &context->next;
}
if (param.newone)
{
if (daemon->dhcp || daemon->doing_dhcp6)
{
if (param.newname)
lease_update_slaac(now);
lease_update_file(now);
}
else
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
}
}
#endif /* HAVE_DHCP6 */

View File

@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2022 Simon Kelley
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -16,8 +16,6 @@
#define NAMESERVER_PORT 53
#define TFTP_PORT 69
#define MIN_PORT 1024 /* first non-reserved port */
#define MAX_PORT 65535u
#define IN6ADDRSZ 16
#define INADDRSZ 4
@@ -38,83 +36,24 @@
#define C_IN 1 /* the arpa internet */
#define C_CHAOS 3 /* for chaos net (MIT) */
#define C_HESIOD 4 /* hesiod */
#define C_ANY 255 /* wildcard match */
#define T_A 1
#define T_NS 2
#define T_MD 3
#define T_MF 4
#define T_NS 2
#define T_CNAME 5
#define T_SOA 6
#define T_MB 7
#define T_MG 8
#define T_MR 9
#define T_PTR 12
#define T_MINFO 14
#define T_MX 15
#define T_TXT 16
#define T_RP 17
#define T_AFSDB 18
#define T_RT 21
#define T_SIG 24
#define T_PX 26
#define T_AAAA 28
#define T_NXT 30
#define T_SRV 33
#define T_NAPTR 35
#define T_KX 36
#define T_DNAME 39
#define T_OPT 41
#define T_DS 43
#define T_RRSIG 46
#define T_NSEC 47
#define T_DNSKEY 48
#define T_NSEC3 50
#define T_TKEY 249
#define T_TSIG 250
#define T_AXFR 252
#define T_MAILB 253
#define T_ANY 255
#define T_CAA 257
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
#define EDNS0_OPTION_EDE 15 /* IANA - RFC 8914 */
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
/* RFC-8914 extended errors, negative values are our definitions */
#define EDE_UNSET -1 /* No extended DNS error available */
#define EDE_OTHER 0 /* Other */
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
#define EDE_USUPDS 2 /* Unsupported DS Digest */
#define EDE_STALE 3 /* Stale answer */
#define EDE_FORGED 4 /* Forged answer */
#define EDE_DNSSEC_IND 5 /* DNSSEC Indeterminate */
#define EDE_DNSSEC_BOGUS 6 /* DNSSEC Bogus */
#define EDE_SIG_EXP 7 /* Signature Expired */
#define EDE_SIG_NYV 8 /* Signature Not Yet Valid */
#define EDE_NO_DNSKEY 9 /* DNSKEY missing */
#define EDE_NO_RRSIG 10 /* RRSIGs missing */
#define EDE_NO_ZONEKEY 11 /* No Zone Key Bit Set */
#define EDE_NO_NSEC 12 /* NSEC Missing */
#define EDE_CACHED_ERR 13 /* Cached Error */
#define EDE_NOT_READY 14 /* Not Ready */
#define EDE_BLOCKED 15 /* Blocked */
#define EDE_CENSORED 16 /* Censored */
#define EDE_FILTERED 17 /* Filtered */
#define EDE_PROHIBITED 18 /* Prohibited */
#define EDE_STALE_NXD 19 /* Stale NXDOMAIN */
#define EDE_NOT_AUTH 20 /* Not Authoritative */
#define EDE_NOT_SUP 21 /* Not Supported */
#define EDE_NO_AUTH 22 /* No Reachable Authority */
#define EDE_NETERR 23 /* Network error */
#define EDE_INVALID_DATA 24 /* Invalid Data */
struct dns_header {
u16 id;
@@ -122,20 +61,18 @@ struct dns_header {
u16 qdcount,ancount,nscount,arcount;
};
#define HB3_QR 0x80 /* Query */
#define HB3_QR 0x80
#define HB3_OPCODE 0x78
#define HB3_AA 0x04 /* Authoritative Answer */
#define HB3_TC 0x02 /* TrunCated */
#define HB3_RD 0x01 /* Recursion Desired */
#define HB3_AA 0x04
#define HB3_TC 0x02
#define HB3_RD 0x01
#define HB4_RA 0x80 /* Recursion Available */
#define HB4_AD 0x20 /* Authenticated Data */
#define HB4_CD 0x10 /* Checking Disabled */
#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 SET_OPCODE(x, code) (x)->hb3 = ((x)->hb3 & ~HB3_OPCODE) | code
#define RCODE(x) ((x)->hb4 & HB4_RCODE)
#define SET_RCODE(x, code) (x)->hb4 = ((x)->hb4 & ~HB4_RCODE) | code
@@ -175,16 +112,3 @@ struct dns_header {
(cp) += 4; \
}
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
/* Escape character in our presentation format for names.
Cannot be '.' or /000 and must be !isprint().
Note that escaped chars are stored as
<NAME_ESCAPE> <orig-char+1>
to ensure that the escaped form of /000 doesn't include /000
*/
#define NAME_ESCAPE 1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,730 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
static int order(char *qdomain, size_t qlen, struct server *serv);
static int order_qsort(const void *a, const void *b);
static int order_servers(struct server *s, struct server *s2);
/* If the server is USE_RESOLV or LITERAL_ADDRES, it lives on the local_domains chain. */
#define SERV_IS_LOCAL (SERV_USE_RESOLV | SERV_LITERAL_ADDRESS)
void build_server_array(void)
{
struct server *serv;
int count = 0;
for (serv = daemon->servers; serv; serv = serv->next)
#ifdef HAVE_LOOP
if (!(serv->flags & SERV_LOOP))
#endif
{
count++;
if (serv->flags & SERV_WILDCARD)
daemon->server_has_wildcard = 1;
}
for (serv = daemon->local_domains; serv; serv = serv->next)
{
count++;
if (serv->flags & SERV_WILDCARD)
daemon->server_has_wildcard = 1;
}
daemon->serverarraysz = count;
if (count > daemon->serverarrayhwm)
{
struct server **new;
count += 10; /* A few extra without re-allocating. */
if ((new = whine_malloc(count * sizeof(struct server *))))
{
if (daemon->serverarray)
free(daemon->serverarray);
daemon->serverarray = new;
daemon->serverarrayhwm = count;
}
}
count = 0;
for (serv = daemon->servers; serv; serv = serv->next)
#ifdef HAVE_LOOP
if (!(serv->flags & SERV_LOOP))
#endif
{
daemon->serverarray[count] = serv;
serv->serial = count;
serv->last_server = -1;
count++;
}
for (serv = daemon->local_domains; serv; serv = serv->next, count++)
daemon->serverarray[count] = serv;
qsort(daemon->serverarray, daemon->serverarraysz, sizeof(struct server *), order_qsort);
/* servers need the location in the array to find all the whole
set of equivalent servers from a pointer to a single one. */
for (count = 0; count < daemon->serverarraysz; count++)
if (!(daemon->serverarray[count]->flags & SERV_IS_LOCAL))
daemon->serverarray[count]->arrayposn = count;
}
/* we're looking for the server whose domain is the longest exact match
to the RH end of qdomain, or a local address if the flags match.
Add '.' to the LHS of the query string so
server=/.example.com/ works.
A flag of F_SERVER returns an upstream server only.
A flag of F_DNSSECOK returns a DNSSEC capable server only and
also disables NODOTS servers from consideration.
A flag of F_DOMAINSRV returns a domain-specific server only.
A flag of F_CONFIG returns anything that generates a local
reply of IPv4 or IPV6.
return 0 if nothing found, 1 otherwise.
*/
int lookup_domain(char *domain, int flags, int *lowout, int *highout)
{
int rc, crop_query, nodots;
ssize_t qlen;
int try, high, low = 0;
int nlow = 0, nhigh = 0;
char *cp, *qdomain = domain;
/* may be no configured servers. */
if (daemon->serverarraysz == 0)
return 0;
/* find query length and presence of '.' */
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
if (*cp == '.')
nodots = 0;
/* Handle empty name, and searches for DNSSEC queries without
diverting to NODOTS servers. */
if (qlen == 0 || flags & F_DNSSECOK)
nodots = 0;
/* Search shorter and shorter RHS substrings for a match */
while (qlen >= 0)
{
/* Note that when we chop off a label, all the possible matches
MUST be at a larger index than the nearest failing match with one more
character, since the array is sorted longest to smallest. Hence
we don't reset low to zero here, we can go further below and crop the
search string to the size of the largest remaining server
when this match fails. */
high = daemon->serverarraysz;
crop_query = 1;
/* binary search */
while (1)
{
try = (low + high)/2;
if ((rc = order(qdomain, qlen, daemon->serverarray[try])) == 0)
break;
if (rc < 0)
{
if (high == try)
{
/* qdomain is longer or same length as longest domain, and try == 0
crop the query to the longest domain. */
crop_query = qlen - daemon->serverarray[try]->domain_len;
break;
}
high = try;
}
else
{
if (low == try)
{
/* try now points to the last domain that sorts before the query, so
we know that a substring of the query shorter than it is required to match, so
find the largest domain that's shorter than try. Note that just going to
try+1 is not optimal, consider searching bbb in (aaa,ccc,bb). try will point
to aaa, since ccc sorts after bbb, but the first domain that has a chance to
match is bb. So find the length of the first domain later than try which is
is shorter than it.
There's a nasty edge case when qdomain sorts before _any_ of the
server domains, where try _doesn't point_ to the last domain that sorts
before the query, since no such domain exists. In that case, the loop
exits via the rc < 0 && high == try path above and this code is
not executed. */
ssize_t len, old = daemon->serverarray[try]->domain_len;
while (++try != daemon->serverarraysz)
{
if (old != (len = daemon->serverarray[try]->domain_len))
{
crop_query = qlen - len;
break;
}
}
break;
}
low = try;
}
};
if (rc == 0)
{
int found = 1;
if (daemon->server_has_wildcard)
{
/* if we have example.com and *example.com we need to check against *example.com,
but the binary search may have found either. Use the fact that example.com is sorted before *example.com
We favour example.com in the case that both match (ie www.example.com) */
while (try != 0 && order(qdomain, qlen, daemon->serverarray[try-1]) == 0)
try--;
if (!(qdomain == domain || *qdomain == 0 || *(qdomain-1) == '.'))
{
while (try < daemon->serverarraysz-1 && order(qdomain, qlen, daemon->serverarray[try+1]) == 0)
try++;
if (!(daemon->serverarray[try]->flags & SERV_WILDCARD))
found = 0;
}
}
if (found && filter_servers(try, flags, &nlow, &nhigh))
/* We have a match, but it may only be (say) an IPv6 address, and
if the query wasn't for an AAAA record, it's no good, and we need
to continue generalising */
{
/* We've matched a setting which says to use servers without a domain.
Continue the search with empty query. We set the F_SERVER flag
so that --address=/#/... doesn't match. */
if (daemon->serverarray[nlow]->flags & SERV_USE_RESOLV)
{
crop_query = qlen;
flags |= F_SERVER;
}
else
break;
}
}
/* crop_query must be at least one always. */
if (crop_query == 0)
crop_query = 1;
/* strip chars off the query based on the largest possible remaining match,
then continue to the start of the next label unless we have a wildcard
domain somewhere, in which case we have to go one at a time. */
qlen -= crop_query;
qdomain += crop_query;
if (!daemon->server_has_wildcard)
while (qlen > 0 && (*(qdomain-1) != '.'))
qlen--, qdomain++;
}
/* domain has no dots, and we have at least one server configured to handle such,
These servers always sort to the very end of the array.
A configured server eg server=/lan/ will take precdence. */
if (nodots &&
(daemon->serverarray[daemon->serverarraysz-1]->flags & SERV_FOR_NODOTS) &&
(nlow == nhigh || daemon->serverarray[nlow]->domain_len == 0))
filter_servers(daemon->serverarraysz-1, flags, &nlow, &nhigh);
if (lowout)
*lowout = nlow;
if (highout)
*highout = nhigh;
if (nlow == nhigh)
return 0;
return 1;
}
/* Return first server in group of equivalent servers; this is the "master" record. */
int server_samegroup(struct server *a, struct server *b)
{
return order_servers(a, b) == 0;
}
int filter_servers(int seed, int flags, int *lowout, int *highout)
{
int nlow = seed, nhigh = seed;
int i;
/* expand nlow and nhigh to cover all the records with the same domain
nlow is the first, nhigh - 1 is the last. nlow=nhigh means no servers,
which can happen below. */
while (nlow > 0 && order_servers(daemon->serverarray[nlow-1], daemon->serverarray[nlow]) == 0)
nlow--;
while (nhigh < daemon->serverarraysz-1 && order_servers(daemon->serverarray[nhigh], daemon->serverarray[nhigh+1]) == 0)
nhigh++;
nhigh++;
#define SERV_LOCAL_ADDRESS (SERV_6ADDR | SERV_4ADDR | SERV_ALL_ZEROS)
if (flags & F_CONFIG)
{
/* We're just lookin for any matches that return an RR. */
for (i = nlow; i < nhigh; i++)
if (daemon->serverarray[i]->flags & SERV_LOCAL_ADDRESS)
break;
/* failed, return failure. */
if (i == nhigh)
nhigh = nlow;
}
else
{
/* Now the servers are on order between low and high, in the order
IPv6 addr, IPv4 addr, return zero for both, resolvconf servers, send upstream, no-data return.
See which of those match our query in that priority order and narrow (low, high) */
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_6ADDR); i++);
if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV6))
nhigh = i;
else
{
nlow = i;
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_4ADDR); i++);
if (!(flags & F_SERVER) && i != nlow && (flags & F_IPV4))
nhigh = i;
else
{
nlow = i;
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_ALL_ZEROS); i++);
if (!(flags & F_SERVER) && i != nlow && (flags & (F_IPV4 | F_IPV6)))
nhigh = i;
else
{
nlow = i;
/* Short to resolv.conf servers */
for (i = nlow; i < nhigh && (daemon->serverarray[i]->flags & SERV_USE_RESOLV); i++);
if (i != nlow)
nhigh = i;
else
{
/* now look for a server */
for (i = nlow; i < nhigh && !(daemon->serverarray[i]->flags & SERV_LITERAL_ADDRESS); i++);
if (i != nlow)
{
/* If we want a server that can do DNSSEC, and this one can't,
return nothing, similarly if were looking only for a server
for a particular domain. */
if ((flags & F_DNSSECOK) && !(daemon->serverarray[nlow]->flags & SERV_DO_DNSSEC))
nlow = nhigh;
else if ((flags & F_DOMAINSRV) && daemon->serverarray[nlow]->domain_len == 0)
nlow = nhigh;
else
nhigh = i;
}
else
{
/* --local=/domain/, only return if we don't need a server. */
if (flags & (F_DNSSECOK | F_DOMAINSRV | F_SERVER))
nhigh = i;
}
}
}
}
}
}
*lowout = nlow;
*highout = nhigh;
return (nlow != nhigh);
}
int is_local_answer(time_t now, int first, char *name)
{
int flags = 0;
int rc = 0;
if ((flags = daemon->serverarray[first]->flags) & SERV_LITERAL_ADDRESS)
{
if (flags & SERV_4ADDR)
rc = F_IPV4;
else if (flags & SERV_6ADDR)
rc = F_IPV6;
else if (flags & SERV_ALL_ZEROS)
rc = F_IPV4 | F_IPV6;
else
{
/* argument first is the first struct server which matches the query type;
now roll back to the server which is just the same domain, to check if that
provides an answer of a different type. */
for (;first > 0 && order_servers(daemon->serverarray[first-1], daemon->serverarray[first]) == 0; first--);
if ((daemon->serverarray[first]->flags & SERV_LOCAL_ADDRESS) ||
check_for_local_domain(name, now))
rc = F_NOERR;
else
rc = F_NXDOMAIN;
}
}
return rc;
}
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
{
int trunc = 0, anscount = 0;
unsigned char *p;
int start;
union all_addr addr;
if (flags & (F_NXDOMAIN | F_NOERR))
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
setup_reply(header, flags, ede);
if (!(p = skip_questions(header, size)))
return 0;
if (flags & gotname & F_IPV4)
for (start = first; start != last; start++)
{
struct serv_addr4 *srv = (struct serv_addr4 *)daemon->serverarray[start];
if (srv->flags & SERV_ALL_ZEROS)
memset(&addr, 0, sizeof(addr));
else
addr.addr4 = srv->addr;
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV6, name, (union all_addr *)&addr, NULL, 0);
}
if (flags & gotname & F_IPV6)
for (start = first; start != last; start++)
{
struct serv_addr6 *srv = (struct serv_addr6 *)daemon->serverarray[start];
if (srv->flags & SERV_ALL_ZEROS)
memset(&addr, 0, sizeof(addr));
else
addr.addr6 = srv->addr;
if (add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &addr))
anscount++;
log_query((flags | F_CONFIG | F_FORWARD) & ~F_IPV4, name, (union all_addr *)&addr, NULL, 0);
}
if (trunc)
header->hb3 |= HB3_TC;
header->ancount = htons(anscount);
return p - (unsigned char *)header;
}
#ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp)
{
int first, last, index;
/* Find server to send DNSSEC query to. This will normally be the
same as for the original query, but may be another if
servers for domains are involved. */
if (!lookup_domain(keyname, F_DNSSECOK, &first, &last))
return -1;
for (index = first; index != last; index++)
if (daemon->serverarray[index] == server)
break;
/* No match to server used for original query.
Use newly looked up set. */
if (index == last)
index = daemon->serverarray[first]->last_server == -1 ?
first : daemon->serverarray[first]->last_server;
if (firstp)
*firstp = first;
if (lastp)
*lastp = last;
return index;
}
#endif
/* order by size, then by dictionary order */
static int order(char *qdomain, size_t qlen, struct server *serv)
{
size_t dlen = 0;
/* servers for dotless names always sort last
searched for name is never dotless. */
if (serv->flags & SERV_FOR_NODOTS)
return -1;
dlen = serv->domain_len;
if (qlen < dlen)
return 1;
if (qlen > dlen)
return -1;
return hostname_order(qdomain, serv->domain);
}
static int order_servers(struct server *s1, struct server *s2)
{
int rc;
/* need full comparison of dotless servers in
order_qsort() and filter_servers() */
if (s1->flags & SERV_FOR_NODOTS)
return (s2->flags & SERV_FOR_NODOTS) ? 0 : 1;
if ((rc = order(s1->domain, s1->domain_len, s2)) != 0)
return rc;
/* For identical domains, sort wildcard ones first */
if (s1->flags & SERV_WILDCARD)
return (s2->flags & SERV_WILDCARD) ? 0 : 1;
return (s2->flags & SERV_WILDCARD) ? -1 : 0;
}
static int order_qsort(const void *a, const void *b)
{
int rc;
struct server *s1 = *((struct server **)a);
struct server *s2 = *((struct server **)b);
rc = order_servers(s1, s2);
/* Sort all literal NODATA and local IPV4 or IPV6 responses together,
in a very specific order. We flip the SERV_LITERAL_ADDRESS bit
so the order is IPv6 literal, IPv4 literal, all-zero literal,
unqualified servers, upstream server, NXDOMAIN literal. */
if (rc == 0)
rc = ((s2->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS) -
((s1->flags & (SERV_LITERAL_ADDRESS | SERV_4ADDR | SERV_6ADDR | SERV_USE_RESOLV | SERV_ALL_ZEROS)) ^ SERV_LITERAL_ADDRESS);
/* Finally, order by appearance in /etc/resolv.conf etc, for --strict-order */
if (rc == 0)
if (!(s1->flags & SERV_LITERAL_ADDRESS))
rc = s1->serial - s2->serial;
return rc;
}
/* Must be called before add_update_server() to set daemon->servers_tail */
void mark_servers(int flag)
{
struct server *serv, **up;
daemon->servers_tail = NULL;
/* mark everything with argument flag */
for (serv = daemon->servers; serv; serv = serv->next)
{
if (serv->flags & flag)
serv->flags |= SERV_MARK;
else
serv->flags &= ~SERV_MARK;
daemon->servers_tail = serv;
}
/* --address etc is different: since they are expected to be
1) numerous and 2) not reloaded often. We just delete
and recreate. */
if (flag)
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = serv->next)
{
if (serv->flags & flag)
{
*up = serv->next;
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
void cleanup_servers(void)
{
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
server_gone(serv);
*up = serv->next;
free(serv->domain);
free(serv);
}
else
{
up = &serv->next;
daemon->servers_tail = serv;
}
}
}
int add_update_server(int flags,
union mysockaddr *addr,
union mysockaddr *source_addr,
const char *interface,
const char *domain,
union all_addr *local_addr)
{
struct server *serv = NULL;
char *alloc_domain;
if (!domain)
domain = "";
/* .domain == domain, for historical reasons. */
if (*domain == '.')
while (*domain == '.') domain++;
else if (*domain == '*')
{
domain++;
if (*domain != 0)
flags |= SERV_WILDCARD;
}
if (*domain == 0)
alloc_domain = whine_malloc(1);
else
alloc_domain = canonicalise((char *)domain, NULL);
if (!alloc_domain)
return 0;
if (flags & SERV_IS_LOCAL)
{
size_t size;
if (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
else if (flags & SERV_4ADDR)
size = sizeof(struct serv_addr4);
else
size = sizeof(struct serv_local);
if (!(serv = whine_malloc(size)))
{
free(alloc_domain);
return 0;
}
serv->next = daemon->local_domains;
daemon->local_domains = serv;
if (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
}
else
{
/* Upstream servers. See if there is a suitable candidate, if so unmark
and move to the end of the list, for order. The entry found may already
be at the end. */
struct server **up, *tmp;
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
{
tmp = serv->next;
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
{
/* Need to move down? */
if (serv->next)
{
*up = serv->next;
daemon->servers_tail->next = serv;
daemon->servers_tail = serv;
serv->next = NULL;
}
break;
}
}
if (serv)
{
free(alloc_domain);
alloc_domain = serv->domain;
}
else
{
if (!(serv = whine_malloc(sizeof(struct server))))
{
free(alloc_domain);
return 0;
}
memset(serv, 0, sizeof(struct server));
/* Add to the end of the chain, for order */
if (daemon->servers_tail)
daemon->servers_tail->next = serv;
else
daemon->servers = serv;
daemon->servers_tail = serv;
}
#ifdef HAVE_LOOP
serv->uid = rand32();
#endif
if (interface)
safe_strncpy(serv->interface, interface, sizeof(serv->interface));
if (addr)
serv->addr = *addr;
if (source_addr)
serv->source_addr = *source_addr;
}
serv->flags = flags;
serv->domain = alloc_domain;
serv->domain_len = strlen(alloc_domain);
return 1;
}

View File

@@ -1,314 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c);
static int match_domain(struct in_addr addr, struct cond_domain *c);
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c);
static int match_domain6(struct in6_addr *addr, struct cond_domain *c);
int is_name_synthetic(int flags, char *name, union all_addr *addr)
{
char *p;
struct cond_domain *c = NULL;
int prot = (flags & F_IPV6) ? AF_INET6 : AF_INET;
for (c = daemon->synth_domains; c; c = c->next)
{
int found = 0;
char *tail, *pref;
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
{
unsigned int c1 = (unsigned char) *pref;
unsigned int c2 = (unsigned char) *tail;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
break;
}
if (pref && *pref != 0)
continue; /* prefix match fail */
if (c->indexed)
{
for (p = tail; *p; p++)
{
char c = *p;
if (c < '0' || c > '9')
break;
}
if (*p != '.')
continue;
*p = 0;
if (hostname_isequal(c->domain, p+1))
{
if (prot == AF_INET)
{
unsigned int index = atoi(tail);
if (!c->is6 &&
index <= ntohl(c->end.s_addr) - ntohl(c->start.s_addr))
{
addr->addr4.s_addr = htonl(ntohl(c->start.s_addr) + index);
found = 1;
}
}
else
{
u64 index = atoll(tail);
if (c->is6 &&
index <= addr6part(&c->end6) - addr6part(&c->start6))
{
u64 start = addr6part(&c->start6);
addr->addr6 = c->start6;
setaddr6part(&addr->addr6, start + index);
found = 1;
}
}
}
}
else
{
/* NB, must not alter name if we return zero */
for (p = tail; *p; p++)
{
char c = *p;
if ((c >='0' && c <= '9') || c == '-')
continue;
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
break;
}
if (*p != '.')
continue;
*p = 0;
if (prot == AF_INET6 && strstr(tail, "--ffff-") == tail)
{
/* special hack for v4-mapped. */
memcpy(tail, "::ffff:", 7);
for (p = tail + 7; *p; p++)
if (*p == '-')
*p = '.';
}
else
{
/* swap . or : for - */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
else
*p = ':';
}
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
found = (prot == AF_INET) ? match_domain(addr->addr4, c) : match_domain6(&addr->addr6, c);
}
/* restore name */
for (p = tail; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
if (found)
return 1;
}
return 0;
}
int is_rev_synth(int flag, union all_addr *addr, char *name)
{
struct cond_domain *c;
if (flag & F_IPV4 && (c = search_domain(addr->addr4, daemon->synth_domains)))
{
char *p;
*name = 0;
if (c->indexed)
{
unsigned int index = ntohl(addr->addr4.s_addr) - ntohl(c->start.s_addr);
snprintf(name, MAXDNAME, "%s%u", c->prefix ? c->prefix : "", index);
}
else
{
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET, &addr->addr4, name + strlen(name), ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
}
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
if ((flag & F_IPV6) && (c = search_domain6(&addr->addr6, daemon->synth_domains)))
{
char *p;
*name = 0;
if (c->indexed)
{
u64 index = addr6part(&addr->addr6) - addr6part(&c->start6);
snprintf(name, MAXDNAME, "%s%llu", c->prefix ? c->prefix : "", index);
}
else
{
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET6, &addr->addr6, name + strlen(name), ADDRSTRLEN);
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (!c->prefix && *name == ':')
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr6, name+1, ADDRSTRLEN);
}
/* V4-mapped have periods.... */
for (p = name; *p; p++)
if (*p == ':' || *p == '.')
*p = '-';
}
strncat(name, ".", MAXDNAME);
strncat(name, c->domain, MAXDNAME);
return 1;
}
return 0;
}
static int match_domain(struct in_addr addr, struct cond_domain *c)
{
if (c->interface)
{
struct addrlist *al;
for (al = c->al; al; al = al->next)
if (!(al->flags & ADDRLIST_IPV6) &&
is_same_net_prefix(addr, al->addr.addr4, al->prefixlen))
return 1;
}
else if (!c->is6 &&
ntohl(addr.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr.s_addr) <= ntohl(c->end.s_addr))
return 1;
return 0;
}
static struct cond_domain *search_domain(struct in_addr addr, struct cond_domain *c)
{
for (; c; c = c->next)
if (match_domain(addr, c))
return c;
return NULL;
}
char *get_domain(struct in_addr addr)
{
struct cond_domain *c;
if ((c = search_domain(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}
static int match_domain6(struct in6_addr *addr, struct cond_domain *c)
{
/* subnet from interface address. */
if (c->interface)
{
struct addrlist *al;
for (al = c->al; al; al = al->next)
if (al->flags & ADDRLIST_IPV6 &&
is_same_net6(addr, &al->addr.addr6, al->prefixlen))
return 1;
}
else if (c->is6)
{
if (c->prefixlen >= 64)
{
u64 addrpart = addr6part(addr);
if (is_same_net6(addr, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
return 1;
}
else if (is_same_net6(addr, &c->start6, c->prefixlen))
return 1;
}
return 0;
}
static struct cond_domain *search_domain6(struct in6_addr *addr, struct cond_domain *c)
{
for (; c; c = c->next)
if (match_domain6(addr, c))
return c;
return NULL;
}
char *get_domain6(struct in6_addr *addr)
{
struct cond_domain *c;
if (addr && (c = search_domain6(addr, daemon->cond_domain)))
return c->domain;
return daemon->domain_suffix;
}

View File

@@ -1,295 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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_DUMPFILE
#include <netinet/icmp6.h>
static u32 packet_count;
static void do_dump_packet(int mask, void *packet, size_t len,
union mysockaddr *src, union mysockaddr *dst, int port, int proto);
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
struct pcap_hdr_s {
u32 magic_number; /* magic number */
u16 version_major; /* major version number */
u16 version_minor; /* minor version number */
u32 thiszone; /* GMT to local correction */
u32 sigfigs; /* accuracy of timestamps */
u32 snaplen; /* max length of captured packets, in octets */
u32 network; /* data link type */
};
struct pcaprec_hdr_s {
u32 ts_sec; /* timestamp seconds */
u32 ts_usec; /* timestamp microseconds */
u32 incl_len; /* number of octets of packet saved in file */
u32 orig_len; /* actual length of packet */
};
void dump_init(void)
{
struct stat buf;
struct pcap_hdr_s header;
struct pcaprec_hdr_s pcap_header;
packet_count = 0;
if (stat(daemon->dump_file, &buf) == -1)
{
/* doesn't exist, create and add header */
header.magic_number = 0xa1b2c3d4;
header.version_major = 2;
header.version_minor = 4;
header.thiszone = 0;
header.sigfigs = 0;
header.snaplen = daemon->edns_pktsz + 200; /* slop for IP/UDP headers */
header.network = 101; /* DLT_RAW http://www.tcpdump.org/linktypes.html */
if (errno != ENOENT ||
(daemon->dumpfd = creat(daemon->dump_file, S_IRUSR | S_IWUSR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 0))
die(_("cannot create %s: %s"), daemon->dump_file, EC_FILE);
}
else if ((daemon->dumpfd = open(daemon->dump_file, O_APPEND | O_RDWR)) == -1 ||
!read_write(daemon->dumpfd, (void *)&header, sizeof(header), 1))
die(_("cannot access %s: %s"), daemon->dump_file, EC_FILE);
else if (header.magic_number != 0xa1b2c3d4)
die(_("bad header in %s"), daemon->dump_file, EC_FILE);
else
{
/* count existing records */
while (read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 1))
{
lseek(daemon->dumpfd, pcap_header.incl_len, SEEK_CUR);
packet_count++;
}
}
}
void dump_packet_udp(int mask, void *packet, size_t len,
union mysockaddr *src, union mysockaddr *dst, int fd)
{
union mysockaddr fd_addr;
socklen_t addr_len = sizeof(fd_addr);
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
{
/* if fd is negative it carries a port number (negated)
which we use as a source or destination when not otherwise
specified so wireshark can ID the packet.
If both src and dst are specified, set this to -1 to avoid
a spurious getsockname() call. */
int port = (fd < 0) ? -fd : -1;
/* fd >= 0 is a file descriptor and the address of that file descriptor is used
in place of a NULL src or dst. */
if (fd >= 0 && getsockname(fd, (struct sockaddr *)&fd_addr, &addr_len) != -1)
{
if (!src)
src = &fd_addr;
if (!dst)
dst = &fd_addr;
}
do_dump_packet(mask, packet, len, src, dst, port, IPPROTO_UDP);
}
}
void dump_packet_icmp(int mask, void *packet, size_t len,
union mysockaddr *src, union mysockaddr *dst)
{
if (daemon->dumpfd != -1 && (mask & daemon->dump_mask))
do_dump_packet(mask, packet, len, src, dst, -1, IPPROTO_ICMP);
}
static void do_dump_packet(int mask, void *packet, size_t len,
union mysockaddr *src, union mysockaddr *dst, int port, int proto)
{
struct ip ip;
struct ip6_hdr ip6;
int family;
struct udphdr {
u16 uh_sport; /* source port */
u16 uh_dport; /* destination port */
u16 uh_ulen; /* udp length */
u16 uh_sum; /* udp checksum */
} udp;
struct pcaprec_hdr_s pcap_header;
struct timeval time;
u32 i, sum;
void *iphdr;
size_t ipsz;
int rc;
/* if port != -1 it carries a port number
which we use as a source or destination when not otherwise
specified so wireshark can ID the packet.
If both src and dst are specified, set this to -1 to avoid
a spurious getsockname() call. */
udp.uh_sport = udp.uh_dport = htons(port < 0 ? 0 : port);
if (src)
family = src->sa.sa_family;
else
family = dst->sa.sa_family;
if (family == AF_INET6)
{
iphdr = &ip6;
ipsz = sizeof(ip6);
memset(&ip6, 0, sizeof(ip6));
ip6.ip6_vfc = 6 << 4;
ip6.ip6_hops = 64;
if ((ip6.ip6_nxt = proto) == IPPROTO_UDP)
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
else
{
proto = ip6.ip6_nxt = IPPROTO_ICMPV6;
ip6.ip6_plen = htons(len);
}
if (src)
{
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
udp.uh_sport = src->in6.sin6_port;
}
if (dst)
{
memcpy(&ip6.ip6_dst, &dst->in6.sin6_addr, IN6ADDRSZ);
udp.uh_dport = dst->in6.sin6_port;
}
/* start UDP checksum */
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
{
sum += ntohs((ip6.ip6_src.s6_addr[i] << 8) + (ip6.ip6_src.s6_addr[i+1])) ;
sum += ntohs((ip6.ip6_dst.s6_addr[i] << 8) + (ip6.ip6_dst.s6_addr[i+1])) ;
}
}
else
{
iphdr = &ip;
ipsz = sizeof(ip);
memset(&ip, 0, sizeof(ip));
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) / 4;
ip.ip_ttl = IPDEFTTL;
if ((ip.ip_p = proto) == IPPROTO_UDP)
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
else
{
ip.ip_len = htons(sizeof(struct ip) + len);
proto = ip.ip_p = IPPROTO_ICMP;
}
if (src)
{
ip.ip_src = src->in.sin_addr;
udp.uh_sport = src->in.sin_port;
}
if (dst)
{
ip.ip_dst = dst->in.sin_addr;
udp.uh_dport = dst->in.sin_port;
}
ip.ip_sum = 0;
for (sum = 0, i = 0; i < sizeof(struct ip) / 2; i++)
sum += ((u16 *)&ip)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
ip.ip_sum = (sum == 0xffff) ? sum : ~sum;
/* start UDP/ICMP checksum */
sum = ip.ip_src.s_addr & 0xffff;
sum += (ip.ip_src.s_addr >> 16) & 0xffff;
sum += ip.ip_dst.s_addr & 0xffff;
sum += (ip.ip_dst.s_addr >> 16) & 0xffff;
}
if (len & 1)
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
if (proto == IPPROTO_UDP)
{
/* Add Remaining part of the pseudoheader. Note that though the
IPv6 pseudoheader is very different to the IPv4 one, the
net result of this calculation is correct as long as the
packet length is less than 65536, which is fine for us. */
sum += htons(IPPROTO_UDP);
sum += htons(sizeof(struct udphdr) + len);
udp.uh_sum = 0;
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
for (i = 0; i < sizeof(struct udphdr)/2; i++)
sum += ((u16 *)&udp)[i];
for (i = 0; i < (len + 1) / 2; i++)
sum += ((u16 *)packet)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
udp.uh_sum = (sum == 0xffff) ? sum : ~sum;
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
}
else
{
/* ICMP - ICMPv6 packet is a superset of ICMP */
struct icmp6_hdr *icmp = packet;
/* See comment in UDP code above. */
sum += htons(proto);
sum += htons(len);
icmp->icmp6_cksum = 0;
for (i = 0; i < (len + 1) / 2; i++)
sum += ((u16 *)packet)[i];
while (sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
icmp->icmp6_cksum = (sum == 0xffff) ? sum : ~sum;
pcap_header.incl_len = pcap_header.orig_len = ipsz + len;
}
rc = gettimeofday(&time, NULL);
pcap_header.ts_sec = time.tv_sec;
pcap_header.ts_usec = time.tv_usec;
if (rc == -1 ||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
(proto == IPPROTO_UDP && !read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0)) ||
!read_write(daemon->dumpfd, (void *)packet, len, 0))
my_syslog(LOG_ERR, _("failed to write packet dump"));
else if (option_bool(OPT_EXTRALOG))
my_syslog(LOG_INFO, _("%u dumping packet %u mask 0x%04x"), daemon->log_display_id, ++packet_count, mask);
else
my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
}
#endif

View File

@@ -1,545 +0,0 @@
/* dnsmasq is Copyright (c) 2000-2022 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"
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
{
/* 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
Finally, check to see if a packet is signed. If it is we cannot change a single bit before
forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
int i, arcount = ntohs(header->arcount);
unsigned char *ansp = (unsigned char *)(header+1);
unsigned short rdlen, type, class;
unsigned char *ret = NULL;
if (is_sign)
{
*is_sign = 0;
if (OPCODE(header) == QUERY)
{
for (i = ntohs(header->qdcount); i != 0; i--)
{
if (!(ansp = skip_name(ansp, header, plen, 4)))
return NULL;
GETSHORT(type, ansp);
GETSHORT(class, ansp);
if (class == C_IN && type == T_TKEY)
*is_sign = 1;
}
}
}
else
{
if (!(ansp = skip_questions(header, plen)))
return NULL;
}
if (arcount == 0)
return NULL;
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
return NULL;
for (i = 0; i < arcount; i++)
{
unsigned char *save, *start = ansp;
if (!(ansp = skip_name(ansp, header, plen, 10)))
return NULL;
GETSHORT(type, ansp);
save = ansp;
GETSHORT(class, ansp);
ansp += 4; /* TTL */
GETSHORT(rdlen, ansp);
if (!ADD_RDLEN(header, ansp, plen, rdlen))
return NULL;
if (type == T_OPT)
{
if (len)
*len = ansp - start;
if (p)
*p = save;
if (is_last)
*is_last = (i == arcount-1);
ret = start;
}
else if (is_sign &&
i == arcount - 1 &&
class == C_ANY &&
type == T_TSIG)
*is_sign = 1;
}
return ret;
}
/* replace == 2 ->delete existing option only. */
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace)
{
unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
int rdlen = 0, is_sign, is_last;
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
if (is_sign)
return plen;
if (p)
{
/* Existing header */
int i;
unsigned short code, len;
p = udp_len;
GETSHORT(udp_sz, p);
GETSHORT(rcode, p);
GETSHORT(flags, p);
if (set_do)
{
p -= 2;
flags |= 0x8000;
PUTSHORT(flags, p);
}
lenp = p;
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return plen; /* bad packet */
datap = p;
/* no option to add */
if (optno == 0)
return plen;
/* check if option already there */
for (i = 0; i + 4 < rdlen;)
{
GETSHORT(code, p);
GETSHORT(len, p);
/* malformed option, delete the whole OPT RR and start again. */
if (i + 4 + len > rdlen)
{
rdlen = 0;
is_last = 0;
break;
}
if (code == optno)
{
if (replace == 0)
return plen;
/* delete option if we're to replace it. */
p -= 4;
rdlen -= len + 4;
memmove(p, p+len+4, rdlen - i);
PUTSHORT(rdlen, lenp);
lenp -= 2;
}
else
{
p += len;
i += len + 4;
}
}
/* If we're going to extend the RR, it has to be the last RR in the packet */
if (!is_last)
{
/* First, take a copy of the options. */
if (rdlen != 0 && (buff = whine_malloc(rdlen)))
memcpy(buff, datap, rdlen);
/* now, delete OPT RR */
plen = rrfilter(header, plen, RRFILTER_EDNS0);
/* Now, force addition of a new one */
p = NULL;
}
}
if (!p)
{
/* We are (re)adding the pseudoheader */
if (!(p = skip_questions(header, plen)) ||
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
{
free(buff);
return plen;
}
if (p + 11 > limit)
{
free(buff);
return plen; /* Too big */
}
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
PUTSHORT(rcode, p); /* extended RCODE and version */
PUTSHORT(flags, p); /* DO flag */
lenp = p;
PUTSHORT(rdlen, p); /* RDLEN */
datap = p;
/* Copy back any options */
if (buff)
{
if (p + rdlen > limit)
{
free(buff);
return plen; /* Too big */
}
memcpy(p, buff, rdlen);
free(buff);
p += rdlen;
}
/* Only bump arcount if RR is going to fit */
if (((ssize_t)optlen) <= (limit - (p + 4)))
header->arcount = htons(ntohs(header->arcount) + 1);
}
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
/* Add new option */
if (optno != 0 && replace != 2)
{
if (p + 4 > limit)
return plen; /* Too big */
PUTSHORT(optno, p);
PUTSHORT(optlen, p);
if (p + optlen > limit)
return plen; /* Too big */
memcpy(p, opt, optlen);
p += optlen;
PUTSHORT(p - datap, lenp);
}
return p - (unsigned char *)header;
}
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit)
{
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1, 0);
}
static unsigned char char64(unsigned char c)
{
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[c & 0x3f];
}
static void encoder(unsigned char *in, char *out)
{
out[0] = char64(in[0]>>2);
out[1] = char64((in[0]<<4) | (in[1]>>4));
out[2] = char64((in[1]<<2) | (in[2]>>6));
out[3] = char64(in[2]);
}
/* OPT_ADD_MAC = MAC is added (if available)
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
OPT_STRIP_MAC = MAC is removed */
static size_t add_dns_client(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *l3, time_t now, int *cacheablep)
{
int replace = 0, maclen = 0;
unsigned char mac[DHCP_CHADDR_MAX];
char encode[18]; /* handle 6 byte MACs ONLY */
if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
{
if (option_bool(OPT_STRIP_MAC))
replace = 1;
*cacheablep = 0;
if (option_bool(OPT_MAC_HEX))
print_mac(encode, mac, maclen);
else
{
encoder(mac, encode);
encoder(mac+3, encode+4);
encode[8] = 0;
}
}
else if (option_bool(OPT_STRIP_MAC))
replace = 2;
if (replace != 0 || maclen == 6)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
return plen;
}
/* OPT_ADD_MAC = MAC is added (if available)
OPT_ADD_MAC + OPT_STRIP_MAC = MAC is replaced, if not available, it is only removed
OPT_STRIP_MAC = MAC is removed */
static size_t add_mac(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *l3, time_t now, int *cacheablep)
{
int maclen = 0, replace = 0;
unsigned char mac[DHCP_CHADDR_MAX];
if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
{
*cacheablep = 0;
if (option_bool(OPT_STRIP_MAC))
replace = 1;
}
else if (option_bool(OPT_STRIP_MAC))
replace = 2;
if (replace != 0 || maclen != 0)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, replace);
return plen;
}
struct subnet_opt {
u16 family;
u8 source_netmask, scope_netmask;
u8 addr[IN6ADDRSZ];
};
static void *get_addrp(union mysockaddr *addr, const short family)
{
if (family == AF_INET6)
return &addr->in6.sin6_addr;
return &addr->in.sin_addr;
}
static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source, int *cacheablep)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int len;
void *addrp = NULL;
int sa_family = source->sa.sa_family;
int cacheable = 0;
opt->source_netmask = 0;
opt->scope_netmask = 0;
if (source->sa.sa_family == AF_INET6 && daemon->add_subnet6)
{
opt->source_netmask = daemon->add_subnet6->mask;
if (daemon->add_subnet6->addr_used)
{
sa_family = daemon->add_subnet6->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet6->addr, sa_family);
cacheable = 1;
}
else
addrp = &source->in6.sin6_addr;
}
if (source->sa.sa_family == AF_INET && daemon->add_subnet4)
{
opt->source_netmask = daemon->add_subnet4->mask;
if (daemon->add_subnet4->addr_used)
{
sa_family = daemon->add_subnet4->addr.sa.sa_family;
addrp = get_addrp(&daemon->add_subnet4->addr, sa_family);
cacheable = 1; /* Address is constant */
}
else
addrp = &source->in.sin_addr;
}
opt->family = htons(sa_family == AF_INET6 ? 2 : 1);
if (addrp && opt->source_netmask != 0)
{
len = ((opt->source_netmask - 1) >> 3) + 1;
memcpy(opt->addr, addrp, len);
if (opt->source_netmask & 7)
opt->addr[len-1] &= 0xff << (8 - (opt->source_netmask & 7));
}
else
{
cacheable = 1; /* No address ever supplied. */
len = 0;
}
if (cacheablep)
*cacheablep = cacheable;
return len + 4;
}
/* OPT_CLIENT_SUBNET = client subnet is added
OPT_CLIENT_SUBNET + OPT_STRIP_ECS = client subnet is replaced
OPT_STRIP_ECS = client subnet is removed */
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *source, int *cacheable)
{
/* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-02 */
int replace = 0, len = 0;
struct subnet_opt opt;
if (option_bool(OPT_CLIENT_SUBNET))
{
if (option_bool(OPT_STRIP_ECS))
replace = 1;
len = calc_subnet_opt(&opt, source, cacheable);
}
else if (option_bool(OPT_STRIP_ECS))
replace = 2;
else
return plen;
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
}
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
{
/* Section 9.2, Check that subnet option in reply matches. */
int len, calc_len;
struct subnet_opt opt;
unsigned char *p;
int code, i, rdlen;
calc_len = calc_subnet_opt(&opt, peer, NULL);
if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1;
p += 8; /* skip UDP length and RCODE */
GETSHORT(rdlen, p);
if (!CHECK_LEN(header, p, plen, rdlen))
return 1; /* bad packet */
/* check if option there */
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
GETSHORT(len, p);
if (code == EDNS0_OPTION_CLIENT_SUBNET)
{
/* make sure this doesn't mismatch. */
opt.scope_netmask = p[3];
if (len != calc_len || memcmp(p, &opt, len) != 0)
return 0;
}
p += len;
}
return 1;
}
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
* detailed information on packet formating.
*/
#define UMBRELLA_VERSION 1
#define UMBRELLA_TYPESZ 2
#define UMBRELLA_ASSET 0x0004
#define UMBRELLA_ASSETSZ sizeof(daemon->umbrella_asset)
#define UMBRELLA_ORG 0x0008
#define UMBRELLA_ORGSZ sizeof(daemon->umbrella_org)
#define UMBRELLA_IPV4 0x0010
#define UMBRELLA_IPV6 0x0020
#define UMBRELLA_DEVICE 0x0040
#define UMBRELLA_DEVICESZ sizeof(daemon->umbrella_device)
struct umbrella_opt {
u8 magic[4];
u8 version;
u8 flags;
/* We have 4 possible fields since we'll never send both IPv4 and
* IPv6, so using the larger of the two to calculate max buffer size.
* Each field also has a type header. So the following accounts for
* the type headers and each field size to get a max buffer size.
*/
u8 fields[4 * UMBRELLA_TYPESZ + UMBRELLA_ORGSZ + IN6ADDRSZ + UMBRELLA_DEVICESZ + UMBRELLA_ASSETSZ];
};
static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
{
*cacheable = 0;
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
u8 *u = &opt.fields[0];
int family = source->sa.sa_family;
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
if (daemon->umbrella_org)
{
PUTSHORT(UMBRELLA_ORG, u);
PUTLONG(daemon->umbrella_org, u);
}
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
memcpy(u, get_addrp(source, family), size);
u += size;
if (option_bool(OPT_UMBRELLA_DEVID))
{
PUTSHORT(UMBRELLA_DEVICE, u);
memcpy(u, (char *)&daemon->umbrella_device, UMBRELLA_DEVICESZ);
u += UMBRELLA_DEVICESZ;
}
if (daemon->umbrella_asset)
{
PUTSHORT(UMBRELLA_ASSET, u);
PUTLONG(daemon->umbrella_asset, u);
}
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, u - (u8 *)&opt, 0, 1);
}
/* Set *check_subnet if we add a client subnet option, which needs to checked
in the reply. Set *cacheable to zero if we add an option which the answer
may depend on. */
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *source, time_t now, int *cacheable)
{
*cacheable = 1;
plen = add_mac(header, plen, limit, source, now, cacheable);
plen = add_dns_client(header, plen, limit, source, now, cacheable);
if (daemon->dns_client_id)
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMCPEID,
(unsigned char *)daemon->dns_client_id, strlen(daemon->dns_client_id), 0, 1);
if (option_bool(OPT_UMBRELLA))
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
plen = add_source_addr(header, plen, limit, source, cacheable);
return plen;
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More