Compare commits

...
62 Commits
Author SHA1 Message Date
Simon Kelley 7fbf1cce7b Improve the performance of DHCP relay.
On machines with many interfaces, enumerating them
via netlink on each packet reciept is slow,
and unneccesary. All we need is the local address->interface
mapping, which can be cached in the relay structures.
2022-02-02 18:28:27 +00:00
Simon Kelley dbceeb4178 Dump.c Fix IPv6 checksum on big-endian. 2022-01-30 00:42:46 +00:00
Simon Kelley ed200fa001 Handle options other than source link-layer address in router solicitations.
RFC 4861 para 4.1 is a MUST.
2022-01-29 23:22:52 +00:00
Simon Kelley b5dafc0b7e Extend packet dump system to RA. 2022-01-29 22:52:21 +00:00
Simon Kelley fc664d114d Extend packet-dump system to DHCP and TFTP. 2022-01-29 15:55:04 +00:00
Simon Kelley c6d4c33d61 Bump copyright to 2022. 2022-01-24 15:19:00 +00:00
Simon Kelley 4e2a4b8788 Fix crash in PXE code with bad config. 2022-01-18 00:55:13 +00:00
Simon Kelley 2362784bc0 Debian bug management. 2022-01-18 00:32:15 +00:00
Simon Kelley b2cec1b881 Debian: fold in 2.86-1.1 changelog and close bug introducded by same. 2022-01-18 00:02:32 +00:00
Simon Kelley a946857133 Remove temporary debugging message and close related Debian bug. 2022-01-17 23:54:58 +00:00
Simon Kelley 10cd342f5c Document change of behaviour of --address in 2.86 onwards. 2022-01-17 16:01:02 +00:00
Simon Kelley 27ce754b3d Tidy previous commit and add manpage entries for new options. 2022-01-15 17:57:57 +00:00
Dominik Derigs 3ab0ad8748 Strip EDNS(0) Client Subnet / MAC information if --strip-subnet or --strip-mac is set. If both the add and strip options are set, incoming EDNS0 options are replaced. This ensures we do not unintentionally forward client information somewhere upstream when ECS is used in lower DNS layers in our local network.
Signed-off-by: DL6ER <dl6er@dl6er.de>
2022-01-15 15:36:28 +00:00
Dominik Derigs 4308236262 Minimum safe size is recommended to be 1232. See https://dnsflagday.net/2020/
Signed-off-by: DL6ER <dl6er@dl6er.de>
2022-01-13 00:31:54 +00:00
Simon Kelley ebd8350300 Fix DNSSEC failure to validate unsigned NoDATA replies.
A reply with an empty answer section would not always be checked
for either suitable NSEC records or proof of non-existence of
the relevant DS record.
2022-01-13 00:12:07 +00:00
Simon Kelley 8285d335f4 Fix error introduced in 11c52d032b 2022-01-12 23:05:25 +00:00
Simon Kelley 9db275ebea Small fix to ff43d35aee 2022-01-12 23:00:16 +00:00
Petr Menšík 1f8f78a49b Add root group writeable flag to log file
Some systems strips even root process capability of writing to different
users file. That include systemd under Fedora. When
log-facility=/var/log/dnsmasq.log is used, log file with mode 0640
is created. But restart then fails, because such log file can be used
only when created new. Existing file cannot be opened by root when
starting, causing fatal error. Avoid that by adding root group writeable flag.

Ensure group is always root when granting write access. If it is
anything else, administrator has to configure correct rights.
2022-01-11 23:43:09 +00:00
Simon Kelley c2f129ba3d Fix FTBFS when HAVE_DNSSEC not defined. 2022-01-11 22:48:14 +00:00
Simon Kelley 07c47416a9 Log source of ignored query when local-service is used.
Thanks to Dominik Derigs for the initial patch.
2022-01-11 22:36:01 +00:00
Dominik Derigs 8f2a62b386 Extend cache dump: "!" as type for non-terminals, new flag "C" for config-provided and log source when applicable.
Signed-off-by: DL6ER <dl6er@dl6er.de>
2022-01-11 22:17:14 +00:00
Dominik Derigs a6c0edd4f4 Fix header of cache dump. The width of the host and address fields are 30 and 40 characters, respectively.
Signed-off-by: DL6ER <dl6er@dl6er.de>
2022-01-11 22:16:48 +00:00
Simon Kelley ff43d35aee Log port numbers in server addresses when non-standard ports in use. 2022-01-11 22:09:09 +00:00
Simon Kelley 70fca205be Overhaul code which sends DNSSEC queries.
There are two functional changes in this commit.

1) When searching for an in-flight DNSSEC query to use
   (rather than starting a new one), compare the already
   sent query (stored in the frec "stash" field, rather than
   using the hash of the query. This is probably faster (no hash
   calculation) and eliminates having to worry about the
   consequences of a hash collision.

2) Check for dependency loops in DNSSEC validation,
   say validating A requires DS B and validating DS B
   requires DNSKEY C and validating DNSKEY C requires DS B.
   This should never happen in correctly signed records, but it's
   likely the case that sufficiently broken ones can cause
   our validation code requests to exhibit cycles.
   The result is that the ->blocking_query list
   can form a cycle, and under certain circumstances that can lock us in
   an infinite loop.
   Instead we transform the situation into an ABANDONED state.
2022-01-11 00:29:36 +00:00
Simon Kelley 1033130b6c Handle malformed query packets sensibly.
Previously, hash_questions() would return a random hash
if the packet was malformed, and probably the hash of a previous
query. Now handle this as an error.
2022-01-09 23:21:55 +00:00
Andreas Metzler 8cfcd9ff63 Clarify man page for --filterwin2k 2022-01-06 23:12:53 +00:00
Daniel Collins 80a6c16dcc Implements a SetLocaliseQueriesOption D-Bus method.
For setting the state of the -y/--localise-queries option.
2022-01-06 00:23:53 +00:00
Simon Kelley 553c4c99cc Fix massive confusion on server reload.
The 2.86 upstream server rewrite severely broke re-reading
of server configuration. It would get everyting right the first
time, but on re-reading /etc/resolv.conf or --servers-file
or setting things with DBUS, the results were just wrong.

This should put things right again.
2022-01-03 23:32:30 +00:00
Simon Kelley 4165c1331b Fix fail to build when NO_SCRIPT set. 2022-01-03 23:31:15 +00:00
Fabrice Fontaine b2690415bf src/option.c: fix build with gcc 4.8
Thanks for applying and fixing my patch. Here is another one on src/pattern.c

Best Regards,

Fabrice

Le dim. 2 janv. 2022 à 00:36, Simon Kelley <simon@thekelleys.org.uk> a écrit :
>
>
>
> Thanks,
>
>
> patch applied. Followed by a small fix, and then a larger fix when I was
> forced to look at the code in question ;)
>
>
>
> Cheers,
>
> Simon.
>
> On 31/12/2021 16:29, Fabrice Fontaine wrote:
> > Fix the following build failure with gcc 4.8 raised since version 2.86:
> >
> > option.c: In function 'one_opt':
> > option.c:2445:11: error: 'for' loop initial declarations are only allowed in C99 mode
> >            for (char *p = arg; *p; p++) {
> >            ^
> > option.c:2445:11: note: use option -std=c99 or -std=gnu99 to compile your code
> > option.c:2453:11: error: 'for' loop initial declarations are only allowed in C99 mode
> >            for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
> >            ^
> >
> > Fixes:
> >  - http://autobuild.buildroot.org/results/39b34a4e69fc10f4bd9d4ddb0ed8c0aae5741c84
> >
> > Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
> > ---
> >  src/option.c | 6 ++++--
> >  1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/src/option.c b/src/option.c
> > index ff54def..c57f6d8 100644
> > --- a/src/option.c
> > +++ b/src/option.c
> > @@ -2525,7 +2525,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
> >            arg += 9;
> >            if (strlen(arg) != 16)
> >                ret_err(gen_err);
> > -          for (char *p = arg; *p; p++) {
> > +          char *p;
> > +          for (*p = arg; *p; p++) {
> >              if (!isxdigit((int)*p))
> >                ret_err(gen_err);
> >            }
> > @@ -2533,7 +2534,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
> >
> >            u8 *u = daemon->umbrella_device;
> >            char word[3];
> > -          for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
> > +          u8 i;
> > +          for (i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
> >              memcpy(word, &(arg[0]), 2);
> >              *u++ = strtoul(word, NULL, 16);
> >            }
> >
>

From 0c89dd2fa0fe50b00bca638dbbacfbd361526e0a Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Date: Sun, 2 Jan 2022 21:57:52 +0100
Subject: [PATCH] src/pattern.c: fix build with gcc 4.8

Fix the following build failure:

pattern.c: In function 'is_valid_dns_name':
pattern.c:134:3: error: 'for' loop initial declarations are only allowed in C99 mode
   for (const char *c = value;; c++)
   ^
pattern.c:134:3: note: use option -std=c99 or -std=gnu99 to compile your code
pattern.c: In function 'is_valid_dns_name_pattern':
pattern.c:249:3: error: 'for' loop initial declarations are only allowed in C99 mode
   for (const char *c = value;; c++)
   ^

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2022-01-03 15:13:53 +00:00
Simon Kelley 011f8cf1d0 Tidy code for --umbrella option. 2022-01-01 23:33:39 +00:00
Simon Kelley 2748fb81e2 Fix 46312909d9 typo. 2022-01-01 23:03:26 +00:00
Fabrice Fontaine 46312909d9 src/option.c: fix build with gcc 4.8
Fix the following build failure with gcc 4.8 raised since version 2.86:

option.c: In function 'one_opt':
option.c:2445:11: error: 'for' loop initial declarations are only allowed in C99 mode
           for (char *p = arg; *p; p++) {
           ^
option.c:2445:11: note: use option -std=c99 or -std=gnu99 to compile your code
option.c:2453:11: error: 'for' loop initial declarations are only allowed in C99 mode
           for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
           ^

Fixes:
 - http://autobuild.buildroot.org/results/39b34a4e69fc10f4bd9d4ddb0ed8c0aae5741c84

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2022-01-01 23:00:25 +00:00
Simon Kelley 41adecad14 Include client address if TFTP file-not-found errors. 2022-01-01 22:15:16 +00:00
Simon Kelley ea5d8c56a0 Finesse parsing of --dhcp-remoteid and --dhcp-subscrid.
To be treated as hex, the pattern must consist of only hex digits AND
contain at least one ':'. Thanks to Bengt-Erik Sandstrom who tripped
over a pattern consisting of a decimal number which was interpreted
surprisingly.
2021-12-30 23:22:43 +00:00
Simon Kelley d242cbffa4 Add snooping of DHCPv6 prefix delegation to the DHCP-relay function. 2021-12-30 21:20:37 +00:00
Simon Kelley 1c8855ed10 Fix wrong client address for dhcp-script when DHCPv4 relay in use. 2021-12-26 16:35:54 +00:00
Simon Kelley ea33a01303 Fix rare "Internal error in cache" messages.
Fix error created in 1ce1c6beae

Many thanks to Hartmut Birr for finding the bug and bisecting to
the guilty commit.

The breaking commit creates cache entries which have F_NXDOMAIN
set but none of F_IPV4, F_IPV6 or F_SRV. If cache_scan_free() is called
to delete such an entry it will fail to do so.

If the cache has no free slots and the least-recently-used slot is such
an entry, then a new insertion will attempt to make space by calling
cache_scan_free(), which will fail when it should be impossible and
trigger the internal error.
2021-12-24 18:58:35 +00:00
Simon Kelley 18b1d1424e Generalise --dhcp-relay.
Sending via broadcast/multicast is now supported for both
IPv4 and IPv6 and the configuration syntax made
easier (but backwards compatible).
2021-12-20 16:40:41 +00:00
Simon Kelley 1176cd58c9 Fix regression in --rebind-domain-ok in 2.86
The 2.86 domain-match rewrite changed matching from
whole-labels to substring matching, so example.com
would match example.com and www.example.com, as before,
but also goodexample.com, which is a regression. This
restores the original behaviour.

Also restore the behaviour of --rebind-domain-ok=//
to match domains with onlt a single label and no dots.

Thanks to Sung Pae for reporting these bugs and supplying
an initial patch.
2021-12-08 23:51:38 +00:00
guns 44a4643b62 Correctly return a heap-allocated empty string instead of NULL
Commit 32e15c3f45 added the following
change:

  --- a/src/option.c
  +++ b/src/option.c
  @@ -654,7 +654,7 @@ static char *canonicalise_opt(char *s)
       return 0;

     if (strlen(s) == 0)
  -    return "";
  +    return opt_string_alloc("");

     unhide_metas(s);
     if (!(ret = canonicalise(s, &nomem)) && nomem)

Unfortunately, opt_string_alloc(const char *cp) returns NULL when
strlen(cp) == 0, which in turn causes --rebind-domain-ok='' to crash
with SIGSEGV.
2021-12-04 12:03:31 +00:00
Simon Kelley ed96efd865 Fix confusion with log-IDs and DNS retries.
The IDs logged when --log-queries=extra is in effect
can be wrong in three cases.

1) When query is retried in response to a a SERVFAIL or REFUSED
answer from upstream. In this case the ID of an unrelated query will
appear in the answer log lines.

2) When the same query arrives from two clients. The query is
sent upstream once, as designed, and the result returned to both clients,
as designed, but the reply to the first client gets the log-ID of the
second query in error.

3) When a query arrives, is sent upstream, and the reply comes back,
but the transaction is blocked awaiting a DNSSEC query needed to validate
the reply. If the client retries the query in this state, the blocking
DNSSEC query will be resent, as designed, but that send will be logged with
the ID of the original, currently blocked, query.

Thanks to  Dominik Derigs for his analysis of this problem.
2021-12-01 16:40:26 +00:00
Simon Kelley e3093b532c Fix problems with upper-case in domain-match.
The domain-match rewrite didn't take into account
that domain names are case-insensitive, so things like

--address=/Example.com/.....

didn't work correctly.
2021-11-28 18:39:42 +00:00
Simon Kelley 9560658c5b Fix crash in PXE/netboot when DNS server disabled. 2021-10-19 15:33:41 +01:00
Simon Kelley 37a70d39e0 Add --filter and --filter-AAAA options. 2021-10-07 23:12:59 +01:00
Dominik Derigs 72fac0810c dnsmasq.h has to be included first as it sources config.h
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-10-07 09:28:34 +01:00
Simon Kelley c166c07a93 Support IDN in --auth-zone. 2021-10-06 23:48:06 +01:00
Petr Menšík 39a625ff72 Disable transitional IDN rules, accept only sane names
Transitional encoding accepts every emoticon you can think about.
Because setlocale were not enabled before, IDN 2003 input was not
accepted by dnsmasq. It makes no sense therefore to maintain backward
compatibility. Accept only proper encoded unicode names and reject
random unicode characters.

Signed-off-by: Petr Menšík <pemensik@redhat.com>
2021-10-06 23:33:13 +01:00
Petr Menšík ad32ca18a7 Enable locale support for IDN at startup
--address=/münchen.de/ is not accepted unless LOCALEDIR is defined on
build. It is not by default. If LIBIDN1 or 2 is defined, call setlocale
to initialize locale required to translate domains to ascii form.

Signed-off-by: Petr Menšík <pemensik@redhat.com>
2021-10-06 23:23:51 +01:00
Simon Kelley efea282396 Fix logic in add_update_server() to make optimisation actually optimise. 2021-10-06 23:01:14 +01:00
Simon Kelley 33d6a01cd3 Use host byte-order variable for answer counting. 2021-10-06 22:54:35 +01:00
Simon Kelley d290630d31 Fix crash after re-reading an empty resolv.conf file.
If dnsmasq re-reads a resolv file, and it's empty, it will
retry after a delay. In the meantime, the old servers from the
resolv file have been deleted, but the servers_array doesn't
get updated, leading to dangling pointers and crashes.

Thanks to Brad Jorsch for finding and analysing this bug.

This problem was introduced in 2.86.
2021-10-06 22:31:06 +01:00
Simon Kelley d2ad5dc073 Fix truncation logic in make_local_answer()
add_resource_record() returns 1 if the record was added.
Only increment anscount of so.

Thanks to Petr Menšík for spotting the problem.
2021-10-05 23:38:20 +01:00
Simon Kelley 68ab5127af Man page tweak for --address and more than one address. 2021-10-05 22:50:58 +01:00
DL6ER 089a11f340 --local should behave as --server, not as --address according to the man page
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-10-05 22:47:10 +01:00
Olaf Hering de1d04eb66 remove stale contrib/Suse
dnsmasq is included in SUSE Linux since 2004.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
2021-09-30 12:17:44 +01:00
Dominik Derigs ed4e7defd7 Do not fail hard when rev-server has a non-zero final address part
Signed-off-by: DL6ER <dl6er@dl6er.de>
2021-09-30 11:52:24 +01:00
Simon Kelley 267ab619c4 Get compilation flags for libnftables from pkg-config.
Omission spotted by Olaf Hering. Thanks.
2021-09-29 23:24:52 +01:00
Matt Whitlock 0140454ba2 dnsmasq_time: avoid signed integer overflow when HAVE_BROKEN_RTC
The dnsmasq_time() function, in the case of HAVE_BROKEN_RTC, was calling
times() to read the number of ticks "elapsed since an arbitrary point in
the past" and then dividing that by sysconf(_SC_CLK_TCK) to compute the
number of seconds elapsed since that arbitrary instant. This works fine
until the number of ticks exceeds 2^31, beyond which time the function
would begin erroneously returning negative times. On my system this
happens after approximately 248 days of uptime. A symptom is that
dnsmasq no longer populates the resolver cache with DHCP-derived names
at startup, as the inserted cache entries immediately expire due to
having negative expiration times that cause is_expired() to return true
when called with now==0.

This commit replaces the archaic implementation of dnsmasq_time() with a
call to the POSIX-standardized clock_gettime(CLOCK_MONOTONIC), thereby
eliminating the need to convert manually from ticks to seconds. The new
implementation will yield correct results until the system uptime
exceeds approximately 68 years.

Signed-off-by: Matt Whitlock <dnsmasq@mattwhitlock.name>
2021-09-29 09:46:13 +01:00
Simon Kelley 2c60441239 Fix FTBFS when CONNTRACK and UBUS but not DNSSEC compile options selected. 2021-09-28 23:42:15 +01:00
Simon Kelley cbbd56c965 Build Debian binaries with NFTset support. 2021-09-27 23:16:18 +01:00
Simon Kelley 2561f9fe0e Fix confusion in DNS retries and --strict-order.
Behaviour to stop infinite loops when all servers return REFUSED
was wrongly activated on client retries, resulting in
incorrect REFUSED replies to client retries.

Thanks to Johannes Stezenbach for finding the problem.
2021-09-27 22:37:02 +01:00
72 changed files with 1489 additions and 1038 deletions

No files matched your search

+31
View File
@@ -8,6 +8,37 @@ version 2.87
Add --nftset option, like --ipset but for the newer nftables.
Thanks to Chen Zhenge for the patch.
Add --filter-A and --filter-AAAA options, to remove IPv4 or IPv6
addresses from DNS answers.
Fix crash doing netbooting when --port is set to zero
to disable the DNS server. Thanks to Drexl Johannes
for the bug report.
Generalise --dhcp-relay. Sending via broadcast/multicast is
now supported for both IPv4 and IPv6 and the configuration
syntax made easier (but backwards compatible).
Add snooping of IPv6 prefix-delegations to the DHCP-relay system.
Finesse parsing of --dhcp-remoteid and --dhcp-subscrid. To be treated
as hex, the pattern must consist of only hex digits AND contain
at least one ':'. Thanks to Bengt-Erik Sandstrom who tripped
over a pattern consisting of a decimal number which was interpreted
surprisingly.
Include client address in TFTP file-not-found error reports.
Thanks to Stefan Rink for the initial patch, which has been
re-worked by me (srk). All bugs mine.
Note in manpage the change in behaviour of -address. This behaviour
actually changed in v2.86, but was undocumented there. From 2.86 on,
(eg) --address=/example.com/1.2.3.4 ONLY applies to A queries. All other
types of query will be sent upstream. Pre 2.86, that would catch the
whole example.com domain and queries for other types would get
a local NODATA answer. The pre-2.86 behaviour is still available,
by configuring --address=/example.com/1.2.3.4 --local=/example.com/
version 2.86
Handle DHCPREBIND requests in the DHCPv6 server code.
+6 -5
View File
@@ -1,4 +1,4 @@
# dnsmasq is Copyright (c) 2000-2021 Simon Kelley
# 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
@@ -70,8 +70,9 @@ nettle_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_DNSSEC $(PKG_CO
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_libs = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG) --libs libnftables`
version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
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 ' '
@@ -91,7 +92,7 @@ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
all : $(BUILDDIR)
@cd $(BUILDDIR) && $(MAKE) \
top="$(top)" \
build_cflags="$(version) $(dbus_cflags) $(idn2_cflags) $(idn_cflags) $(ct_cflags) $(lua_cflags) $(nettle_cflags)" \
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)" \
-f $(top)/Makefile dnsmasq
@@ -116,7 +117,7 @@ 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)" \
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)" \
-f $(top)/Makefile dnsmasq
for f in `cd $(PO); echo *.po`; do \
-6
View File
@@ -1,6 +0,0 @@
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/
-27
View File
@@ -1,27 +0,0 @@
This is a patch against SuSEfirewall2-3.1-206 (SuSE 9.x and older)
It fixes the dependency 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 always '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`
-23
View File
@@ -1,23 +0,0 @@
--- 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
-111
View File
@@ -1,111 +0,0 @@
###############################################################################
#
# 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
-79
View File
@@ -1,79 +0,0 @@
#! /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
+4
View File
@@ -48,6 +48,10 @@ 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
+12 -1
View File
@@ -1,9 +1,20 @@
dnsmasq (2.87-1) unstable; urgency=low
* New upstream.
* 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)
+1 -1
View File
@@ -5,7 +5,7 @@ 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
pkg-config, libnftables-dev
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
+1
View File
@@ -60,6 +60,7 @@ Notes on configuring dnsmasq as packaged for Debian.
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
+4
View File
@@ -52,6 +52,10 @@ ifeq (,$(filter noidn, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_LIBIDN2
endif
ifeq (,$(filter nonftset, $(DEB_BUILD_OPTIONS)))
DEB_COPTS += -DHAVE_NFTSET
endif
ifeq (,$(filter noconntrack,$(DEB_BUILD_OPTIONS)))
ifeq ($(DEB_HOST_ARCH_OS),linux)
DEB_COPTS += -DHAVE_CONNTRACK
+52 -19
View File
@@ -345,8 +345,15 @@ forged answer to a DNS request for certain domain, before the correct answer can
.B \-f, --filterwin2k
Later versions of windows make periodic DNS requests which don't get sensible answers from
the public DNS and can cause problems by triggering dial-on-demand links. This flag turns on an option
to filter such requests. The requests blocked are for records of types SOA and SRV, and type ANY where the
requested name has underscores, to catch LDAP requests.
to filter such requests. The requests blocked are for records of type ANY
where the requested name has underscores, to catch LDAP requests, and for
\fBall\fP records of types SOA and SRV.
.TP
.B --filter-A
Remove A records from answers. No IPv4 addresses will be returned.
.TP
.B --filter-AAAA
Remove AAAA records from answers. No IPv6 addresses will be returned.
.TP
.B \-r, --resolv-file=<file>
Read the IP addresses of the upstream nameservers from <file>, instead of
@@ -516,11 +523,9 @@ Allowed prefix lengths are 1-32 (IPv4) and 1-128 (IPv6). If the prefix length is
.TP
.B \-A, --address=/<domain>[/<domain>...]/[<ipaddr>]
Specify an IP address to return for any host in the given domains.
Queries in the domains are never forwarded and always replied to
A (or AAAA) queries in the domains are never forwarded and always replied to
with the specified IP address which may be IPv4 or IPv6. To give
both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
To include multiple IP addresses for a single query, use
\fB--addn-hosts=<path>\fP instead.
multiple addresses or both IPv4 and IPv6 addresses for a domain, use repeated \fB--address\fP flags.
Note that /etc/hosts and DHCP leases override this for individual
names. A common use of this is to redirect the entire doubleclick.net
domain to some friendly local web server to avoid banner ads. The
@@ -538,6 +543,11 @@ address of 0.0.0.0 and its IPv6 equivalent of :: so
its subdomains. This is partly syntactic sugar for \fB--address=/example.com/0.0.0.0\fP
and \fB--address=/example.com/::\fP but is also more efficient than including both
as separate configuration lines. Note that NULL addresses normally work in the same way as localhost, so beware that clients looking up these names are likely to end up talking to themselves.
Note that the behaviour for queries which don't match the specified address literal changed in version 2.86.
Previous versions, configured with (eg) --address=/example.com/1.2.3.4 and then queried for a RR type other than
A would return a NoData answer. From 2.86, the query is sent upstream. To restore the pre-2.86 behaviour,
use the configuration --address=/example.com/1.2.3.4 --local=/example.com/
.TP
.B --ipset=/<domain>[/<domain>...]/<ipset>[,<ipset>...]
Places the resolved IP addresses of queries for one or more domains in
@@ -724,7 +734,7 @@ Specify the location of a pcap-format file which dnsmasq uses to dump copies of
.TP
.B --dumpmask=<mask>
Specify which types of packets should be added to the dumpfile. The argument should be the OR of the bitmasks for each type of packet to be dumped: it can be specified in hex by preceding the number with 0x in the normal way. Each time a packet is written to the dumpfile, dnsmasq logs the packet sequence and the mask
representing its type. The current types are: 0x0001 - DNS queries from clients 0x0002 DNS replies to clients 0x0004 - DNS queries to upstream 0x0008 - DNS replies from upstream 0x0010 - queries send upstream for DNSSEC validation 0x0020 - replies to queries for DNSSEC validation 0x0040 - replies to client queries which fail DNSSEC validation 0x0080 replies to queries for DNSSEC validation which fail validation.
representing its type. The current types are: 0x0001 - DNS queries from clients, 0x0002 DNS replies to clients, 0x0004 - DNS queries to upstream, 0x0008 - DNS replies from upstream, 0x0010 - queries send upstream for DNSSEC validation, 0x0020 - replies to queries for DNSSEC validation, 0x0040 - replies to client queries which fail DNSSEC validation, 0x0080 replies to queries for DNSSEC validation which fail validation, 0x1000 - DHCPv4, 0x2000 - DHCPv6, 0x4000 - Router advertisement, 0x8000 - TFTP.
.TP
.B --add-mac[=base64|text]
Add the MAC address of the requestor to DNS queries which are
@@ -737,6 +747,9 @@ have security and privacy implications. The warning about caching
given for \fB--add-subnet\fP applies to \fB--add-mac\fP too. An alternative encoding of the
MAC, as base64, is enabled by adding the "base64" parameter and a human-readable encoding of hex-and-colons is enabled by added the "text" parameter.
.TP
.B --strip-mac
Remove any MAC address information already in downstream queries before forwarding upstream.
.TP
.B --add-cpe-id=<string>
Add an arbitrary identifying string to DNS queries which are
forwarded upstream.
@@ -762,12 +775,18 @@ will add 1.2.3.0/24 for IPv4 requestors and ::/0 for IPv6 requestors.
.B --add-subnet=1.2.3.4/24,1.2.3.4/24
will add 1.2.3.0/24 for both IPv4 and IPv6 requestors.
.TP
.B --umbrella[=deviceid:<deviceid>[,orgid:<orgid>]]
.B --strip-subnet
Remove any subnet address already present in a downstream query before forwarding it upstream. If --add-subnet is set this also
ensures that any downstream-provided subnet is replaced by the one added by dnsmasq. Otherwise, dnsmaaq will NOT replace an
existing subnet in the query.
.TP
.B --umbrella[=[deviceid:<deviceid>][,orgid:<orgid>][,assetid:<id>]]
Embeds the requestor's IP address in DNS queries forwarded upstream.
If device id or organization id are specified, the information is
If device id or, asset id or organization id are specified, the information is
included in the forwarded queries and may be able to be used in
filtering policies and reporting. The order of the deviceid and orgid
attributes is irrelevant, but must be separated by a comma.
filtering policies and reporting. The order of the id
attributes is irrelevant, but they must be separated by a comma. Deviceid is
a sixteen digit hexadecimal number, org and asset ids are decimal numbers.
.TP
.B \-c, --cache-size=<cachesize>
Set the size of dnsmasq's cache. The default is 150 names. Setting the cache size to zero disables caching. Note: huge cache size impacts performance.
@@ -1322,7 +1341,7 @@ DHCP options. This make extra space available in the DHCP packet for
options but can, rarely, confuse old or broken clients. This flag
forces "simple and safe" behaviour to avoid problems in such a case.
.TP
.B --dhcp-relay=<local address>,<server address>[,<interface]
.B --dhcp-relay=<local address>[,<server address>][,<interface]
Configure dnsmasq to do DHCP relay. The local address is an address
allocated to an interface on the host running dnsmasq. All DHCP
requests arriving on that interface will we relayed to a remote DHCP
@@ -1330,10 +1349,9 @@ server at the server address. It is possible to relay from a single local
address to multiple remote servers by using multiple \fB--dhcp-relay\fP
configs with the same local address and different server
addresses. A server address must be an IP literal address, not a
domain name. In the case of DHCPv6, the server address may be the
ALL_SERVERS multicast address, ff05::1:3. In this case the interface
must be given, not be wildcard, and is used to direct the multicast to the
correct interface to reach the DHCP server.
domain name. If the server address is ommitted, the request will be
forwarded by broadcast (IPv4) or multicast (IPv6). In this case the interface
must be given and not be wildcard.
Access control for DHCP clients has the same rules as for the DHCP
server, see \fB--interface\fP, \fB--except-interface\fP, etc. The optional
@@ -1353,6 +1371,11 @@ supported: the relay function will take precedence.
Both DHCPv4 and DHCPv6 relay is supported. It's not possible to relay
DHCPv4 to a DHCPv6 server or vice-versa.
The DHCP relay function for IPv6 includes the ability to snoop
prefix-delegation from relayed DHCP transactions. See
.B --dhcp-script
for details.
.TP
.B \-U, --dhcp-vendorclass=set:<tag>,[enterprise:<IANA-enterprise number>,]<vendor-class>
Map from a vendor-class string to a tag. Most DHCP clients provide a
@@ -1763,15 +1786,25 @@ receives a HUP signal, the script will be invoked for existing leases
with an "old" event.
There are four further actions which may appear as the first argument
to the script, "init", "arp-add", "arp-del" and "tftp". More may be added in the future, so
There are five further actions which may appear as the first argument
to the script, "init", "arp-add", "arp-del", "relay-snoop" and "tftp".
More may be added in the future, so
scripts should be written to ignore unknown actions. "init" is
described below in
.B --leasefile-ro
The "tftp" action is invoked when a TFTP file transfer completes: the
arguments are the file size in bytes, the address to which the file
was sent, and the complete pathname of the file.
The "relay-snoop" action is invoked when dnsmasq is configured as a DHCP
relay for DHCPv6 and it relays a prefx delegation to a client. The arguments
are the name of the interface where the client is conected, its (link-local)
address on that interface and the delegated prefix. This information is
sufficient to install routes to the delegated prefix of a router. See
.B --dhcp-relay
for more details on configuring DHCP relay.
The "arp-add" and "arp-del" actions are only called if enabled with
.B --script-arp
They are are supplied with a MAC address and IP address as arguments. "arp-add" indicates
+2 -2
View File
@@ -2145,8 +2145,8 @@ msgstr "nicht unterstützte Anfrage von %s"
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgstr "Datei %s nicht gefunden"
msgid "file %s not found for %s"
msgstr "Datei %s nicht gefunden für %s"
#: tftp.c:602
#, c-format
+2 -2
View File
@@ -2213,8 +2213,8 @@ msgstr "pedido no-soportado desde %s"
#: tftp.c:512
#, fuzzy, c-format
msgid "file %s not found"
msgstr "archivo %s no encontrado"
msgid "file %s not found for %s"
msgstr "archivo %s no encontrado por %s"
#: tftp.c:602
#, c-format
+1 -1
View File
@@ -2114,7 +2114,7 @@ msgstr ""
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgid "file %s not found for %s"
msgstr ""
#: tftp.c:602
+2 -2
View File
@@ -2197,8 +2197,8 @@ msgstr "requ
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgstr "fichier %s non trouvé"
msgid "file %s not found for %s"
msgstr "fichier %s non trouvé pour %s"
#: tftp.c:602
#, c-format
+2 -2
View File
@@ -2460,8 +2460,8 @@ msgstr ""
# OK
#: tftp.c:512
#, fuzzy, c-format
msgid "file %s not found"
msgstr "lease tak ditemukan"
msgid "file %s not found for %s"
msgstr "file %s tidak ditemukan untuk %s"
#: tftp.c:602
#, c-format
+1 -1
View File
@@ -2114,7 +2114,7 @@ msgstr ""
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgid "file %s not found for %s"
msgstr ""
#: tftp.c:602
+2 -2
View File
@@ -2194,8 +2194,8 @@ msgstr ""
#: tftp.c:512
#, fuzzy, c-format
msgid "file %s not found"
msgstr "leie ikke funnet"
msgid "file %s not found for %s"
msgstr "fil %s ikke funnet for %s"
#: tftp.c:602
#, c-format
+2 -2
View File
@@ -2149,8 +2149,8 @@ msgstr "nieobsługiwane żądanie od komputera %s"
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgstr "plik %s nie został znaleziony"
msgid "file %s not found for %s"
msgstr "plik %s nie został znaleziony dla %s"
#: tftp.c:602
#, c-format
+1 -1
View File
@@ -2114,7 +2114,7 @@ msgstr ""
#: tftp.c:512
#, c-format
msgid "file %s not found"
msgid "file %s not found for %s"
msgstr ""
#: tftp.c:602
+2 -2
View File
@@ -2195,8 +2195,8 @@ msgstr ""
#: tftp.c:512
#, fuzzy, c-format
msgid "file %s not found"
msgstr "împrumutul nu a fost găsit"
msgid "file %s not found for %s"
msgstr "fișier %s nu a fost găsit pentru %s"
#: tftp.c:602
#, c-format
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+37 -21
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -413,7 +413,7 @@ static struct crec *cache_scan_free(char *name, union all_addr *addr, unsigned s
if ((crecp->flags & F_FORWARD) && hostname_isequal(cache_get_name(crecp), name))
{
/* Don't delete DNSSEC in favour of a CNAME, they can co-exist */
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV)) ||
if ((flags & crecp->flags & (F_IPV4 | F_IPV6 | F_SRV | F_NXDOMAIN)) ||
(((crecp->flags | flags) & F_CNAME) && !(crecp->flags & (F_DNSKEY | F_DS))))
{
if (crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG))
@@ -1399,10 +1399,12 @@ struct in_addr a_record_from_hosts(char *name, time_t now)
struct crec *crecp = NULL;
struct in_addr ret;
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
if (crecp->flags & F_HOSTS)
return crecp->addr.addr4;
/* If no DNS service, cache not initialised. */
if (daemon->port != 0)
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
if (crecp->flags & F_HOSTS)
return crecp->addr.addr4;
my_syslog(MS_DHCP | LOG_WARNING, _("No IPv4 address found for %s"), name);
ret.s_addr = 0;
@@ -1755,7 +1757,8 @@ void dump_cache(time_t now)
{
struct crec *cache ;
int i;
my_syslog(LOG_INFO, "Host Address Flags Expires");
my_syslog(LOG_INFO, "Host Address Flags Expires Source");
my_syslog(LOG_INFO, "------------------------------ ---------------------------------------- ---------- ------------------------ ------------");
for (i=0; i<hash_size; i++)
for (cache = hash_table[i]; cache; cache = cache->hash_next)
@@ -1813,7 +1816,10 @@ void dump_cache(time_t now)
else if (cache->flags & F_DNSKEY)
t = "K";
#endif
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s ", a, t,
else /* non-terminal */
t = "!";
p += sprintf(p, "%-40.40s %s%s%s%s%s%s%s%s%s%s ", a, t,
cache->flags & F_FORWARD ? "F" : " ",
cache->flags & F_REVERSE ? "R" : " ",
cache->flags & F_IMMORTAL ? "I" : " ",
@@ -1821,14 +1827,16 @@ void dump_cache(time_t now)
cache->flags & F_NEG ? "N" : " ",
cache->flags & F_NXDOMAIN ? "X" : " ",
cache->flags & F_HOSTS ? "H" : " ",
cache->flags & F_CONFIG ? "C" : " ",
cache->flags & F_DNSSECOK ? "V" : " ");
#ifdef HAVE_BROKEN_RTC
p += sprintf(p, "%lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
p += sprintf(p, "%-24lu", cache->flags & F_IMMORTAL ? 0: (unsigned long)(cache->ttd - now));
#else
p += sprintf(p, "%s", cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd)));
/* ctime includes trailing \n - eat it */
*(p-1) = 0;
p += sprintf(p, "%-24.24s", cache->flags & F_IMMORTAL ? "" : ctime(&(cache->ttd)));
#endif
if(cache->flags & (F_HOSTS | F_CONFIG) && cache->uid > 0)
p += sprintf(p, " %s", record_source(cache->uid));
my_syslog(LOG_INFO, "%s", daemon->namebuff);
}
}
@@ -1949,12 +1957,13 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
char *source, *dest = arg;
char *verb = "is";
char *extra = "";
char portstring[7]; /* space for #<portnum> */
if (!option_bool(OPT_LOG))
return;
/* build query type string if requested */
if(type > 0)
if (!(flags & (F_SERVER | F_IPSET)) && type > 0)
arg = querystr(arg, type);
#ifdef HAVE_DNSSEC
@@ -1990,8 +1999,15 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
}
}
else if (flags & (F_IPV4 | F_IPV6))
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
addr, daemon->addrbuff, ADDRSTRLEN);
{
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
addr, daemon->addrbuff, ADDRSTRLEN);
if ((flags & F_SERVER) && type != NAMESERVER_PORT)
{
extra = portstring;
sprintf(portstring, "#%u", type);
}
}
else
dest = arg;
}
@@ -2043,7 +2059,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
}
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_SERVER)
else if (flags & F_DNSSEC)
{
source = arg;
verb = "to";
}
else if (flags & F_SERVER)
{
source = "forwarded";
verb = "to";
@@ -2053,11 +2074,6 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
source = arg;
verb = "from";
}
else if (flags & F_DNSSEC)
{
source = arg;
verb = "to";
}
else if (flags & F_IPSET)
{
source = type ? "ipset add" : "nftset add";
+2 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -20,7 +20,7 @@
#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 1280 /* "go anywhere" UDP packet size */
#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 */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+8 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -52,6 +52,9 @@ const char* introspection_xml_template =
" <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"
@@ -694,6 +697,10 @@ DBusHandlerResult message_handler(DBusConnection *connection,
{
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");
+18 -2
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -985,11 +985,27 @@ void log_context(int family, struct dhcp_context *context)
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);
#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);
#endif
if (relay->interface)
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay from %s to %s via %s"), daemon->addrbuff, daemon->namebuff, 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);
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+115 -62
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -20,8 +20,6 @@
struct iface_param {
struct dhcp_context *current;
struct dhcp_relay *relay;
struct in_addr relay_local;
int ind;
};
@@ -34,7 +32,7 @@ static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index);
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)
@@ -177,11 +175,16 @@ 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;
#if defined (HAVE_LINUX_NETWORK)
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_DHCP, (void *)daemon->dhcp_packet.iov_base, sz, (union mysockaddr *)&dest, NULL,
pxe_fd ? PXE_PORT : daemon->dhcp_server_port);
#endif
#if defined (HAVE_LINUX_NETWORK)
if (ioctl(fd, SIOCGSTAMP, &tv) == 0)
recvtime = tv.tv_sec;
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)
@@ -302,12 +305,7 @@ void dhcp_packet(time_t now, int pxe_fd)
for (context = daemon->dhcp; context; context = context->next)
context->current = context;
for (relay = daemon->relay4; relay; relay = relay->next)
relay->current = relay;
parm.current = NULL;
parm.relay = NULL;
parm.relay_local.s_addr = 0;
parm.ind = iface_index;
if (!iface_check(AF_INET, (union all_addr *)&iface_addr, ifr.ifr_name, NULL))
@@ -329,15 +327,19 @@ void dhcp_packet(time_t now, int pxe_fd)
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;
/* We're relaying this request */
if (parm.relay_local.s_addr != 0 &&
relay_upstream4(parm.relay, mess, (size_t)sz, iface_index))
/* 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;
@@ -455,6 +457,14 @@ void dhcp_packet(time_t now, int pxe_fd)
#elif defined(HAVE_BSD_NETWORK)
else
{
#ifdef HAVE_DUMPFILE
dest.sin_addr.s_addr = (ntohs(mess->flags) & 0x8000) ? INADDR_BROADCAST : mess->yiaddr;
dest.sin_port = htons(daemon->dhcp_client_port);
dump_packet(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
(union mysockaddr *)&dest, daemon->dhcp_server_port);
#endif
send_via_bpf(mess, iov.iov_len, iface_addr, &ifr);
return;
}
@@ -463,6 +473,11 @@ 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(DUMP_DHCP, (void *)iov.iov_base, iov.iov_len, NULL,
(union mysockaddr *)&dest, daemon->dhcp_server_port);
#endif
while(retry_send(sendmsg(fd, &msg, 0)));
@@ -613,14 +628,9 @@ static int complete_context(struct in_addr local, int if_index, char *label,
}
for (relay = daemon->relay4; relay; relay = relay->next)
if (if_index == param->ind && relay->local.addr4.s_addr == local.s_addr && relay->current == relay &&
(param->relay_local.s_addr == 0 || param->relay_local.s_addr == local.s_addr))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = local;
}
if (relay->local.addr4.s_addr == local.s_addr)
relay->iface_index = if_index;
return 1;
}
@@ -1061,53 +1071,96 @@ char *host_from_dns(struct in_addr addr)
return NULL;
}
static int relay_upstream4(struct dhcp_relay *relay, struct dhcp_packet *mess, size_t sz, int iface_index)
static int relay_upstream4(int iface_index, struct dhcp_packet *mess, size_t sz)
{
/* ->local is same value for all relays on ->current chain */
union all_addr from;
struct in_addr giaddr = mess->giaddr;
u8 hops = mess->hops;
struct dhcp_relay *relay;
if (mess->op != BOOTREQUEST)
return 0;
/* source address == relay address */
from.addr4 = relay->local.addr4;
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;
/* already gatewayed ? */
if (mess->giaddr.s_addr)
{
/* if so check if by us, to stomp on loops. */
if (mess->giaddr.s_addr == relay->local.addr4.s_addr)
return 1;
}
else
{
/* plug in our address */
mess->giaddr.s_addr = relay->local.addr4.s_addr;
}
for (; relay; relay = relay->next)
if (relay->iface_index != 0 && relay->iface_index == iface_index)
{
union mysockaddr to;
union all_addr from;
if ((mess->hops++) > 20)
return 1;
mess->hops = hops;
mess->giaddr = giaddr;
if ((mess->hops++) > 20)
continue;
/* source address == relay address */
from.addr4 = relay->local.addr4;
for (; relay; relay = relay->current)
{
union mysockaddr to;
to.sa.sa_family = AF_INET;
to.in.sin_addr = relay->server.addr4;
to.in.sin_port = htons(daemon->dhcp_server_port);
send_from(daemon->dhcpfd, 0, (char *)mess, sz, &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
/* 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(daemon->dhcp_server_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
{
inet_ntop(AF_INET, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET, &relay->server.addr4, daemon->dhcp_buff2, DHCP_BUFF_SZ);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->dhcp_buff2);
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(DUMP_DHCP, (void *)mess, sz, &fromsock, &to, 0);
}
/* Save this for replies */
relay->iface_index = iface_index;
}
#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;
}
+3 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -55,6 +55,8 @@
#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
+51 -44
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -22,8 +22,7 @@
struct iface_param {
struct dhcp_context *current;
struct dhcp_relay *relay;
struct in6_addr fallback, relay_local, ll_addr, ula_addr;
struct in6_addr fallback, ll_addr, ula_addr;
int ind, addr_match;
};
@@ -90,7 +89,6 @@ void dhcp6_init(void)
void dhcp6_packet(time_t now)
{
struct dhcp_context *context;
struct dhcp_relay *relay;
struct iface_param parm;
struct cmsghdr *cmptr;
struct msghdr msg;
@@ -105,7 +103,8 @@ void dhcp6_packet(time_t now)
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;
@@ -119,6 +118,11 @@ void dhcp6_packet(time_t now)
if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
return;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_DHCPV6, (void *)daemon->dhcp_packet.iov_base, sz,
(union mysockaddr *)&from, NULL, DHCPV6_SERVER_PORT);
#endif
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
@@ -135,9 +139,13 @@ void dhcp6_packet(time_t now)
if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
return;
if ((port = relay_reply6(&from, sz, ifr.ifr_name)) != 0)
if (relay_reply6(&from, sz, ifr.ifr_name))
{
from.sin6_port = htons(port);
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL,
(union mysockaddr *)&from, DHCPV6_SERVER_PORT);
#endif
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
@@ -145,7 +153,7 @@ void dhcp6_packet(time_t now)
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;
@@ -155,14 +163,12 @@ void dhcp6_packet(time_t now)
return;
parm.current = NULL;
parm.relay = NULL;
memset(&parm.relay_local, 0, IN6ADDRSZ);
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
@@ -200,13 +206,25 @@ void dhcp6_packet(time_t now)
context->current = context;
memset(&context->local6, 0, IN6ADDRSZ);
}
for (relay = daemon->relay6; relay; relay = relay->next)
relay->current = relay;
/* 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)
{
@@ -218,23 +236,10 @@ void dhcp6_packet(time_t now)
return;
}
if (parm.relay)
{
/* Ignore requests sent to the ALL_SERVERS multicast address for relay when
we're listening there for DHCPv6 server reasons. */
struct in6_addr all_servers;
inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id, now);
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,
@@ -247,11 +252,16 @@ void dhcp6_packet(time_t now)
if (port != 0)
{
from.sin6_port = htons(port);
while (retry_send(sendto(daemon->dhcp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&from,
sizeof(from))));
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1),
NULL, (union mysockaddr *)&from, DHCPV6_SERVER_PORT);
#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);
@@ -312,6 +322,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
struct dhcp_relay *relay;
struct iface_param *param = vparam;
struct iname *tmp;
int match = !daemon->if_addrs;
(void)scope; /* warning */
@@ -333,7 +344,7 @@ static int complete_context6(struct in6_addr *local, int prefix,
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;
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
@@ -405,16 +416,12 @@ static int complete_context6(struct in6_addr *local, int prefix,
}
}
}
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay &&
(IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
{
relay->current = param->relay;
param->relay = relay;
param->relay_local = *local;
}
if (match)
for (relay = daemon->relay6; relay; relay = relay->next)
if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6))
relay->iface_index = if_index;
return 1;
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+23 -3
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -17,8 +17,13 @@
/* Declare static char *compiler_opts in config.h */
#define DNSMASQ_COMPILE_OPTS
/* dnsmasq.h has to be included first as it sources config.h */
#include "dnsmasq.h"
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
#include <locale.h>
#endif
struct daemon *daemon;
static volatile pid_t pid = 0;
@@ -69,8 +74,10 @@ int main (int argc, char **argv)
int tftp_prefix_missing = 0;
#endif
#ifdef LOCALEDIR
#if defined(HAVE_IDN) || defined(HAVE_LIBIDN2) || defined(LOCALEDIR)
setlocale(LC_ALL, "");
#endif
#ifdef LOCALEDIR
bindtextdomain("dnsmasq", LOCALEDIR);
textdomain("dnsmasq");
#endif
@@ -727,7 +734,11 @@ int main (int argc, char **argv)
/* if we are to run scripts, we need to fork a helper before dropping root. */
daemon->helperfd = -1;
#ifdef HAVE_SCRIPT
if ((daemon->dhcp || daemon->dhcp6 || option_bool(OPT_TFTP) || option_bool(OPT_SCRIPT_ARP)) &&
if ((daemon->dhcp ||
daemon->dhcp6 ||
daemon->relay6 ||
option_bool(OPT_TFTP) ||
option_bool(OPT_SCRIPT_ARP)) &&
(daemon->lease_change_command || daemon->luascript))
daemon->helperfd = create_helper(pipewrite, err_pipe[1], script_uid, script_gid, max_fd);
#endif
@@ -1132,6 +1143,10 @@ int main (int argc, char **argv)
while (helper_buf_empty() && do_tftp_script_run());
# endif
# ifdef HAVE_DHCP6
while (helper_buf_empty() && do_snoop_script_run());
# endif
if (!helper_buf_empty())
poll_listen(daemon->helperfd, POLLOUT);
#else
@@ -1682,6 +1697,11 @@ static void poll_resolv(int force, int do_reload, time_t now)
}
else
{
/* If we're delaying things, we don't call check_servers(), but
reload_servers() may have deleted some servers, rendering the server_array
invalid, so just rebuild that here. Once reload_servers() succeeds,
we call check_servers() above, which calls build_server_array itself. */
build_server_array();
latest->mtime = 0;
if (!warned)
{
+55 -20
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -14,7 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define COPYRIGHT "Copyright (c) 2000-2021 Simon Kelley"
#define COPYRIGHT "Copyright (c) 2000-2022 Simon Kelley"
/* We do defines that influence behavior of stdio.h, so complain
if included too early. */
@@ -275,7 +275,11 @@ struct event_desc {
#define OPT_UMBRELLA_DEVID 64
#define OPT_CMARK_ALST_EN 65
#define OPT_QUIET_TFTP 66
#define OPT_LAST 67
#define OPT_FILTER_A 67
#define OPT_FILTER_AAAA 68
#define OPT_STRIP_ECS 69
#define OPT_STRIP_MAC 70
#define OPT_LAST 71
#define OPTION_BITS (sizeof(unsigned int)*8)
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
@@ -686,14 +690,18 @@ struct hostsfile {
};
/* packet-dump flags */
#define DUMP_QUERY 0x0001
#define DUMP_REPLY 0x0002
#define DUMP_UP_QUERY 0x0004
#define DUMP_UP_REPLY 0x0008
#define DUMP_SEC_QUERY 0x0010
#define DUMP_SEC_REPLY 0x0020
#define DUMP_BOGUS 0x0040
#define DUMP_SEC_BOGUS 0x0080
#define DUMP_QUERY 0x0001
#define DUMP_REPLY 0x0002
#define DUMP_UP_QUERY 0x0004
#define DUMP_UP_REPLY 0x0008
#define DUMP_SEC_QUERY 0x0010
#define DUMP_SEC_REPLY 0x0020
#define DUMP_BOGUS 0x0040
#define DUMP_SEC_BOGUS 0x0080
#define DUMP_DHCP 0x1000
#define DUMP_DHCPV6 0x2000
#define DUMP_RA 0x4000
#define DUMP_TFTP 0x8000
/* DNSSEC status values. */
#define STAT_SECURE 0x10000
@@ -720,7 +728,7 @@ struct hostsfile {
#define FREC_NOREBIND 1
#define FREC_CHECKING_DISABLED 2
#define FREC_HAS_SUBNET 4
#define FREC_NO_CACHE 4
#define FREC_DNSKEY_QUERY 8
#define FREC_DS_QUERY 16
#define FREC_AD_QUESTION 32
@@ -729,7 +737,6 @@ struct hostsfile {
#define FREC_TEST_PKTSZ 256
#define FREC_HAS_EXTRADATA 512
#define FREC_HAS_PHEADER 1024
#define FREC_NO_CACHE 2048
#define HASH_SIZE 32 /* SHA-256 digest size */
@@ -776,6 +783,7 @@ struct frec {
#define ACTION_TFTP 5
#define ACTION_ARP 6
#define ACTION_ARP_DEL 7
#define ACTION_RELAY_SNOOP 8
#define LEASE_NEW 1 /* newly created */
#define LEASE_CHANGED 2 /* modified */
@@ -1074,7 +1082,14 @@ struct dhcp_relay {
union all_addr local, server;
char *interface; /* Allowable interface for replies from server, and dest for IPv6 multicast */
int iface_index; /* working - interface in which requests arrived, for return */
struct dhcp_relay *current, *next;
#ifdef HAVE_SCRIPT
struct snoop_record {
struct in6_addr client, prefix;
int prefix_len;
struct snoop_record *next;
} *snoop_records;
#endif
struct dhcp_relay *next;
};
extern struct daemon {
@@ -1173,9 +1188,12 @@ extern struct daemon {
char *packet; /* packet buffer */
int packet_buff_sz; /* size of above */
char *namebuff; /* MAXDNAME size buffer */
#if (defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)) || defined(HAVE_DNSSEC)
/* CONNTRACK UBUS code uses this buffer, as well as DNSSEC code. */
char *workspacename;
#endif
#ifdef HAVE_DNSSEC
char *keyname; /* MAXDNAME size buffer */
char *workspacename; /* ditto */
unsigned long *rr_status; /* ceiling in TTL from DNSSEC or zero for insecure */
int rr_status_sz;
int dnssec_no_time_check;
@@ -1222,13 +1240,18 @@ extern struct daemon {
unsigned char *duid;
struct iovec outpacket;
int dhcp6fd, icmp6fd;
# ifdef HAVE_SCRIPT
struct snoop_record *free_snoops;
# endif
#endif
/* DBus stuff */
/* void * here to avoid depending on dbus headers outside dbus.c */
void *dbus;
#ifdef HAVE_DBUS
struct watch *watches;
#endif
/* UBus stuff */
#ifdef HAVE_UBUS
/* void * here to avoid depending on ubus headers outside ubus.c */
@@ -1371,6 +1394,7 @@ void safe_pipe(int *fd, int read_noblock);
void *whine_malloc(size_t size);
int sa_len(union mysockaddr *addr);
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
int hostname_order(const char *a, const char *b);
int hostname_isequal(const char *a, const char *b);
int hostname_issubdomain(char *a, char *b);
time_t dnsmasq_time(void);
@@ -1613,6 +1637,9 @@ void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer);
void queue_arp(int action, unsigned char *mac, int maclen,
int family, union all_addr *addr);
int helper_buf_empty(void);
#ifdef HAVE_DHCP6
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len);
#endif
#endif
/* tftp.c */
@@ -1655,10 +1682,13 @@ void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac,
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
struct in6_addr *fallback, struct in6_addr *ll_addr, struct in6_addr *ula_addr,
size_t sz, struct in6_addr *client_addr, time_t now);
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz, struct in6_addr *peer_address,
int relay_upstream6(int iface_index, ssize_t sz, struct in6_addr *peer_address,
u32 scope_id, time_t now);
unsigned short relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
int relay_reply6( struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface);
# ifdef HAVE_SCRIPT
int do_snoop_script_run(void);
# endif
#endif
/* dhcp-common.c */
@@ -1746,7 +1776,11 @@ int do_poll(int timeout);
size_t rrfilter(struct dns_header *header, size_t plen, int mode);
u16 *rrfilter_desc(int type);
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
/* modes. */
#define RRFILTER_EDNS0 0
#define RRFILTER_DNSSEC 1
#define RRFILTER_A 2
#define RRFILTER_AAAA 3
/* edns0.c */
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign, int *is_last);
@@ -1754,7 +1788,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do, int replace);
size_t add_do_bit(struct dns_header *header, size_t plen, unsigned char *limit);
size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *limit,
union mysockaddr *source, time_t now, int *check_subnet, int *cacheable);
union mysockaddr *source, time_t now, int *cacheable);
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
/* arp.c */
@@ -1764,7 +1798,8 @@ int do_arp_script_run(void);
/* dump.c */
#ifdef HAVE_DUMPFILE
void dump_init(void);
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst);
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src,
union mysockaddr *dst, int port);
#endif
/* domain-match.c */
+32 -32
View File
@@ -1867,7 +1867,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
int type1, class1, rdlen1 = 0, type2, class2, rdlen2, qclass, qtype, targetidx;
int i, j, rc = STAT_INSECURE;
int secure = STAT_SECURE;
/* extend rr_status if necessary */
if (daemon->rr_status_sz < ntohs(header->ancount) + ntohs(header->nscount))
{
@@ -1989,7 +1989,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
{
/* NSEC and NSEC3 records must be signed. We make this assumption elsewhere. */
if (type1 == T_NSEC || type1 == T_NSEC3)
rc = STAT_INSECURE;
return STAT_BOGUS | DNSSEC_FAIL_NOSIG;
else if (nons && i >= ntohs(header->ancount))
/* If we're validating a DS reply, rather than looking for the value of AD bit,
we only care that NSEC and NSEC3 RRs in the auth section are signed.
@@ -2003,6 +2003,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
rc = zone_status(name, class1, keyname, now);
if (STAT_ISEQUAL(rc, STAT_SECURE))
rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
if (class)
*class = class1; /* Class for NEED_DS or NEED_KEY */
}
@@ -2081,36 +2082,35 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
}
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
if (STAT_ISEQUAL(secure, STAT_SECURE))
for (j = 0; j <targetidx; j++)
if ((p2 = targets[j]))
{
if (neganswer)
*neganswer = 1;
if (!extract_name(header, plen, &p2, name, 1, 10))
return STAT_BOGUS; /* bad packet */
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
/* For anything other than a DS record, this situation is OK if either
the answer is in an unsigned zone, or there's a NSEC records. */
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl))
{
/* Empty DS without NSECS */
if (qtype == T_DS)
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
if (STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
{
if (class)
*class = qclass; /* Class for NEED_DS or NEED_KEY */
return rc;
}
return STAT_BOGUS | DNSSEC_FAIL_NONSEC; /* signed zone, no NSECs */
}
}
for (j = 0; j <targetidx; j++)
if ((p2 = targets[j]))
{
if (neganswer)
*neganswer = 1;
if (!extract_name(header, plen, &p2, name, 1, 10))
return STAT_BOGUS; /* bad packet */
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype) */
/* For anything other than a DS record, this situation is OK if either
the answer is in an unsigned zone, or there's a NSEC records. */
if (!prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl))
{
/* Empty DS without NSECS */
if (qtype == T_DS)
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
if (!STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
{
if (class)
*class = qclass; /* Class for NEED_DS or NEED_KEY */
return rc;
}
return STAT_BOGUS | DNSSEC_FAIL_NONSEC; /* signed zone, no NSECs */
}
}
return secure;
}
+96 -77
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -395,7 +395,7 @@ int is_local_answer(time_t now, int first, char *name)
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;
int trunc = 0, anscount = 0;
unsigned char *p;
int start;
union all_addr addr;
@@ -418,9 +418,8 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
else
addr.addr4 = srv->addr;
header->ancount = htons(ntohs(header->ancount) + 1);
if (!add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_A, C_IN, "4", &addr))
return 0;
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);
}
@@ -434,14 +433,15 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
else
addr.addr6 = srv->addr;
header->ancount = htons(ntohs(header->ancount) + 1);
add_resource_record(header, limit, &trunc, sizeof(struct dns_header), &p, daemon->local_ttl, NULL, T_AAAA, C_IN, "6", &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;
}
@@ -494,7 +494,7 @@ static int order(char *qdomain, size_t qlen, struct server *serv)
if (qlen > dlen)
return -1;
return strcmp(qdomain, serv->domain);
return hostname_order(qdomain, serv->domain);
}
static int order_servers(struct server *s1, struct server *s2)
@@ -542,22 +542,39 @@ static int order_qsort(const void *a, const void *b)
return rc;
}
/* Must be called before add_update_server() to set daemon->servers_tail */
void mark_servers(int flag)
{
struct server *serv;
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;
{
if (serv->flags & flag)
serv->flags |= SERV_MARK;
else
serv->flags &= ~SERV_MARK;
for (serv = daemon->local_domains; 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)
@@ -565,7 +582,7 @@ void cleanup_servers(void)
struct server *serv, *tmp, **up;
/* unlink and free anything still marked. */
for (serv = daemon->servers, up = &daemon->servers; serv; serv = tmp)
for (serv = daemon->servers, up = &daemon->servers, daemon->servers_tail = NULL; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
@@ -581,19 +598,6 @@ void cleanup_servers(void)
daemon->servers_tail = serv;
}
}
for (serv = daemon->local_domains, up = &daemon->local_domains; serv; serv = tmp)
{
tmp = serv->next;
if (serv->flags & SERV_MARK)
{
*up = serv->next;
free(serv->domain);
free(serv);
}
else
up = &serv->next;
}
}
int add_update_server(int flags,
@@ -626,36 +630,17 @@ int add_update_server(int flags,
if (!alloc_domain)
return 0;
/* See if there is a suitable candidate, and unmark
only do this for forwarding servers, not
address or local, to avoid delays on large numbers. */
if (flags & SERV_IS_LOCAL)
for (serv = daemon->servers; serv; serv = serv->next)
if ((serv->flags & SERV_MARK) &&
hostname_isequal(alloc_domain, serv->domain))
break;
if (serv)
{
free(alloc_domain);
alloc_domain = serv->domain;
}
else
{
size_t size;
if (flags & SERV_IS_LOCAL)
{
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 (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
else if (flags & SERV_4ADDR)
size = sizeof(struct serv_addr4);
else
size = sizeof(struct server);
size = sizeof(struct serv_local);
if (!(serv = whine_malloc(size)))
{
@@ -663,19 +648,53 @@ int add_update_server(int flags,
return 0;
}
if (flags & SERV_IS_LOCAL)
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)
{
serv->next = daemon->local_domains;
daemon->local_domains = serv;
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 (flags & SERV_4ADDR)
((struct serv_addr4*)serv)->addr = local_addr->addr4;
if (flags & SERV_6ADDR)
((struct serv_addr6*)serv)->addr = local_addr->addr6;
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 */
@@ -684,20 +703,20 @@ int add_update_server(int flags,
else
daemon->servers = serv;
daemon->servers_tail = serv;
}
#ifdef HAVE_LOOP
serv->uid = rand32();
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;
}
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);
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+73 -24
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -18,6 +18,8 @@
#ifdef HAVE_DUMPFILE
#include <netinet/icmp6.h>
static u32 packet_count;
/* https://wiki.wireshark.org/Development/LibpcapFileFormat */
@@ -79,7 +81,9 @@ void dump_init(void)
}
}
void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, union mysockaddr *dst)
/* port == -1 ->ICMPv6 */
void dump_packet(int mask, void *packet, size_t len,
union mysockaddr *src, union mysockaddr *dst, int port)
{
struct ip ip;
struct ip6_hdr ip6;
@@ -101,7 +105,7 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
return;
/* So wireshark can Id the packet. */
udp.uh_sport = udp.uh_dport = htons(NAMESERVER_PORT);
udp.uh_sport = udp.uh_dport = htons(port);
if (src)
family = src->sa.sa_family;
@@ -115,10 +119,19 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
memset(&ip6, 0, sizeof(ip6));
ip6.ip6_vfc = 6 << 4;
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
ip6.ip6_nxt = IPPROTO_UDP;
ip6.ip6_hops = 64;
if (port == -1)
{
ip6.ip6_plen = htons(len);
ip6.ip6_nxt = IPPROTO_ICMPV6;
}
else
{
ip6.ip6_plen = htons(sizeof(struct udphdr) + len);
ip6.ip6_nxt = IPPROTO_UDP;
}
if (src)
{
memcpy(&ip6.ip6_src, &src->in6.sin6_addr, IN6ADDRSZ);
@@ -134,9 +147,8 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
/* start UDP checksum */
for (sum = 0, i = 0; i < IN6ADDRSZ; i+=2)
{
sum += ip6.ip6_src.s6_addr[i] + (ip6.ip6_src.s6_addr[i+1] << 8) ;
sum += ip6.ip6_dst.s6_addr[i] + (ip6.ip6_dst.s6_addr[i+1] << 8) ;
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
@@ -147,9 +159,18 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) / 4;
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
ip.ip_ttl = IPDEFTTL;
ip.ip_p = IPPROTO_UDP;
if (port == -1)
{
ip.ip_len = htons(sizeof(struct ip) + len);
ip.ip_p = IPPROTO_ICMP;
}
else
{
ip.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + len);
ip.ip_p = IPPROTO_UDP;
}
if (src)
{
@@ -180,31 +201,59 @@ void dump_packet(int mask, void *packet, size_t len, union mysockaddr *src, unio
if (len & 1)
((unsigned char *)packet)[len] = 0; /* for checksum, in case length is odd. */
udp.uh_sum = 0;
udp.uh_ulen = htons(sizeof(struct udphdr) + len);
sum += htons(IPPROTO_UDP);
sum += 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;
if (port == -1)
{
/* ICMP - ICMPv6 packet is a superset of ICMP */
struct icmp6_hdr *icmp = packet;
/* See comment in UDP code below. */
sum += htons((family == AF_INET6) ? IPPROTO_ICMPV6 : IPPROTO_ICMP);
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;
}
else
{
/* 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;
}
rc = gettimeofday(&time, NULL);
pcap_header.ts_sec = time.tv_sec;
pcap_header.ts_usec = time.tv_usec;
pcap_header.incl_len = pcap_header.orig_len = ipsz + sizeof(udp) + len;
if (rc == -1 ||
!read_write(daemon->dumpfd, (void *)&pcap_header, sizeof(pcap_header), 0) ||
!read_write(daemon->dumpfd, iphdr, ipsz, 0) ||
!read_write(daemon->dumpfd, (void *)&udp, sizeof(udp), 0) ||
(port != -1 && !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
my_syslog(LOG_INFO, _("dumping UDP packet %u mask 0x%04x"), ++packet_count, mask);
my_syslog(LOG_INFO, _("dumping packet %u mask 0x%04x"), ++packet_count, mask);
}
+84 -58
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -178,7 +178,7 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
memcpy(buff, datap, rdlen);
/* now, delete OPT RR */
plen = rrfilter(header, plen, 0);
plen = rrfilter(header, plen, RRFILTER_EDNS0);
/* Now, force addition of a new one */
p = NULL;
@@ -264,44 +264,62 @@ static void encoder(unsigned char *in, char *out)
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 maclen, replace = 2; /* can't get mac address, just delete any incoming. */
int replace = 0, maclen = 0;
unsigned char mac[DHCP_CHADDR_MAX];
char encode[18]; /* handle 6 byte MACs */
char encode[18]; /* handle 6 byte MACs ONLY */
if ((maclen = find_mac(l3, mac, 1, now)) == 6)
if ((option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX)) && (maclen = find_mac(l3, mac, 1, now)) == 6)
{
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;
}
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;
return add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_NOMDEVICEID, (unsigned char *)encode, strlen(encode), 0, replace);
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;
int maclen = 0, replace = 0;
unsigned char mac[DHCP_CHADDR_MAX];
if ((maclen = find_mac(l3, mac, 1, now)) != 0)
if (option_bool(OPT_ADD_MAC) && (maclen = find_mac(l3, mac, 1, now)) != 0)
{
*cacheablep = 0;
plen = add_pseudoheader(header, plen, limit, PACKETSZ, EDNS0_OPTION_MAC, mac, maclen, 0, 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;
}
@@ -378,15 +396,29 @@ static size_t calc_subnet_opt(struct subnet_opt *opt, union mysockaddr *source,
return len + 4;
}
static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned char *limit, union mysockaddr *source, int *cacheable)
/* 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 len;
int replace = 0, len = 0;
struct subnet_opt opt;
len = calc_subnet_opt(&opt, source, cacheable);
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, 0);
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)
@@ -460,47 +492,45 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
u8 *u = &opt.fields[0];
if (daemon->umbrella_org) {
PUTSHORT(UMBRELLA_ORG, u);
PUTLONG(daemon->umbrella_org, u);
}
int family = source->sa.sa_family;
PUTSHORT(family == AF_INET ? UMBRELLA_IPV4 : UMBRELLA_IPV6, u);
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 (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);
}
int len = u - &opt.magic[0];
return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_UMBRELLA, (unsigned char *)&opt, len, 0, 1);
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 *check_subnet, int *cacheable)
union mysockaddr *source, time_t now, int *cacheable)
{
*check_subnet = 0;
*cacheable = 1;
if (option_bool(OPT_ADD_MAC))
plen = add_mac(header, plen, limit, source, now, cacheable);
if (option_bool(OPT_MAC_B64) || option_bool(OPT_MAC_HEX))
plen = add_dns_client(header, plen, limit, source, now, cacheable);
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,
@@ -509,11 +539,7 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
if (option_bool(OPT_UMBRELLA))
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
if (option_bool(OPT_CLIENT_SUBNET))
{
plen = add_source_addr(header, plen, limit, source, cacheable);
*check_subnet = 1;
}
plen = add_source_addr(header, plen, limit, source, cacheable);
return plen;
}
+257 -160
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -19,6 +19,9 @@
static struct frec *get_new_frec(time_t now, struct server *serv, int force);
static struct frec *lookup_frec(unsigned short id, int fd, void *hash, int *firstp, int *lastp);
static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigned int flagmask);
#ifdef HAVE_DNSSEC
static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header);
#endif
static unsigned short get_id(void);
static void free_frec(struct frec *f);
@@ -122,9 +125,17 @@ static void set_outgoing_mark(struct frec *forward, int fd)
static void log_query_mysockaddr(unsigned int flags, char *name, union mysockaddr *addr, char *arg, unsigned short type)
{
if (addr->sa.sa_family == AF_INET)
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
{
if (flags & F_SERVER)
type = ntohs(addr->in.sin_port);
log_query(flags | F_IPV4, name, (union all_addr *)&addr->in.sin_addr, arg, type);
}
else
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
{
if (flags & F_SERVER)
type = ntohs(addr->in6.sin6_port);
log_query(flags | F_IPV6, name, (union all_addr *)&addr->in6.sin6_addr, arg, type);
}
}
static void server_send(struct server *server, int fd,
@@ -135,29 +146,24 @@ static void server_send(struct server *server, int fd,
sa_len(&server->addr))));
}
#ifdef HAVE_DNSSEC
static void server_send_log(struct server *server, int fd,
const void *header, size_t plen, int dumpflags,
unsigned int logflags, char *name, char *arg,
unsigned short type)
{
#ifdef HAVE_DUMPFILE
dump_packet(dumpflags, (void *)header, (size_t)plen, NULL, &server->addr);
#endif
log_query_mysockaddr(logflags, name, &server->addr, arg, type);
server_send(server, fd, header, plen, 0);
}
#endif
static int domain_no_rebind(char *domain)
{
struct rebind_domain *rbd;
size_t tlen, dlen = strlen(domain);
char *dots = strchr(domain, '.');
/* Match whole labels only. Empty domain matches no dots (any single label) */
for (rbd = daemon->no_rebind; rbd; rbd = rbd->next)
if (dlen >= (tlen = strlen(rbd->domain)) && strcmp(rbd->domain, &domain[dlen - tlen]) == 0)
{
if (dlen >= (tlen = strlen(rbd->domain)) &&
hostname_isequal(rbd->domain, &domain[dlen - tlen]) &&
(dlen == tlen || domain[dlen - tlen - 1] == '.'))
return 1;
if (tlen == 0 && !dots)
return 1;
}
return 0;
}
@@ -170,12 +176,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
unsigned int fwd_flags = 0;
int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
struct server *master;
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
void *hash = hash_questions(header, plen, daemon->namebuff);
unsigned int gotname = extract_request(header, plen, daemon->namebuff, NULL);
unsigned char *oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
int old_src = 0;
int old_src = 0, old_reply = 0;
int first, last, start = 0;
int subnet, cacheable, forwarded = 0;
int cacheable, forwarded = 0;
size_t edns0_len;
unsigned char *pheader;
int ede = EDE_UNSET;
@@ -199,7 +205,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
Similarly FREC_NO_CACHE is never set in flags, so a query which is
contigent on a particular source address EDNS0 option will never be matched. */
if (forward)
old_src = 1;
{
old_src = 1;
old_reply = 1;
}
else if ((forward = lookup_frec_by_query(hash, fwd_flags,
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
FREC_HAS_PHEADER | FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_NO_CACHE)))
@@ -212,7 +221,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
break;
if (src)
old_src = 1;
{
old_src = 1;
/* If a query is retried, use the log_id for the retry when logging the answer. */
src->log_id = daemon->log_id;
}
else
{
/* Existing query, but from new source, just add this
@@ -256,6 +269,15 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* new query */
if (!forward)
{
/* If the query is malformed, we can't forward it because
we can't get a reliable hash to recognise the answer. */
if (!hash)
{
flags = 0;
ede = EDE_INVALID_DATA;
goto reply;
}
if (lookup_domain(daemon->namebuff, gotname, &first, &last))
flags = is_local_answer(now, first, daemon->namebuff);
else
@@ -283,6 +305,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
goto reply;
/* table full - flags == 0, return REFUSED */
forward->frec_src.log_id = daemon->log_id;
forward->frec_src.source = *udpaddr;
forward->frec_src.orig_id = ntohs(header->id);
forward->frec_src.dest = *dst_addr;
@@ -326,7 +349,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
else
{
/* retry on existing query, from original source. Send to all available servers */
#ifdef HAVE_DNSSEC
/* If we've already got an answer to this query, but we're awaiting keys for validation,
there's no point retrying the query, retry the key query instead...... */
@@ -337,7 +359,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (forward->blocking_query)
forward = forward->blocking_query;
/* log_id should match previous DNSSEC query. */
daemon->log_display_id = forward->frec_src.log_id;
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
/* get query for logging. */
@@ -376,9 +401,18 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* In strict order mode, there must be a server later in the list
left to send to, otherwise without the forwardall mechanism,
code further on will cycle around the list forwever if they
all return REFUSED. If at the last, give up. */
all return REFUSED. If at the last, give up.
Note that we can get here EITHER because a client retried,
or an upstream server returned REFUSED. The above only
applied in the later case. For client retries,
keep trying the last server.. */
if (++start == last)
goto reply;
{
if (old_reply)
goto reply;
else
start--;
}
}
}
}
@@ -390,18 +424,12 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->flags |= FREC_TEST_PKTSZ;
}
/* If a query is retried, use the log_id for the retry when logging the answer. */
forward->frec_src.log_id = daemon->log_id;
/* We may be resending a DNSSEC query here, for which the below processing is not necessary. */
if (!is_dnssec)
{
header->id = htons(forward->new_id);
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &subnet, &cacheable);
if (subnet)
forward->flags |= FREC_HAS_SUBNET;
plen = add_edns0_config(header, plen, ((unsigned char *)header) + PACKETSZ, &forward->frec_src.source, now, &cacheable);
if (!cacheable)
forward->flags |= FREC_NO_CACHE;
@@ -482,7 +510,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (errno == 0)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr);
dump_packet(DUMP_UP_QUERY, (void *)header, plen, NULL, &srv->addr, daemon->port);
#endif
/* Keep info in case we want to re-send this packet */
@@ -579,7 +607,7 @@ static struct ipsets *domain_find_sets(struct ipsets *setlist, const char *domai
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede)
union mysockaddr *query_source, unsigned char *limit, int ede)
{
unsigned char *pheader, *sizep;
struct ipsets *ipsets = NULL, *nftsets = NULL;
@@ -606,7 +634,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
/* Get extended RCODE. */
rcode |= sizep[2] << 4;
if (check_subnet && !check_source(header, plen, pheader, query_source))
if (option_bool(OPT_CLIENT_SUBNET) && !check_source(header, plen, pheader, query_source))
{
my_syslog(LOG_WARNING, _("discarding DNS reply: subnet option mismatch"));
return 0;
@@ -617,7 +645,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
if (added_pheader)
{
/* client didn't send EDNS0, we added one, strip it off before returning answer. */
n = rrfilter(header, n, 0);
n = rrfilter(header, n, RRFILTER_EDNS0);
pheader = NULL;
}
else
@@ -706,7 +734,17 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
cache_secure = 0;
}
}
/* Before extract_addresses() */
if (rcode == NOERROR)
{
if (option_bool(OPT_FILTER_A))
n = rrfilter(header, n, RRFILTER_A);
if (option_bool(OPT_FILTER_AAAA))
n = rrfilter(header, n, RRFILTER_AAAA);
}
if (extract_addresses(header, n, daemon->namebuff, now, ipsets, nftsets, is_sign, check_rebind, no_cache, cache_secure, &doctored))
{
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
@@ -736,7 +774,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
if (!do_bit)
n = rrfilter(header, n, 1);
n = rrfilter(header, n, RRFILTER_DNSSEC);
}
#endif
@@ -760,7 +798,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
u16 swap = htons((u16)ede);
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
}
return n;
}
@@ -802,7 +840,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
#ifdef HAVE_DUMPFILE
if (STAT_ISEQUAL(status, STAT_BOGUS))
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
header, (size_t)plen, &forward->sentto->addr, NULL);
header, (size_t)plen, &forward->sentto->addr, NULL, daemon->port);
#endif
}
@@ -811,106 +849,127 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
if (STAT_ISEQUAL(status, STAT_NEED_DS) || STAT_ISEQUAL(status, STAT_NEED_KEY))
{
struct frec *new = NULL;
int serverind;
struct blockdata *stash;
/* Now save reply pending receipt of key data */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
(stash = blockdata_alloc((char *)header, plen)))
if ((stash = blockdata_alloc((char *)header, plen)))
{
struct server *server = daemon->serverarray[serverind];
struct frec *orig;
unsigned int flags;
void *hash;
size_t nn;
/* validate routines leave name of required record in daemon->keyname */
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
daemon->keyname, forward->class,
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
flags = STAT_ISEQUAL(status, STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
hash = hash_questions(header, nn, daemon->namebuff);
unsigned int flags = STAT_ISEQUAL(status, STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
if ((new = lookup_frec_by_query(hash, flags, FREC_DNSKEY_QUERY | FREC_DS_QUERY)))
if ((new = lookup_frec_dnssec(daemon->keyname, forward->class, flags, header)))
{
forward->next_dependent = new->dependent;
new->dependent = forward;
/* Make consistent, only replace query copy with unvalidated answer
when we set ->blocking_query. */
if (forward->stash)
blockdata_free(forward->stash);
forward->blocking_query = new;
forward->stash_len = plen;
forward->stash = stash;
return;
/* This is tricky; it detects loops in the dependency
graph for DNSSEC validation, say validating A requires DS B
and validating DS B requires DNSKEY C and validating DNSKEY C requires DS B.
This should never happen in correctly signed records, but it's
likely the case that sufficiently broken ones can cause our validation
code requests to exhibit cycles. The result is that the ->blocking_query list
can form a cycle, and under certain circumstances that can lock us in
an infinite loop. Here we transform the situation into ABANDONED. */
struct frec *f;
for (f = new; f; f = f->blocking_query)
if (f == forward)
break;
if (!f)
{
forward->next_dependent = new->dependent;
new->dependent = forward;
/* Make consistent, only replace query copy with unvalidated answer
when we set ->blocking_query. */
if (forward->stash)
blockdata_free(forward->stash);
forward->blocking_query = new;
forward->stash_len = plen;
forward->stash = stash;
return;
}
}
/* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent);
/* Make sure we don't expire and free the orig frec during the
allocation of a new one: third arg of get_new_frec() does that. */
if (--orig->work_counter == 0 || !(new = get_new_frec(now, server, 1)))
blockdata_free(stash); /* don't leak this on failure. */
else
{
int fd;
struct frec *next = new->next;
*new = *forward; /* copy everything, then overwrite */
new->next = next;
new->blocking_query = NULL;
struct server *server;
struct frec *orig;
void *hash;
size_t nn;
int serverind, fd;
struct randfd_list *rfds = NULL;
new->frec_src.log_id = daemon->log_display_id = ++daemon->log_id;
new->sentto = server;
new->rfds = NULL;
new->frec_src.next = NULL;
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
new->flags |= flags;
new->forwardall = 0;
/* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent);
forward->next_dependent = NULL;
new->dependent = forward; /* to find query awaiting new one. */
/* Make consistent, only replace query copy with unvalidated answer
when we set ->blocking_query. */
forward->blocking_query = new;
if (forward->stash)
blockdata_free(forward->stash);
forward->stash_len = plen;
forward->stash = stash;
memcpy(new->hash, hash, HASH_SIZE);
new->new_id = get_id();
header->id = htons(new->new_id);
/* Save query for retransmission */
new->stash = blockdata_alloc((char *)header, nn);
new->stash_len = nn;
/* Don't resend this. */
daemon->srv_save = NULL;
if ((fd = allocate_rfd(&new->rfds, server)) != -1)
/* Make sure we don't expire and free the orig frec during the
allocation of a new one: third arg of get_new_frec() does that. */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 &&
(server = daemon->serverarray[serverind]) &&
(nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
daemon->keyname, forward->class,
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz)) &&
(hash = hash_questions(header, nn, daemon->namebuff)) &&
--orig->work_counter != 0 &&
(fd = allocate_rfd(&rfds, server)) != -1 &&
(new = get_new_frec(now, server, 1)))
{
struct frec *next = new->next;
*new = *forward; /* copy everything, then overwrite */
new->next = next;
new->blocking_query = NULL;
new->frec_src.log_id = daemon->log_display_id = ++daemon->log_id;
new->sentto = server;
new->rfds = rfds;
new->frec_src.next = NULL;
new->flags &= ~(FREC_DNSKEY_QUERY | FREC_DS_QUERY | FREC_HAS_EXTRADATA);
new->flags |= flags;
new->forwardall = 0;
forward->next_dependent = NULL;
new->dependent = forward; /* to find query awaiting new one. */
/* Make consistent, only replace query copy with unvalidated answer
when we set ->blocking_query. */
forward->blocking_query = new;
if (forward->stash)
blockdata_free(forward->stash);
forward->stash_len = plen;
forward->stash = stash;
memcpy(new->hash, hash, HASH_SIZE);
new->new_id = get_id();
header->id = htons(new->new_id);
/* Save query for retransmission and de-dup */
new->stash = blockdata_alloc((char *)header, nn);
new->stash_len = nn;
/* Don't resend this. */
daemon->srv_save = NULL;
#ifdef HAVE_CONNTRACK
if (option_bool(OPT_CONNTRACK))
set_outgoing_mark(orig, fd);
#endif
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
F_NOEXTRA | F_DNSSEC, daemon->keyname,
"dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, daemon->port);
#endif
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, daemon->keyname, &server->addr,
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
server_send(server, fd, header, nn, 0);
server->queries++;
return;
}
return;
free_rfds(&rfds); /* error unwind */
}
blockdata_free(stash); /* don't leak this on failure. */
}
/* sending DNSSEC query failed. */
/* sending DNSSEC query failed or loop detected. */
status = STAT_ABANDONED;
}
/* Validated original answer, all done. */
if (!forward->dependent)
return_reply(now, forward, header, plen, status);
@@ -988,7 +1047,7 @@ void reply_query(int fd, time_t now)
#ifdef HAVE_DUMPFILE
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_REPLY : DUMP_UP_REPLY,
(void *)header, n, &serveraddr, NULL);
(void *)header, n, &serveraddr, NULL, daemon->port);
#endif
/* log_query gets called indirectly all over the place, so
@@ -1167,7 +1226,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source,
forward->flags & FREC_ADDED_PHEADER, &forward->frec_src.source,
((unsigned char *)header) + daemon->edns_pktsz, ede)))
{
struct frec_src *src;
@@ -1192,7 +1251,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
header->id = htons(src->orig_id);
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source);
dump_packet(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, daemon->port);
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
@@ -1388,7 +1447,8 @@ void receive_query(struct listener *listen, time_t now)
static int warned = 0;
if (!warned)
{
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
prettyprint_addr(&source_addr, daemon->addrbuff);
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s (logged only once)"), daemon->addrbuff);
warned = 1;
}
return;
@@ -1506,7 +1566,7 @@ void receive_query(struct listener *listen, time_t now)
daemon->log_source_addr = &source_addr;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL);
dump_packet(DUMP_QUERY, daemon->packet, (size_t)n, &source_addr, NULL, daemon->port);
#endif
#ifdef HAVE_CONNTRACK
@@ -1589,7 +1649,7 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port);
#endif
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index);
@@ -1605,7 +1665,7 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port);
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
if (local_auth)
@@ -1631,7 +1691,7 @@ void receive_query(struct listener *listen, time_t now)
if (m >= 1)
{
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr);
dump_packet(DUMP_REPLY, daemon->packet, m, NULL, &source_addr, daemon->port);
#endif
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
if (option_bool(OPT_CMARK_ALST_EN) && have_mark && ((u32)mark & daemon->allowlist_mask))
@@ -1659,13 +1719,16 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
unsigned char *payload = &packet[2];
struct dns_header *header = (struct dns_header *)payload;
unsigned char c1, c2;
unsigned char hash[HASH_SIZE];
unsigned char hash[HASH_SIZE], *hashp;
unsigned int rsize;
(void)mark;
(void)have_mark;
memcpy(hash, hash_questions(header, (unsigned int)qsize, daemon->namebuff), HASH_SIZE);
if (!(hashp = hash_questions(header, (unsigned int)qsize, daemon->namebuff)))
return 0;
memcpy(hash, hashp, HASH_SIZE);
while (1)
{
@@ -1746,7 +1809,7 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
someone might be attempting to insert bogus values into the cache by
sending replies containing questions and bogus answers.
Try another server, or give up */
if (memcmp(hash, hash_questions(header, rsize, daemon->namebuff), HASH_SIZE) != 0)
if (!(hashp = hash_questions(header, rsize, daemon->namebuff)) || memcmp(hash, hashp, HASH_SIZE) != 0)
continue;
serv->flags |= SERV_GOT_TCP;
@@ -1815,8 +1878,8 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
log_save = daemon->log_display_id;
daemon->log_display_id = ++daemon->log_id;
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
"dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, keyname, &server->addr,
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
@@ -1850,7 +1913,7 @@ unsigned char *tcp_request(int confd, time_t now,
int local_auth = 0;
#endif
int checking_disabled, do_bit, added_pheader = 0, have_pseudoheader = 0;
int check_subnet, cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
int cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
size_t m;
unsigned short qtype;
unsigned int gotname;
@@ -1915,7 +1978,8 @@ unsigned char *tcp_request(int confd, time_t now,
}
if (!addr)
{
my_syslog(LOG_WARNING, _("Ignoring query from non-local network"));
prettyprint_addr(&peer_addr, daemon->addrbuff);
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
return packet;
}
}
@@ -2067,7 +2131,7 @@ unsigned char *tcp_request(int confd, time_t now,
else
start = master->last_server;
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &check_subnet, &cacheable);
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
@@ -2145,7 +2209,7 @@ unsigned char *tcp_request(int confd, time_t now,
m = process_reply(header, now, serv, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr, ((unsigned char *)header) + 65536, ede);
ad_reqd, do_bit, added_pheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
}
}
}
@@ -2511,28 +2575,29 @@ static struct frec *lookup_frec(unsigned short id, int fd, void *hash, int *firs
struct server *s;
int first, last;
struct randfd_list *fdl;
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->new_id == id &&
(memcmp(hash, f->hash, HASH_SIZE) == 0))
{
filter_servers(f->sentto->arrayposn, F_SERVER, firstp, lastp);
/* sent from random port */
for (fdl = f->rfds; fdl; fdl = fdl->next)
if (fdl->rfd->fd == fd)
return f;
/* Sent to upstream from socket associated with a server.
Note we have to iterate over all the possible servers, since they may
have different bound sockets. */
for (first = *firstp, last = *lastp; first != last; first++)
{
s = daemon->serverarray[first];
if (s->sfd && s->sfd->fd == fd)
if (hash)
for (f = daemon->frec_list; f; f = f->next)
if (f->sentto && f->new_id == id &&
(memcmp(hash, f->hash, HASH_SIZE) == 0))
{
filter_servers(f->sentto->arrayposn, F_SERVER, firstp, lastp);
/* sent from random port */
for (fdl = f->rfds; fdl; fdl = fdl->next)
if (fdl->rfd->fd == fd)
return f;
}
}
/* Sent to upstream from socket associated with a server.
Note we have to iterate over all the possible servers, since they may
have different bound sockets. */
for (first = *firstp, last = *lastp; first != last; first++)
{
s = daemon->serverarray[first];
if (s->sfd && s->sfd->fd == fd)
return f;
}
}
return NULL;
}
@@ -2541,15 +2606,47 @@ static struct frec *lookup_frec_by_query(void *hash, unsigned int flags, unsigne
{
struct frec *f;
for(f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
(f->flags & flagmask) == flags &&
memcmp(hash, f->hash, HASH_SIZE) == 0)
return f;
if (hash)
for (f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
(f->flags & flagmask) == flags &&
memcmp(hash, f->hash, HASH_SIZE) == 0)
return f;
return NULL;
}
#ifdef HAVE_DNSSEC
/* DNSSEC frecs have the complete query in the block stash.
Search for an existing query using that. */
static struct frec *lookup_frec_dnssec(char *target, int class, int flags, struct dns_header *header)
{
struct frec *f;
for (f = daemon->frec_list; f; f = f->next)
if (f->sentto &&
(f->flags & flags) &&
blockdata_retrieve(f->stash, f->stash_len, (void *)header))
{
unsigned char *p = (unsigned char *)(header+1);
int hclass;
if (extract_name(header, f->stash_len, &p, target, 0, 4) != 1)
continue;
p += 2; /* type, known from flags */
GETSHORT(hclass, p);
if (class != hclass)
continue;
return f;
}
return NULL;
}
#endif
/* Send query packet again, if we can. */
void resend_query()
{
+4 -4
View File
@@ -55,7 +55,7 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
char *cp, c;
if (!extract_name(header, plen, &p, name, 1, 4))
break; /* bad packet */
return NULL; /* bad packet */
for (cp = name; (c = *cp); cp++)
if (c >= 'A' && c <= 'Z')
@@ -67,7 +67,7 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
break; /* bad packet */
return NULL; /* bad packet */
}
hash->digest(ctx, hash->digest_size, digest);
@@ -109,7 +109,7 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
char *cp, c;
if (!extract_name(header, plen, &p, name, 1, 4))
break; /* bad packet */
return NULL; /* bad packet */
for (cp = name; (c = *cp); cp++)
if (c >= 'A' && c <= 'Z')
@@ -121,7 +121,7 @@ unsigned char *hash_questions(struct dns_header *header, size_t plen, char *name
p += 4;
if (!CHECK_LEN(header, p, plen, 0))
break; /* bad packet */
return NULL; /* bad packet */
}
sha256_final(&ctx, digest);
+57 -8
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -233,8 +233,13 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
is6 = (data.flags != AF_INET);
data.action = ACTION_ARP;
}
else
continue;
else if (data.action == ACTION_RELAY_SNOOP)
{
is6 = 1;
action_str = "relay-snoop";
}
else
continue;
/* stringify MAC into dhcp_buff */
p = daemon->dhcp_buff;
@@ -286,7 +291,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
char *dot;
hostname = (char *)buf;
hostname[data.hostname_len - 1] = 0;
if (data.action != ACTION_TFTP)
if (data.action != ACTION_TFTP && data.action != ACTION_RELAY_SNOOP)
{
if (!legal_hostname(hostname))
hostname = NULL;
@@ -332,6 +337,24 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
}
else if (data.action == ACTION_RELAY_SNOOP)
{
lua_getglobal(lua, "snoop");
if (lua_type(lua, -1) != LUA_TFUNCTION)
lua_pop(lua, 1); /* tftp function optional */
else
{
lua_pushstring(lua, action_str); /* arg1 - action */
lua_newtable(lua); /* arg2 - data table */
lua_pushstring(lua, daemon->addrbuff);
lua_setfield(lua, -2, "client_address");
lua_pushstring(lua, hostname);
lua_setfield(lua, -2, "prefix");
lua_pushstring(lua, data.interface);
lua_setfield(lua, -2, "client_interface");
lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
}
}
else if (data.action == ACTION_ARP)
{
lua_getglobal(lua, "arp");
@@ -432,8 +455,8 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
buf = grab_extradata_lua(buf, end, "relay_address");
else if (data.giaddr.s_addr != 0)
{
inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
lua_pushstring(lua, daemon->addrbuff);
inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
lua_pushstring(lua, daemon->dhcp_buff2);
lua_setfield(lua, -2, "relay_address");
}
@@ -553,7 +576,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
close(pipeout[1]);
}
if (data.action != ACTION_TFTP && data.action != ACTION_ARP)
if (data.action != ACTION_TFTP && data.action != ACTION_ARP && data.action != ACTION_RELAY_SNOOP)
{
#ifdef HAVE_DHCP6
my_setenv("DNSMASQ_IAID", is6 ? daemon->dhcp_buff3 : NULL, &err);
@@ -615,7 +638,7 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
{
const char *giaddr = NULL;
if (data.giaddr.s_addr != 0)
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->addrbuff, ADDRSTRLEN);
giaddr = inet_ntop(AF_INET, &data.giaddr, daemon->dhcp_buff2, ADDRSTRLEN);
my_setenv("DNSMASQ_RELAY_ADDRESS", giaddr, &err);
}
@@ -640,6 +663,9 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
close(pipefd[0]);
if (data.action == ACTION_RELAY_SNOOP)
strcpy(daemon->packet, data.interface);
p = strrchr(daemon->lease_change_command, '/');
if (err == 0)
{
@@ -810,6 +836,29 @@ void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t n
bytes_in_buf = p - (unsigned char *)buf;
}
#ifdef HAVE_DHCP6
void queue_relay_snoop(struct in6_addr *client, int if_index, struct in6_addr *prefix, int prefix_len)
{
/* no script */
if (daemon->helperfd == -1)
return;
inet_ntop(AF_INET6, prefix, daemon->addrbuff, ADDRSTRLEN);
/* 5 for /nnn and zero on the end of the prefix. */
buff_alloc(sizeof(struct script_data) + ADDRSTRLEN + 5);
memset(buf, 0, sizeof(struct script_data));
buf->action = ACTION_RELAY_SNOOP;
buf->addr6 = *client;
buf->hostname_len = sprintf((char *)(buf+1), "%s/%u", daemon->addrbuff, prefix_len) + 1;
indextoname(daemon->dhcp6fd, if_index, buf->interface);
bytes_in_buf = sizeof(struct script_data) + buf->hostname_len;
}
#endif
#ifdef HAVE_TFTP
/* This nastily re-uses DHCP-fields for TFTP stuff */
void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+19 -6
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -100,10 +100,23 @@ int log_start(struct passwd *ent_pw, int errfd)
/* If we're running as root and going to change uid later,
change the ownership here so that the file is always owned by
the dnsmasq user. Then logrotate can just copy the owner.
Failure of the chown call is OK, (for instance when started as non-root) */
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0 &&
fchown(log_fd, ent_pw->pw_uid, -1) != 0)
ret = errno;
Failure of the chown call is OK, (for instance when started as non-root).
If we've created a file with group-id root, we also make
the file group-writable. This gives processes in the root group
write access to the file and avoids the problem that on some systems,
once the file is owned by the dnsmasq user, it can't be written
whilst dnsmasq is running as root during startup.
*/
if (log_to_file && !log_stderr && ent_pw && ent_pw->pw_uid != 0)
{
struct stat ls;
if (getgid() == 0 && fstat(log_fd, &ls) == 0 && ls.st_gid == 0 &&
(ls.st_mode & S_IWGRP) == 0)
(void)fchmod(log_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
if (fchown(log_fd, ent_pw->pw_uid, -1) != 0)
ret = errno;
}
return ret;
}
@@ -118,7 +131,7 @@ int log_reopen(char *log_file)
/* NOTE: umask is set to 022 by the time this gets called */
if (log_file)
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
log_fd = open(log_file, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
else
{
#if defined(HAVE_SOLARIS_NETWORK) || defined(__ANDROID__)
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+12 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -1743,6 +1743,8 @@ int reload_servers(char *fname)
/* Called when addresses are added or deleted from an interface */
void newaddress(time_t now)
{
struct dhcp_relay *relay;
(void)now;
if (option_bool(OPT_CLEVERBIND) || option_bool(OPT_LOCAL_SERVICE) ||
@@ -1751,6 +1753,12 @@ void newaddress(time_t now)
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
#ifdef HAVE_DHCP
/* clear cache of subnet->relay index */
for (relay = daemon->relay4; relay; relay = relay->next)
relay->iface_index = 0;
#endif
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->relay6 || daemon->doing_ra)
@@ -1761,5 +1769,8 @@ void newaddress(time_t now)
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
for (relay = daemon->relay6; relay; relay = relay->next)
relay->iface_index = 0;
#endif
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+118 -70
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -175,7 +175,11 @@ struct myoption {
#define LOPT_CMARK_ALST 366
#define LOPT_QUIET_TFTP 367
#define LOPT_NFTSET 368
#define LOPT_FILTER_A 369
#define LOPT_FILTER_AAAA 370
#define LOPT_STRIP_SBNET 371
#define LOPT_STRIP_MAC 372
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
#else
@@ -212,6 +216,8 @@ static const struct myoption opts[] =
{ "ignore-address", 1, 0, LOPT_IGNORE_ADDR },
{ "selfmx", 0, 0, 'e' },
{ "filterwin2k", 0, 0, 'f' },
{ "filter-A", 0, 0, LOPT_FILTER_A },
{ "filter-AAAA", 0, 0, LOPT_FILTER_AAAA },
{ "pid-file", 2, 0, 'x' },
{ "strict-order", 0, 0, 'o' },
{ "server", 1, 0, 'S' },
@@ -310,7 +316,9 @@ static const struct myoption opts[] =
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
{ "add-mac", 2, 0, LOPT_ADD_MAC },
{ "strip-mac", 0, 0, LOPT_STRIP_MAC },
{ "add-subnet", 2, 0, LOPT_ADD_SBNET },
{ "strip-subnet", 0, 0, LOPT_STRIP_SBNET },
{ "add-cpe-id", 1, 0 , LOPT_CPE_ID },
{ "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ "dhcp-sequential-ip", 0, 0, LOPT_INCR_ADDR },
@@ -353,7 +361,7 @@ static const struct myoption opts[] =
{ "dhcp-ignore-clid", 0, 0, LOPT_IGNORE_CLID },
{ "dynamic-host", 1, 0, LOPT_DYNHOST },
{ "log-debug", 0, 0, LOPT_LOG_DEBUG },
{ "umbrella", 2, 0, LOPT_UMBRELLA },
{ "umbrella", 2, 0, LOPT_UMBRELLA },
{ "quiet-tftp", 0, 0, LOPT_QUIET_TFTP },
{ NULL, 0, 0, 0 }
};
@@ -382,6 +390,8 @@ static struct {
{ 'e', OPT_SELFMX, NULL, gettext_noop("Return self-pointing MX records for local hosts."), NULL },
{ 'E', OPT_EXPAND, NULL, gettext_noop("Expand simple names in /etc/hosts with domain-suffix."), NULL },
{ 'f', OPT_FILTER, NULL, gettext_noop("Don't forward spurious DNS requests from Windows hosts."), NULL },
{ LOPT_FILTER_A, OPT_FILTER_A, NULL, gettext_noop("Don't include IPv4 addresses in DNS answers."), NULL },
{ LOPT_FILTER_AAAA, OPT_FILTER_AAAA, NULL, gettext_noop("Don't include IPv6 addresses in DNS answers."), NULL },
{ 'F', ARG_DUP, "<ipaddr>,...", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "<groupname>", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
@@ -495,7 +505,9 @@ static struct {
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
{ LOPT_ADD_MAC, ARG_DUP, "[=base64|text]", gettext_noop("Add requestor's MAC address to forwarded DNS queries."), NULL },
{ LOPT_STRIP_MAC, OPT_STRIP_MAC, NULL, gettext_noop("Strip MAC information from queries."), NULL },
{ LOPT_ADD_SBNET, ARG_ONE, "<v4 pref>[,<v6 pref>]", gettext_noop("Add specified IP subnet to forwarded DNS queries."), NULL },
{ LOPT_STRIP_SBNET, OPT_STRIP_ECS, NULL, gettext_noop("Strip ECS information from queries."), NULL },
{ LOPT_CPE_ID, ARG_ONE, "<text>", gettext_noop("Add client identification to forwarded DNS queries."), NULL },
{ LOPT_DNSSEC, OPT_DNSSEC_PROXY, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers."), NULL },
{ LOPT_INCR_ADDR, OPT_CONSEC_ADDR, NULL, gettext_noop("Attempt to allocate sequential IP addresses to DHCP clients."), NULL },
@@ -657,7 +669,7 @@ static char *canonicalise_opt(char *s)
return 0;
if (strlen(s) == 0)
return opt_string_alloc("");
return opt_malloc(1); /* Heap-allocated empty string */
unhide_metas(s);
if (!(ret = canonicalise(s, &nomem)) && nomem)
@@ -963,13 +975,9 @@ static char *domain_rev4(int from_file, char *server, struct in_addr *addr4, int
if (size > 32 || size < 1)
return _("bad IPv4 prefix length");
for (i = 0; i < addrbytes; i++)
if (((u8 *)addr4)[3-i] != 0)
break;
if (i != addrbytes || (((u8 *)addr4)[3-addrbytes] & ((1 << addrbits) - 1)) != 0)
return _("address part not zero");
/* Zero out last address bits according to CIDR mask */
((u8 *)addr4)[3-addrbytes] &= ~((1 << addrbits)-1);
size = size & ~0x7;
@@ -1026,13 +1034,9 @@ static char *domain_rev6(int from_file, char *server, struct in6_addr *addr6, in
if (size > 128 || size < 1)
return _("bad IPv6 prefix length");
for (i = 0; i < addrbytes; i++)
if (addr6->s6_addr[15-i] != 0)
break;
if (i != addrbytes || (addr6->s6_addr[15-addrbytes] & ((1 << addrbits) - 1)) != 0)
return _("address part not zero");
/* Zero out last address bits according to CIDR mask */
addr6->s6_addr[15-addrbytes] &= ~((1 << addrbits) - 1);
size = size & ~0x3;
@@ -2235,8 +2239,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
comma = split(arg);
new = opt_malloc(sizeof(struct auth_zone));
new->domain = opt_string_alloc(arg);
new->subnet = NULL;
new->domain = canonicalise_opt(arg);
if (!new->domain)
ret_err_free(_("invalid auth-zone"), new);
new->subnet = NULL;
new->exclude = NULL;
new->interface_names = NULL;
new->next = daemon->auth_zones;
@@ -2519,39 +2525,48 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_UMBRELLA: /* --umbrella */
set_option_bool(OPT_UMBRELLA);
while (arg) {
comma = split(arg);
if (strstr(arg, "deviceid:")) {
arg += 9;
if (strlen(arg) != 16)
ret_err(gen_err);
for (char *p = arg; *p; p++) {
if (!isxdigit((int)*p))
ret_err(gen_err);
}
set_option_bool(OPT_UMBRELLA_DEVID);
u8 *u = daemon->umbrella_device;
char word[3];
for (u8 i = 0; i < sizeof(daemon->umbrella_device); i++, arg+=2) {
memcpy(word, &(arg[0]), 2);
*u++ = strtoul(word, NULL, 16);
}
}
else if (strstr(arg, "orgid:")) {
if (!strtoul_check(arg+6, &daemon->umbrella_org)) {
ret_err(gen_err);
}
}
else if (strstr(arg, "assetid:")) {
if (!strtoul_check(arg+8, &daemon->umbrella_asset)) {
ret_err(gen_err);
}
}
arg = comma;
}
while (arg)
{
comma = split(arg);
if (strstr(arg, "deviceid:"))
{
char *p;
u8 *u = daemon->umbrella_device;
char word[3];
arg += 9;
if (strlen(arg) != 16)
ret_err(gen_err);
for (p = arg; *p; p++)
if (!isxdigit((int)*p))
ret_err(gen_err);
set_option_bool(OPT_UMBRELLA_DEVID);
for (i = 0; i < (int)sizeof(daemon->umbrella_device); i++, arg+=2)
{
memcpy(word, &(arg[0]), 2);
*u++ = strtoul(word, NULL, 16);
}
}
else if (strstr(arg, "orgid:"))
{
if (!strtoul_check(arg+6, &daemon->umbrella_org))
ret_err(gen_err);
}
else if (strstr(arg, "assetid:"))
{
if (!strtoul_check(arg+8, &daemon->umbrella_asset))
ret_err(gen_err);
}
else
ret_err(gen_err);
arg = comma;
}
break;
case LOPT_ADD_MAC: /* --add-mac */
if (!arg)
set_option_bool(OPT_ADD_MAC);
@@ -2766,7 +2781,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (!arg || !*arg)
flags = SERV_LITERAL_ADDRESS;
else if (option != 'S')
else if (option == 'A')
{
/* # as literal address means return zero address for 4 and 6 */
if (strcmp(arg, "#") == 0)
@@ -2798,7 +2813,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
flags &= ~SERV_FOR_NODOTS;
/* address=/#/ matches the same as without domain */
if (option != 'S' && domain[0] == '#' && domain[1] == 0)
if (option == 'A' && domain[0] == '#' && domain[1] == 0)
domain[0] = 0;
}
@@ -4128,7 +4143,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_SUBSCR: /* --dhcp-subscrid */
{
unsigned char *p;
int dig = 0;
int dig, colon;
struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
if (!(comma = split(arg)))
@@ -4152,13 +4167,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
else
comma = arg;
for (p = (unsigned char *)comma; *p; p++)
for (dig = 0, colon = 0, p = (unsigned char *)comma; *p; p++)
if (isxdigit(*p))
dig = 1;
else if (*p != ':')
else if (*p == ':')
colon = 1;
else
break;
unhide_metas(comma);
if (option == 'U' || option == 'j' || *p || !dig)
if (option == 'U' || option == 'j' || *p || !dig || !colon)
{
new->len = strlen(comma);
new->data = opt_malloc(new->len);
@@ -4281,26 +4299,56 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
break;
case LOPT_RELAY: /* --dhcp-relay */
{
struct dhcp_relay *new = opt_malloc(sizeof(struct dhcp_relay));
comma = split(arg);
new->interface = opt_string_alloc(split(comma));
char *two = split(arg);
char *three = split(two);
new->iface_index = 0;
if (comma && inet_pton(AF_INET, arg, &new->local) && inet_pton(AF_INET, comma, &new->server))
if (two)
{
new->next = daemon->relay4;
daemon->relay4 = new;
}
if (inet_pton(AF_INET, arg, &new->local))
{
if (!inet_pton(AF_INET, two, &new->server))
{
new->server.addr4.s_addr = 0;
/* Fail for three arg version where there are not two addresses.
Also fail when broadcasting to wildcard address. */
if (three || strchr(two, '*'))
two = NULL;
else
three = two;
}
new->next = daemon->relay4;
daemon->relay4 = new;
}
#ifdef HAVE_DHCP6
else if (comma && inet_pton(AF_INET6, arg, &new->local) && inet_pton(AF_INET6, comma, &new->server))
{
new->next = daemon->relay6;
daemon->relay6 = new;
}
else if (inet_pton(AF_INET6, arg, &new->local))
{
if (!inet_pton(AF_INET6, two, &new->server))
{
inet_pton(AF_INET6, ALL_SERVERS, &new->server.addr6);
/* Fail for three arg version where there are not two addresses.
Also fail when multicasting to wildcard address. */
if (three || strchr(two, '*'))
two = NULL;
else
three = two;
}
new->next = daemon->relay6;
daemon->relay6 = new;
}
#endif
else
new->interface = opt_string_alloc(three);
}
if (!two)
{
free(new->interface);
ret_err_free(_("Bad dhcp-relay"), new);
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+5 -5
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -129,9 +129,9 @@ int is_valid_dns_name(const char *value)
size_t num_bytes = 0;
size_t num_labels = 0;
const char *label = NULL;
const char *c, *label = NULL;
int is_label_numeric = 1;
for (const char *c = value;; c++)
for (c = value;; c++)
{
if (*c &&
*c != '-' && *c != '.' &&
@@ -242,11 +242,11 @@ int is_valid_dns_name_pattern(const char *value)
size_t num_bytes = 0;
size_t num_labels = 0;
const char *label = NULL;
const char *c, *label = NULL;
int is_label_numeric = 1;
size_t num_wildcards = 0;
int previous_label_has_wildcard = 1;
for (const char *c = value;; c++)
for (c = value;; c++)
{
if (*c &&
*c != '*' && /* Wildcard. */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+31 -11
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -123,7 +123,11 @@ void ra_start_unsolicited(time_t now, struct dhcp_context *context)
and pick up new interfaces */
if (context)
context->ra_short_period_start = context->ra_time = now;
{
context->ra_short_period_start = now;
/* start after 1 second to get logging right at startup. */
context->ra_time = now + 1;
}
else
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE))
@@ -162,7 +166,7 @@ void icmp6_packet(time_t now)
return;
packet = (unsigned char *)daemon->outpacket.iov_base;
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
{
@@ -187,24 +191,36 @@ void icmp6_packet(time_t now)
if (packet[1] != 0)
return;
if (packet[0] == ICMP6_ECHO_REPLY)
lease_ping_reply(&from.sin6_addr, packet, interface);
else if (packet[0] == ND_ROUTER_SOLICIT)
{
char *mac = "";
struct dhcp_bridge *bridge, *alias;
ssize_t rem;
unsigned char *p;
int opt_sz;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_RA, (void *)packet, sz, (union mysockaddr *)&from, NULL, -1);
#endif
/* look for link-layer address option for logging */
if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
for (rem = sz - 8, p = &packet[8]; rem >= 2; rem -= opt_sz, p += opt_sz)
{
if ((packet[9] * 8 - 2) * 3 - 1 >= MAXDNAME) {
return;
}
print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
mac = daemon->namebuff;
opt_sz = p[1] * 8;
if (opt_sz == 0 || opt_sz > rem)
return; /* Bad packet */
if (p[0] == ICMP6_OPT_SOURCE_MAC && ((opt_sz - 2) * 3 - 1 < MAXDNAME))
{
print_mac(daemon->namebuff, &p[2], opt_sz - 2);
mac = daemon->namebuff;
}
}
if (!option_bool(OPT_QUIET_RA))
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
@@ -543,6 +559,10 @@ static void send_ra_alias(time_t now, int iface, char *iface_name, struct in6_ad
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &send_iface, sizeof(send_iface));
}
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_RA, (void *)daemon->outpacket.iov_base, save_counter(-1), NULL, (union mysockaddr *)&addr, -1);
#endif
while (retry_send(sendto(daemon->icmp6fd, daemon->outpacket.iov_base,
save_counter(-1), 0, (struct sockaddr *)&addr,
sizeof(addr))));
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+4 -3
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -2200,8 +2200,9 @@ static int pxe_uefi_workaround(int pxe_arch, struct dhcp_netid *netid, struct dh
inet_ntop(AF_INET, &mess->siaddr, (char *)mess->sname, INET_ADDRSTRLEN);
}
snprintf((char *)mess->file, sizeof(mess->file),
strchr(found->basename, '.') ? "%s" : "%s.0", found->basename);
if (found->basename)
snprintf((char *)mess->file, sizeof(mess->file),
strchr(found->basename, '.') ? "%s" : "%s.0", found->basename);
return 1;
}
+156 -70
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -2100,95 +2100,116 @@ static unsigned int opt6_uint(unsigned char *opt, int offset, int size)
return ret;
}
void relay_upstream6(struct dhcp_relay *relay, ssize_t sz,
struct in6_addr *peer_address, u32 scope_id, time_t now)
int relay_upstream6(int iface_index, ssize_t sz,
struct in6_addr *peer_address, u32 scope_id, time_t now)
{
/* ->local is same value for all relays on ->current chain */
union all_addr from;
unsigned char *header;
unsigned char *inbuff = daemon->dhcp_packet.iov_base;
int msg_type = *inbuff;
int hopcount;
int hopcount, o;
struct in6_addr multicast;
unsigned int maclen, mactype;
unsigned char mac[DHCP_CHADDR_MAX];
struct dhcp_relay *relay;
for (relay = daemon->relay6; relay; relay = relay->next)
if (relay->iface_index != 0 && relay->iface_index == iface_index)
break;
/* No relay config. */
if (!relay)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &multicast);
get_client_mac(peer_address, scope_id, mac, &maclen, &mactype, now);
/* source address == relay address */
from.addr6 = relay->local.addr6;
/* Get hop count from nested relayed message */
if (msg_type == DHCP6RELAYFORW)
hopcount = *((unsigned char *)inbuff+1) + 1;
else
hopcount = 0;
/* RFC 3315 HOP_COUNT_LIMIT */
if (hopcount > 32)
return;
reset_counter();
if ((header = put_opt6(NULL, 34)))
/* RFC 3315 HOP_COUNT_LIMIT */
if (hopcount > 32 || !(header = put_opt6(NULL, 34)))
return 1;
header[0] = DHCP6RELAYFORW;
header[1] = hopcount;
memcpy(&header[18], peer_address, IN6ADDRSZ);
/* RFC-6939 */
if (maclen != 0)
{
int o;
header[0] = DHCP6RELAYFORW;
header[1] = hopcount;
memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
memcpy(&header[18], peer_address, IN6ADDRSZ);
/* RFC-6939 */
if (maclen != 0)
{
o = new_opt6(OPTION6_CLIENT_MAC);
put_opt6_short(mactype);
put_opt6(mac, maclen);
end_opt6(o);
}
o = new_opt6(OPTION6_RELAY_MSG);
put_opt6(inbuff, sz);
o = new_opt6(OPTION6_CLIENT_MAC);
put_opt6_short(mactype);
put_opt6(mac, maclen);
end_opt6(o);
for (; relay; relay = relay->current)
{
union mysockaddr to;
to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
to.in6.sin6_flowinfo = 0;
to.in6.sin6_scope_id = 0;
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
{
int multicast_iface;
if (!relay->interface || strchr(relay->interface, '*') ||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast to DHCPv6 server without correct interface"));
}
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay %s -> %s"), daemon->addrbuff, daemon->namebuff);
}
/* Save this for replies */
relay->iface_index = scope_id;
}
}
o = new_opt6(OPTION6_RELAY_MSG);
put_opt6(inbuff, sz);
end_opt6(o);
for (; relay; relay = relay->next)
if (relay->iface_index != 0 && relay->iface_index == iface_index)
{
union mysockaddr to;
union all_addr from;
/* source address == relay address */
from.addr6 = relay->local.addr6;
memcpy(&header[2], &relay->local.addr6, IN6ADDRSZ);
to.sa.sa_family = AF_INET6;
to.in6.sin6_addr = relay->server.addr6;
to.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
to.in6.sin6_flowinfo = 0;
to.in6.sin6_scope_id = 0;
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
{
int multicast_iface;
if (!relay->interface || strchr(relay->interface, '*') ||
(multicast_iface = if_nametoindex(relay->interface)) == 0 ||
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &multicast_iface, sizeof(multicast_iface)) == -1)
{
my_syslog(MS_DHCP | LOG_ERR, _("Cannot multicast DHCP relay via interface %s"), relay->interface);
continue;
}
}
#ifdef HAVE_DUMPFILE
{
union mysockaddr fromsock;
fromsock.in6.sin6_port = htons(DHCPV6_SERVER_PORT);
fromsock.in6.sin6_addr = from.addr6;
fromsock.sa.sa_family = AF_INET6;
fromsock.in6.sin6_flowinfo = 0;
fromsock.in6.sin6_scope_id = 0;
dump_packet(DUMP_DHCPV6, (void *)daemon->outpacket.iov_base, save_counter(-1), &fromsock, &to, 0);
}
#endif
send_from(daemon->dhcp6fd, 0, daemon->outpacket.iov_base, save_counter(-1), &to, &from, 0);
if (option_bool(OPT_LOG_OPTS))
{
inet_ntop(AF_INET6, &relay->local, daemon->addrbuff, ADDRSTRLEN);
if (IN6_ARE_ADDR_EQUAL(&relay->server.addr6, &multicast))
snprintf(daemon->namebuff, MAXDNAME, _("multicast via %s"), relay->interface);
else
inet_ntop(AF_INET6, &relay->server, daemon->namebuff, ADDRSTRLEN);
my_syslog(MS_DHCP | LOG_INFO, _("DHCP relay at %s -> %s"), daemon->addrbuff, daemon->namebuff);
}
}
return 1;
}
unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
int relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival_interface)
{
struct dhcp_relay *relay;
struct in6_addr link;
@@ -2220,11 +2241,76 @@ unsigned short relay_reply6(struct sockaddr_in6 *peer, ssize_t sz, char *arrival
put_opt6(opt6_ptr(opt, 0), opt6_len(opt));
memcpy(&peer->sin6_addr, &inbuff[18], IN6ADDRSZ);
peer->sin6_scope_id = relay->iface_index;
return encap_type == DHCP6RELAYREPL ? DHCPV6_SERVER_PORT : DHCPV6_CLIENT_PORT;
}
}
if (encap_type == DHCP6RELAYREPL)
{
peer->sin6_port = ntohs(DHCPV6_SERVER_PORT);
return 1;
}
peer->sin6_port = ntohs(DHCPV6_CLIENT_PORT);
#ifdef HAVE_SCRIPT
if (daemon->lease_change_command && encap_type == DHCP6REPLY)
{
/* decapsulate relayed message */
opts = opt6_ptr(opt, 4);
end = opt6_ptr(opt, opt6_len(opt));
for (opt = opts; opt; opt = opt6_next(opt, end))
if (opt6_type(opt) == OPTION6_IA_PD && opt6_len(opt) > 12)
{
void *ia_opts = opt6_ptr(opt, 12);
void *ia_end = opt6_ptr(opt, opt6_len(opt));
void *ia_opt;
for (ia_opt = ia_opts; ia_opt; ia_opt = opt6_next(ia_opt, ia_end))
/* valid lifetime must not be zero. */
if (opt6_type(ia_opt) == OPTION6_IAPREFIX && opt6_len(ia_opt) >= 25 && opt6_uint(ia_opt, 4, 4) != 0)
{
if (daemon->free_snoops ||
(daemon->free_snoops = whine_malloc(sizeof(struct snoop_record))))
{
struct snoop_record *snoop = daemon->free_snoops;
daemon->free_snoops = snoop->next;
snoop->client = peer->sin6_addr;
snoop->prefix_len = opt6_uint(ia_opt, 8, 1);
memcpy(&snoop->prefix, opt6_ptr(ia_opt, 9), IN6ADDRSZ);
snoop->next = relay->snoop_records;
relay->snoop_records = snoop;
}
}
}
}
#endif
return 1;
}
}
return 0;
}
#ifdef HAVE_SCRIPT
int do_snoop_script_run(void)
{
struct dhcp_relay *relay;
struct snoop_record *snoop;
for (relay = daemon->relay6; relay; relay = relay->next)
if ((snoop = relay->snoop_records))
{
relay->snoop_records = snoop->next;
snoop->next = daemon->free_snoops;
daemon->free_snoops = snoop;
queue_relay_snoop(&snoop->client, relay->iface_index, &snoop->prefix, snoop->prefix_len);
return 1;
}
return 0;
}
#endif
#endif
+28 -11
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -156,7 +156,7 @@ static int check_rrs(unsigned char *p, struct dns_header *header, size_t plen, i
}
/* mode is 0 to remove EDNS0, 1 to filter DNSSEC RRs */
/* mode may be remove EDNS0 or DNSSEC RRs or remove A or AAAA from answer section. */
size_t rrfilter(struct dns_header *header, size_t plen, int mode)
{
static unsigned char **rrs;
@@ -192,20 +192,37 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
if (!ADD_RDLEN(header, p, plen, rdlen))
return plen;
/* Don't remove the answer. */
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
continue;
if (mode == 0) /* EDNS */
if (mode == RRFILTER_EDNS0) /* EDNS */
{
/* EDNS mode, remove T_OPT from additional section only */
if (i < (ntohs(header->nscount) + ntohs(header->ancount)) || type != T_OPT)
continue;
}
else if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
continue;
else if (mode == RRFILTER_DNSSEC)
{
if (type != T_NSEC && type != T_NSEC3 && type != T_RRSIG)
/* DNSSEC mode, remove SIGs and NSECs from all three sections. */
continue;
/* Don't remove the answer. */
if (i < ntohs(header->ancount) && type == qtype && class == qclass)
continue;
}
else
{
/* Only looking at answer section now. */
if (i >= ntohs(header->ancount))
break;
if (class != C_IN)
continue;
if (mode == RRFILTER_A && type != T_A)
continue;
if (mode == RRFILTER_AAAA && type != T_AAAA)
continue;
}
if (!expand_workspace(&rrs, &rr_sz, rr_found + 1))
return plen;
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+33 -18
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -19,9 +19,9 @@
#ifdef HAVE_TFTP
static void handle_tftp(time_t now, struct tftp_transfer *transfer, ssize_t len);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix);
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client);
static void free_transfer(struct tftp_transfer *transfer);
static ssize_t tftp_err(int err, char *packet, char *message, char *file);
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2);
static ssize_t tftp_err_oops(char *packet, const char *file);
static ssize_t get_block(char *packet, struct tftp_transfer *transfer);
static char *next(char **p, char *end);
@@ -95,6 +95,10 @@ void tftp_request(struct listener *listen, time_t now)
if ((len = recvmsg(listen->tftpfd, &msg, 0)) < 2)
return;
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_TFTP, (void *)packet, len, (union mysockaddr *)&peer, NULL, TFTP_PORT);
#endif
/* Can always get recvd interface for IPv6 */
if (!check_dest)
@@ -362,7 +366,7 @@ void tftp_request(struct listener *listen, time_t now)
!(mode = next(&p, end)) ||
(strcasecmp(mode, "octet") != 0 && strcasecmp(mode, "netascii") != 0))
{
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff);
len = tftp_err(ERR_ILL, packet, _("unsupported request from %s"), daemon->addrbuff, NULL);
is_err = 1;
}
else
@@ -472,7 +476,7 @@ void tftp_request(struct listener *listen, time_t now)
strncat(daemon->namebuff, filename, (MAXDNAME-1) - strlen(daemon->namebuff));
/* check permissions and open file */
if ((transfer->file = check_tftp_fileperm(&len, prefix)))
if ((transfer->file = check_tftp_fileperm(&len, prefix, daemon->addrbuff)))
{
if ((len = get_block(packet, transfer)) == -1)
len = tftp_err_oops(packet, daemon->namebuff);
@@ -482,6 +486,10 @@ void tftp_request(struct listener *listen, time_t now)
}
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), packet, len, &peer, &addra, if_index);
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_TFTP, (void *)packet, len, NULL, (union mysockaddr *)&peer, TFTP_PORT);
#endif
if (is_err)
free_transfer(transfer);
@@ -492,7 +500,7 @@ void tftp_request(struct listener *listen, time_t now)
}
}
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix, char *client)
{
char *packet = daemon->packet, *namebuff = daemon->namebuff;
struct tftp_file *file;
@@ -509,7 +517,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
{
if (errno == ENOENT)
{
*len = tftp_err(ERR_FNF, packet, _("file %s not found"), namebuff);
*len = tftp_err(ERR_FNF, packet, _("file %s not found for %s"), namebuff, client);
return NULL;
}
else if (errno == EACCES)
@@ -562,8 +570,7 @@ static struct tftp_file *check_tftp_fileperm(ssize_t *len, char *prefix)
return file;
perm:
errno = EACCES;
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff);
*len = tftp_err(ERR_PERM, packet, _("cannot access %s: %s"), namebuff, strerror(EACCES));
if (fd != -1)
close(fd);
return NULL;
@@ -599,8 +606,12 @@ void check_tftp_listeners(time_t now)
{
/* Wrong source address. See rfc1350 para 4. */
prettyprint_addr(&peer, daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff);
len = tftp_err(ERR_TID, daemon->packet, _("ignoring packet from %s (TID mismatch)"), daemon->addrbuff, NULL);
while(retry_send(sendto(transfer->sockfd, daemon->packet, len, 0, &peer.sa, sa_len(&peer))));
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&peer, TFTP_PORT);
#endif
}
}
}
@@ -635,9 +646,14 @@ void check_tftp_listeners(time_t now)
}
if (len != 0)
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
&transfer->peer, &transfer->source, transfer->if_index);
{
send_from(transfer->sockfd, !option_bool(OPT_SINGLE_PORT), daemon->packet, len,
&transfer->peer, &transfer->source, transfer->if_index);
#ifdef HAVE_DUMPFILE
dump_packet(DUMP_TFTP, (void *)daemon->packet, len, NULL, (union mysockaddr *)&transfer->peer, TFTP_PORT);
#endif
}
if (endcon || len == 0)
{
strcpy(daemon->namebuff, transfer->file->filename);
@@ -743,22 +759,21 @@ static void sanitise(char *buf)
}
#define MAXMESSAGE 500 /* limit to make packet < 512 bytes and definitely smaller than buffer */
static ssize_t tftp_err(int err, char *packet, char *message, char *file)
static ssize_t tftp_err(int err, char *packet, char *message, char *file, char *arg2)
{
struct errmess {
unsigned short op, err;
char message[];
} *mess = (struct errmess *)packet;
ssize_t len, ret = 4;
char *errstr = strerror(errno);
memset(packet, 0, daemon->packet_buff_sz);
if (file)
sanitise(file);
mess->op = htons(OP_ERR);
mess->err = htons(err);
len = snprintf(mess->message, MAXMESSAGE, message, file, errstr);
len = snprintf(mess->message, MAXMESSAGE, message, file, arg2);
ret += (len < MAXMESSAGE) ? len + 1 : MAXMESSAGE; /* include terminating zero */
if (err != ERR_FNF || !option_bool(OPT_QUIET_TFTP))
@@ -772,7 +787,7 @@ static ssize_t tftp_err_oops(char *packet, const char *file)
/* May have >1 refs to file, so potentially mangle a copy of the name */
if (file != daemon->namebuff)
strcpy(daemon->namebuff, file);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff);
return tftp_err(ERR_NOTDEF, packet, _("cannot read %s: %s"), daemon->namebuff, strerror(errno));
}
/* return -1 for error, zero for done. */
+1 -1
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
+17 -12
View File
@@ -1,4 +1,4 @@
/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley
/* 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
@@ -233,8 +233,6 @@ char *canonicalise(char *in, int *nomem)
{
# ifdef HAVE_LIBIDN2
rc = idn2_to_ascii_lz(in, &ret, IDN2_NONTRANSITIONAL);
if (rc == IDN2_DISALLOWED)
rc = idn2_to_ascii_lz(in, &ret, IDN2_TRANSITIONAL);
# else
rc = idna_to_ascii_lz(in, &ret, 0);
# endif
@@ -369,7 +367,7 @@ int sa_len(union mysockaddr *addr)
}
/* don't use strcasecmp and friends here - they may be messed up by LOCALE */
int hostname_isequal(const char *a, const char *b)
int hostname_order(const char *a, const char *b)
{
unsigned int c1, c2;
@@ -382,11 +380,19 @@ int hostname_isequal(const char *a, const char *b)
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
return 0;
if (c1 < c2)
return -1;
else if (c1 > c2)
return 1;
} while (c1);
return 1;
return 0;
}
int hostname_isequal(const char *a, const char *b)
{
return hostname_order(a, b) == 0;
}
/* is b equal to or a subdomain of a return 2 for equal, 1 for subdomain */
@@ -430,13 +436,12 @@ int hostname_issubdomain(char *a, char *b)
time_t dnsmasq_time(void)
{
#ifdef HAVE_BROKEN_RTC
struct tms dummy;
static long tps = 0;
struct timespec ts;
if (tps == 0)
tps = sysconf(_SC_CLK_TCK);
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
die(_("cannot read monotonic clock: %s"), NULL, EC_MISC);
return (time_t)(times(&dummy)/tps);
return ts.tv_sec;
#else
return time(NULL);
#endif