Compare commits

...

35 Commits

Author SHA1 Message Date
Simon Kelley
b72ecb3a59 Fix log message fields in wrong order in some auth replies. 2025-01-18 23:56:23 +00:00
Simon Kelley
c221030f89 Rename cache_validated() to cache_not_validated().
Let's give the poor programmers a chance.
2025-01-18 23:26:06 +00:00
Simon Kelley
5bbea085d0 Fix subtle bug in arbitrary-RR caching.
If the client asks for DNSSEC RRs via the do bit, and
we have an answer cached, we can only return the cached
answer if the RR was not validated. This is because
we don't the extra info (RRSIGS, NSECs) for a complete
validated answer. In that case we have to forward again.

This bug was that the "is the cache entry validated" test was
in an outer loop rather than an inner one. A cache hit on
a different RRtype that wasn't validated would satify the
condition to use the cache, even if the cache entry for
the required RRtype didn't. The only time when there can be a mix
of validated and non validated cache entries for the same domain
is when most are not validated, but one is a negative cache for
a DS record.

This bug took a long time to find.
2025-01-18 23:15:53 +00:00
Simon Kelley
622cf03ab9 Fix fubar that could return unsigned NODATA response when do bit set. 2025-01-18 22:16:29 +00:00
Simon Kelley
8ce27433f8 Handle DS queries to auth zones.
When dnsmasq is configured to act as an authoritative server and has
an authoritative zone configured, and recieves a query for
that zone _as_forwarder_ it answers the query directly rather
than forwarding it. This doesn't affect the answer, but it
saves dnsmasq forwarding the query to the recusor upstream,
whch then bounces it back to dnsmasq in auth mode. The
exception should be when the query is for the root of zone, for a DS
RR. The answer to that has to come from the parent, via the
recursor, and will typically be a proof-of-nonexistence since
dnsmasq doesn't support signed zones. This patch suppresses
local answers and forces forwarding to the upstream recursor
for such queries. It stops breakage when a DNSSEC validating
client makes queries to dnsmasq acting as forwarder for a zone
for which it is authoritative.
2025-01-18 08:57:14 +00:00
Simon Kelley
5d894620b4 Extend build fingerprinting to include CFLAGS.
If the value of CFLAGS is changed between builds, the makefile
will rebuid, in the same way as for COPTS.
2025-01-17 16:48:08 +00:00
Simon Kelley
71766c0c35 Tweak handling of duplicate DNS answers via UDP.
If we get a duplicate answer for a query via UDP which we have
either already received and started DNSSEC validation, or was
truncated and we've passed to TCP, then just ignore it.

The code was already in place, but had evolved wonky and
only worked for error replies which would otherwise prompt
a retransmit.
2025-01-13 20:30:37 +00:00
Simon Kelley
da58455508 Tweak 7d915a0bb9
A downstream query may have gone to TCP, not just DNSSEC queries.
2025-01-13 11:03:30 +00:00
Simon Kelley
b915c9a661 Attempt to keep running if a child process dies.
If a child process dies unexpectedly, log the error and
try and tidy up so the main process continues to run and
doesn't block awaiting the dead child.
2025-01-13 10:56:19 +00:00
Simon Kelley
424aaa0f9d Fix another 509afcd1d2 SNAFU 2025-01-13 10:32:55 +00:00
Andrew Sayers
c72c895869 Improve "no upstream servers configured" when D-Bus is enabled
Print a specific INFO message instead of a generic WARNING message,
so users know what to do.

Starting dnsmasq without upstream servers indicates a problem by default,
but is perfectly normal with D-Bus enabled.  For example, NetworkManager
starts dnsmasq with no upstream servers, then immediately populates it
over D-Bus.
2025-01-12 22:32:32 +00:00
Simon Kelley
b7156116c2 Fix SNAFU in 509afcd1d2 2025-01-12 22:28:12 +00:00
Simon Kelley
7d915a0bb9 Don't do retries over UDP when we've sent the query by TCP. 2025-01-12 22:02:05 +00:00
Simon Kelley
509afcd1d2 Refactor poll() loop.
Handling events on file descriptors can result in new file
descriptors being created or old ones being deleted. As such
the results of the last call to poll() become invalid in subtle
ways.

After handling each file descriptor in  check_dns_listeners()
return, to go around the poll() loop again and get valid data
for the new situation.

Thanks to Dominik Derigs for his indefatigable sleuthing of this one.
2025-01-12 21:36:09 +00:00
Simon Kelley
51343bd9a2 Treat replies with CD flag set the same for UDP and TCP code paths. 2025-01-12 16:25:07 +00:00
Simon Kelley
b58276a73c Return EDE OTHER error when DNSSEC validation abandoned.
This distinguishes the case where we found a message was bogus
from cases where the process failed.
2025-01-12 16:00:09 +00:00
Matthias Andree
f162d344c0 cache: Fix potential NULL deref in arcane situations. 2025-01-08 23:34:12 +00:00
Simon Kelley
0003db15cb Fix crash introduced in 6656790f24 2025-01-07 23:08:35 +00:00
Simon Kelley
275f4a4475 Remove arbitrary workspace size limit.
I have no memory for why this was ever there. It breaks DNSSEC
validation of large RRsets.

I can't see any DoS potential that is exposed by removing it.
2025-01-07 21:41:30 +00:00
Andrew Sayers
12e4565fef Improve "chown of PID file failed" message for missing CAP_CHOWN
Print a specific INFO message instead of a generic WARNING message,
so users aren't inconvenienced and maintainers know what to do.

Debian currently runs this service as part of NetworkManager,
in a systemd service without CAP_CHOWN.  Other distributions may
have the same problem, or might add the issue in future.
This fix should communicate the issue clearly to them.
2025-01-07 21:03:25 +00:00
Andrew Sayers
7af26eed32 Fix manpage typo.
s/will we/will be/
2025-01-07 21:01:15 +00:00
Simon Kelley
63dc6eb316 Fix read_write() changes for TCP timeout.
I misread the man page for socket(7) and TCP timeouts.

A timeout generates a -1 return and EAGAIN errno, NOT a short read.

Short reads are legit, and aborting when they are seen creates
hard-to-reproduce errors.
2025-01-07 20:53:03 +00:00
Simon Kelley
6656790f24 Handle queries with EDNS client subnet fields better.
If dnsmasq is configured to add an EDNS client subnet to a query,
it is careful to suppress use of the cache, since a cached answer may
not be valid for a query with a different client subnet.
Extend this behaviour to queries which arrive a dnsmasq
already carrying an EDNS client subnet.

This change is rather more involved than may seem necessary at first sight,
since the existing code relies on all queries being decorated by dnsmasq
and therefore not cached, so there is no chance that an incoming query
might hit the cache and cache lookup don't need to be suppressed, just
cache insertion. When downstream queries may be a mix of client-subnet
bearing and plain vanilla, it can't be assumed that the answers are never
in the cache, and queries with subnets must not do lookups.
2025-01-07 20:46:33 +00:00
Simon Kelley
c8de423038 Fix finger-trouble in immediately previous commit. 2025-01-07 17:00:18 +00:00
Simon Kelley
c52653f97c Correctly handle failure of pipe() call in swap_to_tcp() 2025-01-06 23:16:40 +00:00
Simon Kelley
e24c341068 Fix wrong packet size when dumpong packets to file. 2025-01-01 17:03:50 +00:00
Simon Kelley
5ef6c8c24f Extend fcb40ee73d to cover "Make install-i18n" 2024-12-30 13:29:48 +00:00
Simon Kelley
7c348a0b73 Extend d578da0665 to Linux-only code. 2024-12-24 11:31:34 +00:00
Matthias Andree
d578da0665 Fix FTBFS when using -pedantic compiler flag.
I am attaching an incremental git-am ready patch to go on top your Git HEAD,
to fix all sorts of issues and make this conforming C99 with default
options set,
and fix another load of warnings you receive when setting the compiler
to pick the nits,
-pedantic-errors -std=c99 (or c11, c18, c2x).
It changes many void * to uint8_t * to make the "increment by bytes"
explicit.
You can't do:

void *foo;
// ...
foo += 2.
2024-12-24 11:18:42 +00:00
Conrad Kostecki
8949ef44b4 Update DE translation. 2024-12-24 09:47:41 +00:00
DL6ER
3ac11cdd98 Add newly assigned RRTYPE DSYNC
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:19:00 +00:00
DL6ER
5d49fa112d Add newly assigned RRTYPEs NXNAME, CLA, and IPN
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:18:56 +00:00
DL6ER
d29d19e654 Add newly assigned RRTYPE WALLET (262)
Signed-off-by: DL6ER <dl6er@dl6er.de>
2024-12-23 15:18:47 +00:00
Simon Kelley
49ea7db74e Fix c9bc0156a8d36d56735831cb81e786d628ed73e
Eg.

dhcp-host=AA:BB:CC:DD:EE:FF,192.168.1.5,server,infinite

is broken.

Thanks to Dominik for the diagnosis.
2024-12-23 15:14:27 +00:00
Olaf Hering
fcb40ee73d Fix dependency in make install target
The make target 'install-common' expects results from the target 'all'.
A 'make -j install' may fail because both targets are brought
up-to-todate in parallel. As a result the final binary will not exist at
the time 'install-common' runs, because 'all' is not yet done.

Adjust the dependencies to update 'all' before processing 'install-common'.

Signed-off-by: Olaf Hering <olaf@aepfle.de>
2024-12-23 15:02:34 +00:00
22 changed files with 630 additions and 501 deletions

View File

@@ -75,7 +75,29 @@ version 2.91
Fix erroneous "DNSSEC validated" state with non-DNSSEC
upstream servers. Thanks to Dominik Derigs for the bug report.
Handle queries with EDNS client subnet fields better. If dnsmasq
is configured to add an EDNS client subnet to a query, it is careful
to suppress use of the cache, since a cached answer may not be valid
for a query with a different client subnet. Extend this behaviour
to queries which arrive a dnsmasq already carrying an EDNS client
subnet.
Handle DS queries to auth zones. When dnsmasq is configured to
act as an authoritative server and has an authoritative zone
configured, and recieves a query for that zone _as_forwarder_
it answers the query directly rather than forwarding it. This
doesn't affect the answer, but it saves dnsmasq forwarding the
query to the recusor upstream, whch then bounces it back to dnsmasq
in auth mode. The exception should be when the query is for the root
of zone, for a DS RR. The answer to that has to come from the parent,
via the recursor, and will typically be a proof-of-nonexistence
since dnsmasq doesn't support signed zones. This patch suppresses
local answers and forces forwarding to the upstream recursor for such
queries. It stops breakage when a DNSSEC validating client makes
queries to dnsmasq acting as forwarder for a zone for which it is
authoritative.
version 2.90
Fix reversion in --rev-server introduced in 2.88 which
caused breakage if the prefix length is not exactly divisible

View File

@@ -71,8 +71,8 @@ nft_cflags = `echo $(COPTS) | $(top)/bld/pkg-wrapper HAVE_NFTSET $(PKG_CONFIG
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 ' '
sum?=$(shell echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' ')
sum!=echo $(CC) -DDNSMASQ_COMPILE_FLAGS="$(CFLAGS)" -DDNSMASQ_COMPILE_OPTS $(COPTS) -E $(top)/$(SRC)/dnsmasq.h | ( md5sum 2>/dev/null || md5 ) | cut -f 1 -d ' '
copts_conf = .copts_$(sum)
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
@@ -102,9 +102,7 @@ clean : mostly_clean
rm -f core */core
rm -f *~ contrib/*/*~ */*~
install : all install-common
install-common :
install : all
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
@@ -121,7 +119,11 @@ all-i18n : $(BUILDDIR)
cd $(top) && cd $(BUILDDIR) && $(MAKE) top="$(top)" -f $(top)/Makefile $${f%.po}.mo; \
done
install-i18n : all-i18n install-common
install-i18n : all-i18n
$(INSTALL) -d $(DESTDIR)$(BINDIR)
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 $(MAN)/dnsmasq.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 755 $(BUILDDIR)/dnsmasq $(DESTDIR)$(BINDIR)
cd $(BUILDDIR); $(top)/bld/install-mo $(DESTDIR)$(LOCALEDIR) $(INSTALL)
cd $(MAN); ../bld/install-man $(DESTDIR)$(MANDIR) $(INSTALL)

View File

@@ -1429,7 +1429,7 @@ forces "simple and safe" behaviour to avoid problems in such a case.
.B --dhcp-relay=<local address>[,<server address>[#<server port>]][,<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
requests arriving on that interface will be relayed to a remote DHCP
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

137
po/de.po
View File

@@ -2,7 +2,7 @@
#
# This revised version is (C) Copyright by
# Matthias Andree <matthias.andree@gmx.de>, 2010 - 2021.
# Conrad Kostecki <conrad@kostecki.com>, 2014 - 2022.
# Conrad Kostecki <conrad@kostecki.com>, 2014 - 2024.
# It is subject to the GNU General Public License v2,
# or at your option, any later version.
#
@@ -10,10 +10,10 @@
# Simon Kelley <simon@thekelleys.org.uk>, 2005.
msgid ""
msgstr ""
"Project-Id-Version: dnsmasq 2.88\n"
"Project-Id-Version: dnsmasq 2.91\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-03-20 00:00+0000\n"
"PO-Revision-Date: 2022-11-17 20:08+0100\n"
"PO-Revision-Date: 2024-12-23 22:36+0100\n"
"Last-Translator: Conrad Kostecki <conrad@kostecki.com>\n"
"Language-Team: German <de@li.org>\n"
"Language: de\n"
@@ -21,7 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.2\n"
"X-Generator: Poedit 3.5\n"
#: cache.c:652
msgid "Internal error in cache."
@@ -43,9 +43,9 @@ msgid "bad name at %s line %d"
msgstr "Fehlerhafter Name in %s Zeile %d"
#: cache.c:1265
#, fuzzy, c-format
#, c-format
msgid "read %s - %d names"
msgstr "%s gelesen - %d Adressen"
msgstr "%s gelesen - %d Namen"
#: cache.c:1381
msgid "cleared cache"
@@ -84,7 +84,7 @@ msgstr "weitergeleitete Anfragen %u, lokal beantwortete Anfragen %u"
#: cache.c:1766
#, c-format
msgid "queries answered from stale cache %u"
msgstr ""
msgstr "Anfragen beantwortet vom veralteten Cache %u"
#: cache.c:1768
#, c-format
@@ -92,9 +92,9 @@ msgid "queries for authoritative zones %u"
msgstr "Anfragen nach autoritativen Zonen %u"
#: cache.c:1796
#, fuzzy, c-format
#, c-format
msgid "server %s#%d: queries sent %u, retried %u, failed %u, nxdomain replies %u, avg. latency %ums"
msgstr "Server %s#%d: Anfragen gesendet %u, erneut versucht oder fehlgeschlagen %u"
msgstr "Server %s#%d: Anfragen gesendet %u, erneut versucht %u, fehlgeschlagen %u, nxdomain-Antworten %u, durchschnittliche Latenz %ums"
#: util.c:51
#, c-format
@@ -120,14 +120,14 @@ msgid "failed to allocate %d bytes"
msgstr "Konnte %d Bytes nicht belegen"
#: util.c:344
#, fuzzy, c-format
#, c-format
msgid "failed to reallocate %d bytes"
msgstr "Konnte %d Bytes nicht belegen"
msgstr "Konnte %d Bytes nicht allozieren"
#: util.c:465
#, fuzzy, c-format
#, c-format
msgid "cannot read monotonic clock: %s"
msgstr "kann Netlink-Socket nicht erzeugen: %s"
msgstr "monotone Uhr kann nicht gelesen werden: %s"
# @Simon: not perfect but I cannot get nearer right now.
#: util.c:579
@@ -188,11 +188,11 @@ msgstr "Unberechtigte DNS-Anfragen von Windows-Rechnern nicht weiterleiten."
#: option.c:404
msgid "Don't include IPv4 addresses in DNS answers."
msgstr ""
msgstr "Keine IPv4-Adressen in DNS-Antworten inkludieren."
#: option.c:405
msgid "Don't include IPv6 addresses in DNS answers."
msgstr ""
msgstr "Keine IPv6-Adressen in DNS-Antworten inkludieren."
#: option.c:406
msgid "Enable DHCP in the range given with lease duration."
@@ -313,7 +313,7 @@ msgstr "Fehlerhafte Suchergebnisse NICHT zwischenspeichern."
#: option.c:434
msgid "Use expired cache data for faster reply."
msgstr ""
msgstr "Verwende abgelaufene Cachedaten für schnellere Antwort."
#: option.c:435
#, c-format
@@ -347,7 +347,7 @@ msgstr "Ausgehenden Port für DNS-Anfragen an vorgelagerte Server erzwingen."
#: option.c:442
msgid "Set maximum number of random originating ports for a query."
msgstr ""
msgstr "Setze die maximale Anzahl zufälliger Ursprungsports für eine Abfrage."
#: option.c:443
msgid "Do NOT read resolv.conf."
@@ -404,7 +404,7 @@ msgstr "Spezifiziere untere Gültigkeitsdauergrenze für Zwischenspeicher."
#: option.c:456
msgid "Retry DNS queries after this many milliseconds."
msgstr ""
msgstr "DNS-Abfragen nach so vielen Millisekunden wiederholen."
#: option.c:457
#, c-format
@@ -520,7 +520,7 @@ msgstr "Konfiguration aus allen Dateien in diesem Verzeichnis lesen."
#: option.c:484
msgid "Execute file and read configuration from stdin."
msgstr ""
msgstr "Führe Datei aus und lese die Konfiguration aus stdin."
#: option.c:485
msgid "Log to this syslog facility or file. (defaults to DAEMON)"
@@ -680,7 +680,7 @@ msgstr "Anfragende MAC-Adresse in die weiterleitende DNS-Anfrage einfügen."
#: option.c:523
msgid "Strip MAC information from queries."
msgstr ""
msgstr "Entferne die MAC-Information von Abfragen."
#: option.c:524
msgid "Add specified IP subnet to forwarded DNS queries."
@@ -688,7 +688,7 @@ msgstr "Füge spezifiziertes IP-Subnetz an weitergeleiteten DNS-Anfragen hinzu."
#: option.c:525
msgid "Strip ECS information from queries."
msgstr ""
msgstr "Entferne die ECS-Information von Abfragen."
#: option.c:526
msgid "Add client identification to forwarded DNS queries."
@@ -773,9 +773,8 @@ msgid "Specify ipsets to which matching domains should be added"
msgstr "Spezifiziere IPSets, zu denen passende Domains hinzugefügt werden sollen"
#: option.c:546
#, fuzzy
msgid "Specify nftables sets to which matching domains should be added"
msgstr "Spezifiziere IPSets, zu denen passende Domains hinzugefügt werden sollen"
msgstr "Geben Sie nftables sets an, zu denen passende Domänen hinzugefügt werden sollen"
#: option.c:547
msgid "Enable filtering of DNS queries with connection-track marks."
@@ -880,7 +879,7 @@ msgstr "Protokolliere kein Routine-TFTP."
#: option.c:572
msgid "Suppress round-robin ordering of DNS records."
msgstr ""
msgstr "Unterdrückt die Round-Robin-Sortierung von DNS-Einträgen."
#: option.c:802
#, c-format
@@ -915,11 +914,11 @@ msgstr "Schnittstellenbindung nicht unterstützt"
#: option.c:955
msgid "Cannot resolve server name"
msgstr ""
msgstr "Servername kann nicht aufgelöst werden"
#: option.c:991
msgid "cannot use IPv4 server address with IPv6 source address"
msgstr ""
msgstr "IPv4-Serveradresse kann nicht mit IPv6-Quelladresse verwendet werden"
#: option.c:997 option.c:1043
msgid "interface can only be specified once"
@@ -931,21 +930,19 @@ msgstr "Fehlerhafter Schnittestellenname"
#: option.c:1037
msgid "cannot use IPv6 server address with IPv4 source address"
msgstr ""
msgstr "IPv6-Serveradresse kann nicht mit IPv4-Quelladresse verwendet werden"
#: option.c:1124
#, fuzzy
msgid "bad IPv4 prefix length"
msgstr "fehlerhafte Präfixlänge"
msgstr "ungültige IPv4-Präfixlänge"
#: option.c:1155 option.c:1165 option.c:1240 option.c:1250 option.c:5360
msgid "error"
msgstr "Fehler"
#: option.c:1207
#, fuzzy
msgid "bad IPv6 prefix length"
msgstr "fehlerhafte Präfixlänge"
msgstr "ungültige IPv6-Präfixlänge"
#: option.c:1467
msgid "inappropriate vendor:"
@@ -1034,7 +1031,6 @@ msgid "recompile with HAVE_LUASCRIPT defined to enable Lua scripts"
msgstr "Neuübersetzung mit HAVE_LUASCRIPT nötig, um benutzerdefinierte Lua-Skripte auszuführen"
#: option.c:2447
#, fuzzy
msgid "invalid auth-zone"
msgstr "unzulässiger Alias-Bereich"
@@ -1059,9 +1055,8 @@ msgid "recompile with HAVE_IPSET defined to enable ipset directives"
msgstr "Neuübersetzung mit HAVE_IPSET nötig, um IPSet-Direktiven zu aktivieren"
#: option.c:3117
#, fuzzy
msgid "recompile with HAVE_NFTSET defined to enable nftset directives"
msgstr "Neuübersetzung mit HAVE_IPSET nötig, um IPSet-Direktiven zu aktivieren"
msgstr "Neukompilieren mit definiertem HAVE_NFTSET, um NFTSET-Direktiven zu aktivieren"
#: option.c:3192 option.c:3210
msgid "recompile with HAVE_CONNTRACK defined to enable connmark-allowlist directives"
@@ -1259,7 +1254,7 @@ msgstr "unzulässige Option"
#: option.c:5363
#, c-format
msgid " in output from %s"
msgstr ""
msgstr " in der Ausgabe von %s"
#: option.c:5365
#, c-format
@@ -1272,9 +1267,9 @@ msgid "read %s"
msgstr "%s gelesen"
#: option.c:5446
#, fuzzy, c-format
#, c-format
msgid "cannot execute %s: %s"
msgstr "kann %s nicht erstellen: %s"
msgstr "kann %s nicht ausführen: %s"
#: option.c:5454 option.c:5615 tftp.c:790
#, c-format
@@ -1282,14 +1277,14 @@ msgid "cannot read %s: %s"
msgstr "kann %s nicht lesen: %s"
#: option.c:5473
#, fuzzy, c-format
#, c-format
msgid "error executing %s: %s"
msgstr "konnte %s nicht ausführen: %s"
msgstr "Fehler bei der Ausführung von %s: %s"
#: option.c:5476
#, c-format
msgid "%s returns non-zero error code"
msgstr ""
msgstr "%s gibt einen Fehlercode ungleich Null zurück"
#: option.c:5775
msgid "junk found in command line"
@@ -1399,14 +1394,14 @@ msgid "reducing DNS packet size for nameserver %s to %d"
msgstr "Reduziere die DNS-Paketgröße für Nameserver %s auf %d"
#: forward.c:1565
#, fuzzy, c-format
#, c-format
msgid "ignoring query from non-local network %s (logged only once)"
msgstr "Ignoriere Anfrage von auswärtigem Netzwerk"
msgstr "Ignoriere Abfrage von nicht-lokalen Netzwerk %s (Nur einmal protokolliert)"
#: forward.c:2139
#, fuzzy, c-format
#, c-format
msgid "ignoring query from non-local network %s"
msgstr "Ignoriere Anfrage von auswärtigem Netzwerk"
msgstr "Ignoriere Abfrage von nicht-lokalen Netzwerk %s"
#: forward.c:2501
#, c-format
@@ -1488,7 +1483,7 @@ msgstr "ignoriere Namensserver %s - kann Socket nicht erzeugen/binden: %s"
#: network.c:1643
msgid "more servers are defined but not logged"
msgstr ""
msgstr "mehr Server sind definiert aber nicht protokolliert"
#: network.c:1654
msgid "(no DNSSEC)"
@@ -1605,7 +1600,7 @@ msgstr "max_port darf nicht kleiner als min_port sein"
#: dnsmasq.c:271
msgid "port_limit must not be larger than available port range"
msgstr ""
msgstr "port_limit darf nicht größer als der verfügbare Portbereich sein"
#: dnsmasq.c:278
msgid "--auth-server required when an auth zone is defined."
@@ -1810,9 +1805,9 @@ msgid "restricting maximum simultaneous TFTP transfers to %d"
msgstr "Begrenze gleichzeitige TFTP-Übertragungen auf maximal %d"
#: dnsmasq.c:1095
#, fuzzy, c-format
#, c-format
msgid "error binding DHCP socket to device %s"
msgstr "Fehler beim Senden des DHCP-Pakets an %s: %s"
msgstr "Fehler beim Binden des DHCP-Sockets an Gerät %s"
#: dnsmasq.c:1229
msgid "connected to system DBus"
@@ -1981,19 +1976,19 @@ msgid "read %s - %d addresses"
msgstr "%s gelesen - %d Adressen"
#: dhcp.c:1136
#, fuzzy, c-format
#, c-format
msgid "Cannot broadcast DHCP relay via interface %s"
msgstr "Kann nicht zum DHCPv6 Server multicasten ohne korrekte Schnittstelle"
msgstr "DHCP-Relay kann nicht über die Schnittstelle %s gesendet werden"
#: dhcp.c:1160
#, c-format
msgid "broadcast via %s"
msgstr ""
msgstr "broadcast via %s"
#: dhcp.c:1163 rfc3315.c:2219
#, fuzzy, c-format
#, c-format
msgid "DHCP relay at %s -> %s"
msgstr "DHCP Relais %s -> %s"
msgstr "DHCP-Relay bei %s -> %s"
#: lease.c:64
#, c-format
@@ -2405,14 +2400,14 @@ msgid "release received"
msgstr "Freigabe empfangen"
#: rfc3315.c:2200
#, fuzzy, c-format
#, c-format
msgid "Cannot multicast DHCP relay via interface %s"
msgstr "Kann nicht zum DHCPv6 Server multicasten ohne korrekte Schnittstelle"
msgstr "Multicast-DHCP-Relay über Schnittstelle %s nicht möglich"
#: rfc3315.c:2216
#, c-format
msgid "multicast via %s"
msgstr ""
msgstr "multicast via %s"
#: dhcp-common.c:187
#, c-format
@@ -2484,9 +2479,9 @@ msgid "router advertisement on %s%s"
msgstr "Router-Advertisment auf %s%s"
#: dhcp-common.c:1043
#, fuzzy, c-format
#, c-format
msgid "DHCP relay from %s via %s"
msgstr "DHCP Weiterleitung von %s nach %s"
msgstr "DHCP-Relay von %s über %s"
#: dhcp-common.c:1045
#, c-format
@@ -2621,9 +2616,9 @@ msgid "Insecure DS reply received for %s, check domain configuration and upstrea
msgstr "Unsichere DS-Antwort für %s, bitte Domainkonfiguration und Upstream DNS-Server für DNSSEC-Unterstützung überprüfen"
#: blockdata.c:55
#, fuzzy, c-format
#, c-format
msgid "pool memory in use %zu, max %zu, allocated %zu"
msgstr "Speicherpool in Benutzung %u, Max %u, zugewiesen %u"
msgstr "Speicherpool in Benutzung %zu, Max %zu, zugewiesen %zu"
#: tables.c:61
#, c-format
@@ -2695,24 +2690,23 @@ msgid "bad dynamic directory %s: %s"
msgstr "fehlerhaftes dynamisches Verzeichnis %s: %s"
#: inotify.c:186
#, fuzzy
msgid "not a directory"
msgstr "Kann auf Verzeichnis %s nicht zugreifen: %s"
msgstr "ist kein Verzeichnis"
#: inotify.c:299
#, c-format
msgid "inotify: %s removed"
msgstr ""
msgstr "inotify: %s entfernt"
#: inotify.c:301
#, fuzzy, c-format
#, c-format
msgid "inotify: %s new or modified"
msgstr "inotify, neue oder geänderte Datei %s"
msgstr "inotify: %s neu oder modifiziert"
#: inotify.c:309
#, c-format
msgid "inotify: flushed %u names read from %s"
msgstr ""
msgstr "inotify: %u Namen gelöscht, aus %s gelesen"
#: dump.c:68
#, c-format
@@ -2729,14 +2723,14 @@ msgid "failed to write packet dump"
msgstr "schreiben des Paketmitschnitts fehlgeschlagen"
#: dump.c:289
#, fuzzy, c-format
#, c-format
msgid "%u dumping packet %u mask 0x%04x"
msgstr "Lade UDP Paket %u Maske 0x%04x ab"
msgstr "%u dumpe Paket %u Maske 0x%04x"
#: dump.c:291
#, fuzzy, c-format
#, c-format
msgid "dumping packet %u mask 0x%04x"
msgstr "Lade UDP Paket %u Maske 0x%04x ab"
msgstr "Dumpe Packet %u Make 0x%04x"
#: ubus.c:79
#, c-format
@@ -2770,9 +2764,8 @@ msgid "Failed to create SHA-256 hash object"
msgstr "Kann SHA-256-Hash-Objekt nicht erstellen"
#: nftset.c:35
#, fuzzy
msgid "failed to create nftset context"
msgstr "konnte IPset-Kontroll-Socket nicht erzeugen: %s"
msgstr "Fehler beim Erstellen des NFTSET-Kontexts"
#~ msgid "bad IPv4 prefix"
#~ msgstr "fehlerhaftes IPv4-Präfix"

View File

@@ -35,7 +35,7 @@ struct arp_record {
static struct arp_record *arps = NULL, *old = NULL, *freelist = NULL;
static time_t last = 0;
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
static int filter_mac(int family, void *addrp, char *mac, size_t maclen, void *parmv)
{
struct arp_record *arp;

View File

@@ -513,7 +513,7 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
nxdomain = 0;
if ((crecp->flags & flag) && (local_query || filter_zone(zone, flag, &(crecp->addr))))
{
log_query(crecp->flags, name, &crecp->addr, record_source(crecp->uid), 0);
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, record_source(crecp->uid), 0);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))

View File

@@ -193,7 +193,7 @@ void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
{
size_t blen;
struct blockdata *b;
void *new, *d;
uint8_t *new, *d;
static unsigned int buff_len = 0;
static unsigned char *buff = NULL;

View File

@@ -101,6 +101,7 @@ static const struct {
{ 63, "ZONEMD" }, /* Message Digest Over Zone Data [RFC8976] ZONEMD/zonemd-completed-template 2018-12-12*/
{ 64, "SVCB" }, /* Service Binding [draft-ietf-dnsop-svcb-https-00] SVCB/svcb-completed-template 2020-06-30*/
{ 65, "HTTPS" }, /* HTTPS Binding [draft-ietf-dnsop-svcb-https-00] HTTPS/https-completed-template 2020-06-30*/
{ 66, "DSYNC" }, /* Endpoint discovery for delegation synchronization [draft-ietf-dnsop-generalized-notify-03] DSYNC/dsync-completed-template 2024-12-10 */
{ 99, "SPF" }, /* [RFC7208] */
{ 100, "UINFO" }, /* [IANA-Reserved] */
{ 101, "UID" }, /* [IANA-Reserved] */
@@ -112,6 +113,7 @@ static const struct {
{ 107, "LP" }, /* [RFC6742] ILNP/lp-completed-template */
{ 108, "EUI48" }, /* an EUI-48 address [RFC7043] EUI48/eui48-completed-template 2013-03-27*/
{ 109, "EUI64" }, /* an EUI-64 address [RFC7043] EUI64/eui64-completed-template 2013-03-27*/
{ 128, "NXNAME" }, /* NXDOMAIN indicator for Compact Denial of Existence https://www.iana.org/go/draft-ietf-dnsop-compact-denial-of-existence-04 */
{ 249, "TKEY" }, /* Transaction Key [RFC2930] */
{ 250, "TSIG" }, /* Transaction Signature [RFC8945] */
{ 251, "IXFR" }, /* incremental transfer [RFC1995] */
@@ -125,6 +127,9 @@ static const struct {
{ 259, "DOA" }, /* Digital Object Architecture [draft-durand-doa-over-dns] DOA/doa-completed-template 2017-08-30*/
{ 260, "AMTRELAY" }, /* Automatic Multicast Tunneling Relay [RFC8777] AMTRELAY/amtrelay-completed-template 2019-02-06*/
{ 261, "RESINFO" }, /* Resolver Information as Key/Value Pairs https://datatracker.ietf.org/doc/draft-ietf-add-resolver-info/06/ */
{ 262, "WALLET" }, /* Public wallet address https://www.iana.org/assignments/dns-parameters/WALLET/wallet-completed-template */
{ 263, "CLA" }, /* BP Convergence Layer Adapter https://www.iana.org/go/draft-johnson-dns-ipn-cla-07 */
{ 264, "IPN" }, /* BP Node Number https://www.iana.org/go/draft-johnson-dns-ipn-cla-07 */
{ 32768, "TA" }, /* DNSSEC Trust Authorities [Sam_Weiler][http://cameo.library.cmu.edu/][ Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.] 2005-12-13*/
{ 32769, "DLV" }, /* DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431] */
};
@@ -474,7 +479,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))
{
int rrmatch = 0;
if (crecp->flags & flags & F_RR)
if (addr && (crecp->flags & flags & F_RR))
{
unsigned short rrc = (crecp->flags & F_KEYTAG) ? crecp->addr.rrblock.rrtype : crecp->addr.rrdata.rrtype;
unsigned short rra = (flags & F_KEYTAG) ? addr->rrblock.rrtype : addr->rrdata.rrtype;

View File

@@ -362,6 +362,11 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_INOTIFY
#endif
/* This never compiles code, it's only used by the makefile to fingerprint builds. */
#ifdef DNSMASQ_COMPILE_FLAGS
static char *compile_flags = DNSMASQ_COMPILE_FLAGS;
#endif
/* Define a string indicating which options are in use.
DNSMASQ_COMPILE_OPTS is only defined in dnsmasq.c */

View File

@@ -32,6 +32,7 @@ static volatile int pipewrite;
static void set_dns_listeners(void);
static void set_tftp_listeners(void);
static void check_dns_listeners(time_t now);
static void do_tcp_connection(struct listener *listener, time_t now, int slot);
static void sig_handler(int sig);
static void async_event(int pipe, time_t now);
static void fatal_event(struct event_desc *ev, char *msg);
@@ -61,6 +62,7 @@ int main (int argc, char **argv)
int need_cap_net_admin = 0;
int need_cap_net_raw = 0;
int need_cap_net_bind_service = 0;
int have_cap_chown = 0;
char *bound_device = NULL;
int did_bind = 0;
struct server *serv;
@@ -556,6 +558,8 @@ int main (int argc, char **argv)
data = safe_malloc(sizeof(*data) * capsize);
capget(hdr, data); /* Get current values, for verification */
have_cap_chown = data->permitted & (1 << CAP_CHOWN);
if (need_cap_net_admin && !(data->permitted & (1 << CAP_NET_ADMIN)))
fail = "NET_ADMIN";
else if (need_cap_net_raw && !(data->permitted & (1 << CAP_NET_RAW)))
@@ -869,7 +873,14 @@ int main (int argc, char **argv)
my_syslog(LOG_INFO, _("compile time options: %s"), compile_opts);
if (chown_warn != 0)
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
{
#if defined(HAVE_LINUX_NETWORK)
if (chown_warn == EPERM && !have_cap_chown)
my_syslog(LOG_INFO, "chown of PID file %s failed: please add capability CAP_CHOWN", daemon->runfile);
else
#endif
my_syslog(LOG_WARNING, "chown of PID file %s failed: %s", daemon->runfile, strerror(chown_warn));
}
#ifdef HAVE_DBUS
if (option_bool(OPT_DBUS))
@@ -951,7 +962,14 @@ int main (int argc, char **argv)
my_syslog(LOG_WARNING, _("warning: ignoring resolv-file flag because no-resolv is set"));
daemon->resolv_files = NULL;
if (!daemon->servers)
my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
{
#ifdef HAVE_DBUS
if (option_bool(OPT_DBUS))
my_syslog(LOG_INFO, _("no upstream servers configured - please set them from DBus"));
else
#endif
my_syslog(LOG_WARNING, _("warning: no upstream servers configured"));
}
}
if (daemon->max_logs != 0)
@@ -1466,7 +1484,7 @@ static void async_event(int pipe, time_t now)
{
pid_t p;
struct event_desc ev;
int i, check = 0;
int wstatus, i, check = 0;
char *msg;
/* NOTE: the memory used to return msg is leaked: use msgs in events only
@@ -1529,7 +1547,7 @@ static void async_event(int pipe, time_t now)
case EVENT_CHILD:
/* See Stevens 5.10 */
while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
while ((p = waitpid(-1, &wstatus, WNOHANG)) != 0)
if (p == -1)
{
if (errno != EINTR)
@@ -1540,6 +1558,20 @@ static void async_event(int pipe, time_t now)
if (daemon->tcp_pids[i] == p)
{
daemon->tcp_pids[i] = 0;
if (!WIFEXITED(wstatus))
{
/* If a helper process dies, (eg with SIGSEV)
log that and attempt to patch things up so that the
parent can continue to function. */
my_syslog(LOG_WARNING, _("TCP helper process %u died unexpectedly"), (unsigned int)p);
if (daemon->tcp_pipes[i] != -1)
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
}
}
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pipes[i] == -1)
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
@@ -1822,247 +1854,281 @@ static void check_dns_listeners(time_t now)
struct listener *listener;
struct randfd_list *rfl;
int i;
int pipefd[2];
/* Note that handling events here can create or destroy fds and
render the result of the last poll() call invalid. Once
we find an fd that needs service, do it, then return to go around the
poll() loop again. This avoid really, really, wierd bugs. */
if (!option_bool(OPT_DEBUG))
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP))
{
/* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
process, and tcp_pipes to -1 and close the FD when we read the last
of the data - indicated by cache_recv_insert returning zero.
The order of these events is indeterminate, and both are needed
to free the process slot. Once the child process has gone, poll()
returns POLLHUP, not POLLIN, so have to check for both here. */
if (!cache_recv_insert(now, daemon->tcp_pipes[i]))
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pids[i] == 0)
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
}
return;
}
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
if (poll_check(serverfdp->fd, POLLIN))
reply_query(serverfdp->fd, now);
{
reply_query(serverfdp->fd, now);
return;
}
for (i = 0; i < daemon->numrrand; i++)
if (daemon->randomsocks[i].refcount != 0 &&
poll_check(daemon->randomsocks[i].fd, POLLIN))
reply_query(daemon->randomsocks[i].fd, now);
{
reply_query(daemon->randomsocks[i].fd, now);
return;
}
/* Check overflow random sockets too. */
for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next)
if (poll_check(rfl->rfd->fd, POLLIN))
reply_query(rfl->rfd->fd, now);
/* Races. The child process can die before we read all of the data from the
pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the
process, and tcp_pipes to -1 and close the FD when we read the last
of the data - indicated by cache_recv_insert returning zero.
The order of these events is indeterminate, and both are needed
to free the process slot. Once the child process has gone, poll()
returns POLLHUP, not POLLIN, so have to check for both here. */
if (!option_bool(OPT_DEBUG))
for (i = 0; i < daemon->max_procs; i++)
if (daemon->tcp_pipes[i] != -1 &&
poll_check(daemon->tcp_pipes[i], POLLIN | POLLHUP) &&
!cache_recv_insert(now, daemon->tcp_pipes[i]))
{
close(daemon->tcp_pipes[i]);
daemon->tcp_pipes[i] = -1;
/* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
if (daemon->tcp_pids[i] == 0)
daemon->metrics[METRIC_TCP_CONNECTIONS]--;
}
{
reply_query(rfl->rfd->fd, now);
return;
}
for (listener = daemon->listeners; listener; listener = listener->next)
{
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
if (listener->fd != -1 && poll_check(listener->fd, POLLIN))
{
receive_query(listener, now);
/* check to see if we have a free tcp process slot.
Note that we can't assume that because we had
at least one a poll() time, that we still do.
There may be more waiting connections after
poll() returns then free process slots. */
for (i = daemon->max_procs - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
return;
}
/* check to see if we have a free tcp process slot.
Note that we can't assume that because we had
at least one a poll() time, that we still do.
There may be more waiting connections after
poll() returns then free process slots. */
for (i = daemon->max_procs - 1; i >= 0; i--)
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN))
if (i >= 0)
for (listener = daemon->listeners; listener; listener = listener->next)
if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN))
{
int confd, client_ok = 1;
struct irec *iface = NULL;
pid_t p;
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
do_tcp_connection(listener, now, i);
return;
}
}
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
if (confd == -1)
continue;
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
{
close(confd);
continue;
}
/* Make sure that the interface list is up-to-date.
We do this here as we may need the results below, and
the DNS code needs them for --interface-name stuff.
static void do_tcp_connection(struct listener *listener, time_t now, int slot)
{
int confd, client_ok = 1;
struct irec *iface = NULL;
pid_t p;
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
unsigned char a = 0, *buff;
struct server *s;
int flags, auth_dns;
struct in_addr netmask;
int pipefd[2];
Multiple calls to enumerate_interfaces() per select loop are
inhibited, so calls to it in the child process (which doesn't select())
have no effect. This avoids two processes reading from the same
netlink fd and screwing the pooch entirely.
*/
enumerate_interfaces(0);
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
if (confd == -1)
return;
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
{
closeconandreturn:
shutdown(confd, SHUT_RDWR);
close(confd);
return;
}
/* Make sure that the interface list is up-to-date.
We do this here as we may need the results below, and
the DNS code needs them for --interface-name stuff.
Multiple calls to enumerate_interfaces() per select loop are
inhibited, so calls to it in the child process (which doesn't select())
have no effect. This avoids two processes reading from the same
netlink fd and screwing the pooch entirely.
*/
enumerate_interfaces(0);
if (option_bool(OPT_NOWILD))
iface = listener->iface; /* May be NULL */
else
{
int if_index;
char intr_name[IF_NAMESIZE];
/* if we can find the arrival interface, check it's one that's allowed */
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
indextoname(listener->tcpfd, if_index, intr_name))
{
union all_addr addr;
if (option_bool(OPT_NOWILD))
iface = listener->iface; /* May be NULL */
else
{
int if_index;
char intr_name[IF_NAMESIZE];
/* if we can find the arrival interface, check it's one that's allowed */
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
indextoname(listener->tcpfd, if_index, intr_name))
{
union all_addr addr;
if (tcp_addr.sa.sa_family == AF_INET6)
addr.addr6 = tcp_addr.in6.sin6_addr;
else
addr.addr4 = tcp_addr.in.sin_addr;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->index == if_index &&
iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
break;
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
client_ok = 0;
}
if (option_bool(OPT_CLEVERBIND))
iface = listener->iface; /* May be NULL */
else
{
/* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as
the local address of the TCP connection, then looking to see if that's
an allowed interface. As a side effect, we get the netmask of the
interface too, for localisation. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr))
break;
if (!iface)
client_ok = 0;
}
}
if (!client_ok)
{
shutdown(confd, SHUT_RDWR);
close(confd);
}
else if (!option_bool(OPT_DEBUG) && pipe(pipefd) == 0 && (p = fork()) != 0)
{
close(pipefd[1]); /* parent needs read pipe end. */
if (p == -1)
close(pipefd[0]);
else
{
#ifdef HAVE_LINUX_NETWORK
/* The child process inherits the netlink socket,
which it never uses, but when the parent (us)
uses it in the future, the answer may go to the
child, resulting in the parent blocking
forever awaiting the result. To avoid this
the child closes the netlink socket, but there's
a nasty race, since the parent may use netlink
before the child has done the close.
To avoid this, the parent blocks here until a
single byte comes back up the pipe, which
is sent by the child after it has closed the
netlink socket. */
unsigned char a;
read_write(pipefd[0], &a, 1, RW_READ);
#endif
/* i holds index of free slot */
daemon->tcp_pids[i] = p;
daemon->tcp_pipes[i] = pipefd[0];
daemon->metrics[METRIC_TCP_CONNECTIONS]++;
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
}
close(confd);
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
daemon->log_id += TCP_MAX_QUERIES;
#ifdef HAVE_DNSSEC
/* It can do more if making DNSSEC queries too. */
if (option_bool(OPT_DNSSEC_VALID))
daemon->log_id += daemon->limit[LIMIT_WORK];
#endif
}
if (tcp_addr.sa.sa_family == AF_INET6)
addr.addr6 = tcp_addr.in6.sin6_addr;
else
{
unsigned char *buff;
struct server *s;
int flags;
struct in_addr netmask;
int auth_dns;
if (iface)
{
netmask = iface->netmask;
auth_dns = iface->dns_auth;
}
else
{
netmask.s_addr = 0;
auth_dns = 0;
}
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
terminate the process. */
if (!option_bool(OPT_DEBUG))
{
#ifdef HAVE_LINUX_NETWORK
/* See comment above re: netlink socket. */
unsigned char a = 0;
close(daemon->netlinkfd);
read_write(pipefd[1], &a, 1, RW_WRITE);
#endif
alarm(CHILD_LIFETIME);
close(pipefd[0]); /* close read end in child. */
daemon->pipe_to_parent = pipefd[1];
}
/* The connected socket inherits non-blocking
attribute from the listening socket.
Reset that here. */
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
if (buff)
free(buff);
for (s = daemon->servers; s; s = s->next)
if (s->tcpfd != -1)
{
shutdown(s->tcpfd, SHUT_RDWR);
close(s->tcpfd);
s->tcpfd = -1;
}
if (!option_bool(OPT_DEBUG))
{
close(daemon->pipe_to_parent);
flush_log();
_exit(0);
}
}
addr.addr4 = tcp_addr.in.sin_addr;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->index == if_index &&
iface->addr.sa.sa_family == tcp_addr.sa.sa_family)
break;
if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
client_ok = 0;
}
if (option_bool(OPT_CLEVERBIND))
iface = listener->iface; /* May be NULL */
else
{
/* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as
the local address of the TCP connection, then looking to see if that's
an allowed interface. As a side effect, we get the netmask of the
interface too, for localisation. */
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr))
break;
if (!iface)
client_ok = 0;
}
}
if (!client_ok)
goto closeconandreturn;
if (!option_bool(OPT_DEBUG))
{
if (pipe(pipefd) == -1)
goto closeconandreturn; /* pipe failed */
if ((p = fork()) == -1)
{
/* fork failed */
close(pipefd[0]);
close(pipefd[1]);
goto closeconandreturn;
}
if (p != 0)
{
/* fork() done: parent side */
close(pipefd[1]); /* parent needs read pipe end. */
#ifdef HAVE_LINUX_NETWORK
/* The child process inherits the netlink socket,
which it never uses, but when the parent (us)
uses it in the future, the answer may go to the
child, resulting in the parent blocking
forever awaiting the result. To avoid this
the child closes the netlink socket, but there's
a nasty race, since the parent may use netlink
before the child has done the close.
To avoid this, the parent blocks here until a
single byte comes back up the pipe, which
is sent by the child after it has closed the
netlink socket. */
read_write(pipefd[0], &a, 1, RW_READ);
#endif
daemon->tcp_pids[slot] = p;
daemon->tcp_pipes[slot] = pipefd[0];
daemon->metrics[METRIC_TCP_CONNECTIONS]++;
if (daemon->metrics[METRIC_TCP_CONNECTIONS] > daemon->max_procs_used)
daemon->max_procs_used = daemon->metrics[METRIC_TCP_CONNECTIONS];
close(confd);
/* The child can use up to TCP_MAX_QUERIES ids, so skip that many. */
daemon->log_id += TCP_MAX_QUERIES;
#ifdef HAVE_DNSSEC
/* It can do more if making DNSSEC queries too. */
if (option_bool(OPT_DNSSEC_VALID))
daemon->log_id += daemon->limit[LIMIT_WORK];
#endif
return;
}
}
if (iface)
{
netmask = iface->netmask;
auth_dns = iface->dns_auth;
}
else
{
netmask.s_addr = 0;
auth_dns = 0;
}
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
terminate the process. */
if (!option_bool(OPT_DEBUG))
{
#ifdef HAVE_LINUX_NETWORK
/* See comment above re: netlink socket. */
close(daemon->netlinkfd);
read_write(pipefd[1], &a, 1, RW_WRITE);
#endif
alarm(CHILD_LIFETIME);
close(pipefd[0]); /* close read end in child. */
daemon->pipe_to_parent = pipefd[1];
}
/* The connected socket inherits non-blocking
attribute from the listening socket.
Reset that here. */
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
if (buff)
free(buff);
for (s = daemon->servers; s; s = s->next)
if (s->tcpfd != -1)
{
shutdown(s->tcpfd, SHUT_RDWR);
close(s->tcpfd);
s->tcpfd = -1;
}
if (!option_bool(OPT_DEBUG))
{
close(daemon->pipe_to_parent);
flush_log();
_exit(0);
}
}
#ifdef HAVE_DNSSEC
/* If a DNSSEC query over UDP returns a truncated answer,
we swap to the TCP path. This routine is responsible for forking
@@ -2091,11 +2157,11 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1)
break;
/* No slots */
if (i < 0)
/* No slots or no pipe */
if (i < 0 || pipe(pipefd) != 0)
return STAT_ABANDONED;
if (pipe(pipefd) == 0 && (p = fork()) != 0)
if ((p = fork()) != 0)
{
close(pipefd[1]); /* parent needs read pipe end. */
if (p == -1)

View File

@@ -339,7 +339,7 @@ union all_addr {
struct datablock {
unsigned short rrtype;
unsigned char datalen; /* also length of SOA in negative records. */
char data[];
char data[1];
} rrdata;
};
@@ -772,9 +772,8 @@ struct dyndir {
#define FREC_DS_QUERY 16
#define FREC_AD_QUESTION 32
#define FREC_DO_QUESTION 64
#define FREC_ADDED_PHEADER 128
#define FREC_HAS_PHEADER 256
#define FREC_GONE_TO_TCP 512
#define FREC_HAS_PHEADER 128
#define FREC_GONE_TO_TCP 256
struct frec {
struct frec_src {
@@ -1402,7 +1401,7 @@ void report_addresses(struct dns_header *header, size_t len, u32 mark);
#endif
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int *stale, int *filtered);
time_t now, int ad_reqd, int do_bit, int no_cache, int *stale, int *filtered);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen);
@@ -1667,7 +1666,7 @@ void route_sock(void);
/* bpf.c or netlink.c */
typedef union {
int (*af_unspec)(int family, char *addrp, char *mac, size_t maclen, void *parmv);
int (*af_unspec)(int family, void *addrp, char *mac, size_t maclen, void *parmv);
int (*af_inet)(struct in_addr local, int if_index, char *label, struct in_addr netmask, struct in_addr broadcast, void *vparam);
int (*af_inet6)(struct in6_addr *local, int prefix, int scope, int if_index, int flags, unsigned int preferred, unsigned int valid, void *vparam);
int (*af_local)(int index, unsigned int type, char *mac, size_t maclen, void *parm);

View File

@@ -417,21 +417,34 @@ static size_t add_source_addr(struct dns_header *header, size_t plen, unsigned c
else if (option_bool(OPT_STRIP_ECS))
replace = 2;
else
return plen;
{
unsigned char *pheader;
/* If we still think the data is cacheable, and we're not
messing with EDNS client subnet ourselves, see if the client
sent a client subnet. If so, mark the data as uncacheable */
if (*cacheable &&
(pheader = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL)) &&
!check_source(header, plen, pheader, NULL))
*cacheable = 0;
return plen;
}
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0, replace);
}
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
{
/* Section 9.2, Check that subnet option in reply matches. */
/* Section 9.2, Check that subnet option (if any) in reply matches.
if peer == NULL, this degrades to a check for the existence of and EDNS0 client-subnet option. */
int len, calc_len;
struct subnet_opt opt;
unsigned char *p;
int code, i, rdlen;
calc_len = calc_subnet_opt(&opt, peer, NULL);
if (peer)
calc_len = calc_subnet_opt(&opt, peer, NULL);
if (!(p = skip_name(pseudoheader, header, plen, 10)))
return 1;
@@ -443,21 +456,26 @@ int check_source(struct dns_header *header, size_t plen, unsigned char *pseudohe
return 1; /* bad packet */
/* check if option there */
for (i = 0; i + 4 < rdlen; i += len + 4)
for (i = 0; i + 4 < rdlen; i += len + 4)
{
GETSHORT(code, p);
GETSHORT(len, p);
if (code == EDNS0_OPTION_CLIENT_SUBNET)
{
/* make sure this doesn't mismatch. */
opt.scope_netmask = p[3];
if (len != calc_len || memcmp(p, &opt, len) != 0)
if (peer)
{
/* make sure this doesn't mismatch. */
opt.scope_netmask = p[3];
if (len != calc_len || memcmp(p, &opt, len) != 0)
return 0;
}
else if (((struct subnet_opt *)p)->source_netmask != 0)
return 0;
}
p += len;
}
return 1;
return 1;
}
/* See https://docs.umbrella.com/umbrella-api/docs/identifying-dns-traffic for
@@ -491,7 +509,7 @@ static size_t add_umbrella_opt(struct dns_header *header, size_t plen, unsigned
{
*cacheable = 0;
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {}};
struct umbrella_opt opt = {{"ODNS"}, UMBRELLA_VERSION, 0, {0}};
u8 *u = &opt.fields[0];
int family = source->sa.sa_family;
int size = family == AF_INET ? INADDRSZ : IN6ADDRSZ;
@@ -541,6 +559,6 @@ size_t add_edns0_config(struct dns_header *header, size_t plen, unsigned char *l
plen = add_umbrella_opt(header, plen, limit, source, cacheable);
plen = add_source_addr(header, plen, limit, source, cacheable);
return plen;
}

View File

@@ -163,37 +163,22 @@ static int domain_no_rebind(char *domain)
return 0;
}
static int forward_query(int udpfd, union mysockaddr *udpaddr,
union all_addr *dst_addr, unsigned int dst_iface,
struct dns_header *header, size_t plen, size_t replylimit, time_t now,
struct frec *forward, int ad_reqd, int do_bit, int fast_retry)
static void forward_query(int udpfd, union mysockaddr *udpaddr,
union all_addr *dst_addr, unsigned int dst_iface,
struct dns_header *header, size_t plen, size_t replylimit, time_t now,
struct frec *forward, unsigned int fwd_flags, int fast_retry)
{
unsigned int flags = 0;
unsigned int fwd_flags = 0;
int is_dnssec = forward && (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY));
struct server *master;
unsigned int gotname;
int old_src = 0, old_reply = 0;
int first, last, start = 0;
int cacheable, forwarded = 0;
unsigned char *oph;
int forwarded = 0;
int ede = EDE_UNSET;
(void)do_bit;
unsigned short rrtype;
gotname = extract_request(header, plen, daemon->namebuff, &rrtype);
oph = find_pseudoheader(header, plen, NULL, NULL, NULL, NULL);
if (header->hb4 & HB4_CD)
fwd_flags |= FREC_CHECKING_DISABLED;
if (ad_reqd)
fwd_flags |= FREC_AD_QUESTION;
if (oph)
fwd_flags |= FREC_HAS_PHEADER;
#ifdef HAVE_DNSSEC
if (do_bit)
fwd_flags |= FREC_DO_QUESTION;
#endif
/* Check for retry on existing query.
FREC_DNSKEY and FREC_DS_QUERY are never set in flags, so the test below
@@ -205,6 +190,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
{
old_src = 1;
old_reply = 1;
fwd_flags = forward->flags;
}
else if (gotname && (forward = lookup_frec(daemon->namebuff, C_IN, (int)rrtype, -1, fwd_flags,
FREC_CHECKING_DISABLED | FREC_AD_QUESTION | FREC_DO_QUESTION |
@@ -268,7 +254,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
it's safe to wait for the reply from the first without
forwarding the second. */
if (difftime(now, forward->time) < 2)
return 0;
return;
}
/* use our id when resending */
@@ -321,11 +307,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->flags = fwd_flags;
plen = add_edns0_config(header, plen, ((unsigned char *)header) + daemon->edns_pktsz, &forward->frec_src.source, now, &cacheable);
if (!cacheable)
forward->flags |= FREC_NO_CACHE;
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
{
@@ -338,10 +319,6 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#endif
/* If there wasn't a PH before, and there is now, we added it. */
if (!oph && find_pseudoheader(header, plen, NULL, NULL, NULL, NULL))
forward->flags |= FREC_ADDED_PHEADER;
/* Do these before saving query. */
forward->frec_src.orig_id = ntohs(header->id);
forward->new_id = get_id();
@@ -365,15 +342,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
forward->forwardall = 0;
if (domain_no_rebind(daemon->namebuff))
forward->flags |= FREC_NOREBIND;
if (header->hb4 & HB4_CD)
forward->flags |= FREC_CHECKING_DISABLED;
if (ad_reqd)
forward->flags |= FREC_AD_QUESTION;
#ifdef HAVE_DNSSEC
forward->work_counter = daemon->limit[LIMIT_WORK];
forward->validate_counter = daemon->limit[LIMIT_CRYPTO];
if (do_bit)
forward->flags |= FREC_DO_QUESTION;
#endif
start = first;
@@ -403,6 +374,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
while (forward->blocking_query)
forward = forward->blocking_query;
/* Don't retry if we've already sent it via TCP. */
if (forward->flags & FREC_GONE_TO_TCP)
return;
if (forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY))
{
/* log_id should match previous DNSSEC query. */
@@ -415,8 +390,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
/* Find suitable servers: should never fail. */
if (!filter_servers(forward->sentto->arrayposn, F_DNSSECOK, &first, &last))
return 0;
return;
is_dnssec = 1;
forward->forwardall = 1;
}
@@ -531,8 +506,9 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (forwarded || is_dnssec)
{
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
forward->forward_timestamp = dnsmasq_milliseconds();
return 1;
return;
}
/* could not send on, prepare to return */
@@ -544,16 +520,16 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (udpfd != -1)
{
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, (char *)(header + replylimit), first, last, ede)))
return 0;
return;
if (oph)
if (fwd_flags & FREC_HAS_PHEADER)
{
u16 swap = htons((u16)ede);
if (ede != EDE_UNSET)
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, 0, 0);
else
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), 0, NULL, 0, do_bit, 0);
plen = add_pseudoheader(header, plen, (unsigned char *)(header + replylimit), 0, NULL, 0, 0, 0);
}
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
@@ -572,7 +548,8 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
send_from(udpfd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, plen, udpaddr, dst_addr, dst_iface);
}
return 0;
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
return;
}
/* Check if any frecs need to do a retry, and action that if so.
@@ -611,8 +588,7 @@ int fast_retry(time_t now)
daemon->log_display_id = f->frec_src.log_id;
daemon->log_source_addr = NULL;
forward_query(-1, NULL, NULL, 0, header, f->stash_len, 0, now, f,
f->flags & FREC_AD_QUESTION, f->flags & FREC_DO_QUESTION, 1);
forward_query(-1, NULL, NULL, 0, header, f->stash_len, 0, now, f, 0, 1);
to_run = f->forward_delay = 2 * f->forward_delay;
}
@@ -810,10 +786,9 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
header->ancount = htons(0);
header->nscount = htons(0);
header->arcount = htons(0);
ede = EDE_DNSSEC_BOGUS;
}
}
else if (!(header->hb4 & HB4_CD) && ad_reqd && cache_secure)
else if (ad_reqd && cache_secure)
header->hb4 |= HB4_AD;
/* If the requestor didn't set the DO bit, don't return DNSSEC info. */
@@ -847,10 +822,6 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
daemon->log_display_id = forward->frec_src.log_id;
/* We've had a reply already, which we're validating. Ignore this duplicate */
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
return;
/* Find the original query that started it all.... */
for (orig = forward; orig->dependent; orig = orig->dependent);
@@ -1177,23 +1148,24 @@ void reply_query(int fd, time_t now)
if (daemon->ignore_addr && RCODE(header) == NOERROR &&
check_for_ignored_address(header, n))
return;
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) && forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
{
#ifdef HAVE_DNSSEC
/* The query MAY have got a good answer, and be awaiting
the results of further queries, in which case
The Stash contains something else and we don't need to retry anyway. */
the stash contains something else and we don't need to retry anyway.
We may also have already got a truncated reply, and be in the process
of doing the query by TCP so can ignore further, probably truncated, UDP answers. */
if (forward->blocking_query || (forward->flags & FREC_GONE_TO_TCP))
return;
#endif
if ((RCODE(header) == REFUSED || RCODE(header) == SERVFAIL) && forward->forwardall == 0)
/* for broken servers, attempt to send to another one. */
{
/* Get the saved query back. */
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
forward_query(-1, NULL, NULL, 0, header, forward->stash_len, 0, now, forward,
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION, 0);
forward_query(-1, NULL, NULL, 0, header, forward->stash_len, 0, now, forward, 0, 0);
return;
}
@@ -1275,20 +1247,25 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
char *result, *domain = "result";
union all_addr a;
a.log.ede = ede = errflags_to_ede(status);
ede = errflags_to_ede(status);
if (STAT_ISEQUAL(status, STAT_ABANDONED))
{
result = "ABANDONED";
status = STAT_BOGUS;
if (ede == EDE_UNSET)
ede = EDE_OTHER;
}
else
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
if (STAT_ISEQUAL(status, STAT_SECURE))
cache_secure = 1;
else if (STAT_ISEQUAL(status, STAT_BOGUS))
{
if (ede == EDE_UNSET)
ede = EDE_DNSSEC_BOGUS;
no_cache_dnssec = 1;
bogusanswer = 1;
@@ -1296,6 +1273,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
domain = daemon->namebuff;
}
a.log.ede = ede;
log_query(F_SECSTAT, domain, &a, result, 0);
}
}
@@ -1315,7 +1293,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
header->hb4 |= HB4_CD;
else
header->hb4 &= ~HB4_CD;
/* Never cache answers which are contingent on the source or MAC address EDSN0 option,
since the cache is ignorant of such things. */
if (forward->flags & FREC_NO_CACHE)
@@ -1323,7 +1301,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
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->frec_src.source,
!(forward->flags & FREC_HAS_PHEADER), &forward->frec_src.source,
((unsigned char *)header) + daemon->edns_pktsz, ede)))
{
struct frec_src *src;
@@ -1391,7 +1369,7 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
&src->source, &src->dest, src->iface);
#ifdef HAVE_DUMPFILE
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)nn, NULL, &src->source, src->fd);
dump_packet_udp(DUMP_REPLY, daemon->packet, (size_t)new, NULL, &src->source, src->fd);
#endif
}
}
@@ -1454,9 +1432,10 @@ void receive_query(struct listener *listen, time_t now)
struct in_addr netmask, dst_addr_4;
size_t m;
ssize_t n;
int if_index = 0, auth_dns = 0, do_bit = 0, have_pseudoheader = 0;
int if_index = 0, auth_dns = 0, do_bit = 0;
unsigned int fwd_flags = 0;
int stale = 0, filtered = 0, ede = EDE_UNSET, do_forward = 0;
int metric, ad_reqd, fd;
int metric, fd;
struct blockdata *saved_question = NULL;
#ifdef HAVE_CONNTRACK
unsigned int mark = 0;
@@ -1712,15 +1691,27 @@ void receive_query(struct listener *listen, time_t now)
&source_addr, auth_dns ? "auth" : "query", type);
#ifdef HAVE_AUTH
/* find queries for zones we're authoritative for, and answer them directly */
/* Find queries for zones we're authoritative for, and answer them directly.
The exception to this is DS queries for the zone route. They
have to come from the parent zone. Since dnsmasq's auth server
can't do DNSSEC, the zone will be unsigned, and anything using
dnsmasq as a forwarder and doing validation will be expecting to
see the proof of non-existence from the parent. */
if (!auth_dns && !option_bool(OPT_LOCALISE))
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, daemon->namebuff, NULL))
{
auth_dns = 1;
local_auth = 1;
break;
}
{
char *cut;
if (in_zone(zone, daemon->namebuff, &cut))
{
if (type != T_DS || cut)
{
auth_dns = 1;
local_auth = 1;
}
break;
}
}
#endif
#ifdef HAVE_LOOP
@@ -1734,7 +1725,8 @@ void receive_query(struct listener *listen, time_t now)
{
unsigned short flags;
have_pseudoheader = 1;
fwd_flags |= FREC_HAS_PHEADER;
GETSHORT(udp_size, pheader);
pheader += 2; /* ext_rcode */
GETSHORT(flags, pheader);
@@ -1752,10 +1744,15 @@ void receive_query(struct listener *listen, time_t now)
udp_size = PACKETSZ; /* Sanity check - can't reduce below default. RFC 6891 6.2.3 */
}
ad_reqd = do_bit;
/* RFC 6840 5.7 */
if (header->hb4 & HB4_AD)
ad_reqd = 1;
if (do_bit || (header->hb4 & HB4_AD))
fwd_flags |= FREC_AD_QUESTION;
if (do_bit)
fwd_flags |= FREC_DO_QUESTION;
if (header->hb4 & HB4_CD)
fwd_flags |= FREC_CHECKING_DISABLED;
fd = listen->fd;
@@ -1790,10 +1787,16 @@ void receive_query(struct listener *listen, time_t now)
#endif
else
{
int cacheable;
n = add_edns0_config(header, n, ((unsigned char *)header) + daemon->edns_pktsz, &source_addr, now, &cacheable);
saved_question = blockdata_alloc((char *) header, (size_t)n);
if (!cacheable)
fwd_flags |= FREC_NO_CACHE;
m = answer_request(header, ((char *) header) + udp_size, (size_t)n,
dst_addr_4, netmask, now, ad_reqd, do_bit, &stale, &filtered);
dst_addr_4, netmask, now, fwd_flags & FREC_AD_QUESTION, do_bit, !cacheable, &stale, &filtered);
metric = stale ? METRIC_DNS_STALE_ANSWERED : METRIC_DNS_LOCAL_ANSWERED;
@@ -1814,7 +1817,7 @@ void receive_query(struct listener *listen, time_t now)
if (m != 0)
{
if (have_pseudoheader)
if (fwd_flags & FREC_HAS_PHEADER)
{
if (ede != EDE_UNSET)
{
@@ -1863,12 +1866,9 @@ void receive_query(struct listener *listen, time_t now)
blockdata_retrieve(saved_question, (size_t)n, (void *)header);
blockdata_free(saved_question);
saved_question = NULL;
if (forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n,
udp_size, now, NULL, ad_reqd, do_bit, 0))
daemon->metrics[METRIC_DNS_QUERIES_FORWARDED]++;
else
daemon->metrics[METRIC_DNS_LOCAL_ANSWERED]++;
forward_query(fd, &source_addr, &dst_addr, if_index, header, (size_t)n,
udp_size, now, NULL, fwd_flags, 0);
}
blockdata_free(saved_question);
@@ -2212,7 +2212,7 @@ unsigned char *tcp_request(int confd, time_t now,
#ifdef HAVE_AUTH
int local_auth = 0;
#endif
int checking_disabled, do_bit = 0, ad_reqd = 0, added_pheader = 0, have_pseudoheader = 0;
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
struct blockdata *saved_question = NULL;
unsigned short qtype;
unsigned int gotname = 0;
@@ -2284,7 +2284,7 @@ unsigned char *tcp_request(int confd, time_t now,
while (1)
{
int stale = 0, ede = EDE_UNSET;
int cacheable = 1, stale = 0, ede = EDE_UNSET;
size_t m = 0;
unsigned int flags = 0;
#ifdef HAVE_AUTH
@@ -2329,6 +2329,7 @@ unsigned char *tcp_request(int confd, time_t now,
if (saved_question)
blockdata_free(saved_question);
size = add_edns0_config(header, size, ((unsigned char *) header) + 65536, &peer_addr, now, &cacheable);
saved_question = blockdata_alloc((char *)header, (size_t)size);
saved_size = size;
@@ -2336,15 +2337,27 @@ unsigned char *tcp_request(int confd, time_t now,
&peer_addr, auth_dns ? "auth" : "query", qtype);
#ifdef HAVE_AUTH
/* find queries for zones we're authoritative for, and answer them directly */
/* Find queries for zones we're authoritative for, and answer them directly.
The exception to this is DS queries for the zone route. They
have to come from the parent zone. Since dnsmasq's auth server
can't do DNSSEC, the zone will be unsigned, and anything using
dnsmasq as a forwarder and doing validation will be expecting to
see the proof of non-existence from the parent. */
if (!auth_dns && !option_bool(OPT_LOCALISE))
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, daemon->namebuff, NULL))
{
auth_dns = 1;
local_auth = 1;
break;
}
{
char *cut;
if (in_zone(zone, daemon->namebuff, &cut))
{
if (qtype != T_DS || cut)
{
auth_dns = 1;
local_auth = 1;
}
break;
}
}
#endif
norebind = domain_no_rebind(daemon->namebuff);
@@ -2395,7 +2408,7 @@ unsigned char *tcp_request(int confd, time_t now,
#endif
else
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
dst_addr_4, netmask, now, ad_reqd, do_bit, &stale, &filtered);
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
}
}
@@ -2406,15 +2419,14 @@ unsigned char *tcp_request(int confd, time_t now,
{
struct server *master;
int start;
int cacheable, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
int no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
blockdata_retrieve(saved_question, (size_t)saved_size, header);
size = saved_size;
/* save state of "cd" flag in query */
if ((checking_disabled = header->hb4 & HB4_CD))
no_cache_dnssec = 1;
checking_disabled = header->hb4 & HB4_CD;
if (lookup_domain(daemon->namebuff, gotname, &first, &last))
flags = is_local_answer(now, first, daemon->namebuff);
else
@@ -2437,8 +2449,6 @@ 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, &cacheable);
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (master->flags & SERV_DO_DNSSEC))
{
@@ -2451,11 +2461,6 @@ unsigned char *tcp_request(int confd, time_t now,
}
#endif
/* Check if we added a pheader on forwarding - may need to
strip it from the reply. */
if (!have_pseudoheader && find_pseudoheader(header, size, NULL, NULL, NULL, NULL))
added_pheader = 1;
/* Loop round available servers until we succeed in connecting to one. */
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
ede = EDE_NETERR;
@@ -2472,7 +2477,9 @@ unsigned char *tcp_request(int confd, time_t now,
/* Clear this in case we don't call tcp_key_recurse() below */
memset(daemon->rr_status, 0, sizeof(*daemon->rr_status) * daemon->rr_status_sz);
if (!checking_disabled && (master->flags & SERV_DO_DNSSEC))
if (checking_disabled || (header->hb4 & HB4_CD))
no_cache_dnssec = 1;
else if (master->flags & SERV_DO_DNSSEC)
{
int keycount = daemon->limit[LIMIT_WORK]; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
int validatecount = daemon->limit[LIMIT_CRYPTO];
@@ -2481,12 +2488,14 @@ unsigned char *tcp_request(int confd, time_t now,
char *result, *domain = "result";
union all_addr a;
a.log.ede = ede = errflags_to_ede(status);
ede = errflags_to_ede(status);
if (STAT_ISEQUAL(status, STAT_ABANDONED))
{
result = "ABANDONED";
status = STAT_BOGUS;
if (ede == EDE_UNSET)
ede = EDE_OTHER;
}
else
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
@@ -2495,6 +2504,8 @@ unsigned char *tcp_request(int confd, time_t now,
cache_secure = 1;
else if (STAT_ISEQUAL(status, STAT_BOGUS))
{
if (ede == EDE_UNSET)
ede = EDE_DNSSEC_BOGUS;
no_cache_dnssec = 1;
bogusanswer = 1;
@@ -2502,6 +2513,7 @@ unsigned char *tcp_request(int confd, time_t now,
domain = daemon->namebuff;
}
a.log.ede = ede;
log_query(F_SECSTAT, domain, &a, result, 0);
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
@@ -2530,7 +2542,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, &peer_addr, ((unsigned char *)header) + 65536, ede);
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
/* process_reply() adds pheader itself */
have_pseudoheader = 0;
@@ -3054,7 +3066,7 @@ static struct frec *lookup_frec(char *target, int class, int rrtype, int id, int
}
/* Send query packet again, if we can. */
void resend_query()
void resend_query(void)
{
if (daemon->srv_save)
server_send(daemon->srv_save, daemon->fd_save,

View File

@@ -75,11 +75,11 @@ static char *buffer;
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
{
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
struct my_nlattr *attr = (struct my_nlattr *)((u8 *)nlh + NL_ALIGN(nlh->nlmsg_len));
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
memcpy((u8 *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
nlh->nlmsg_len += NL_ALIGN(payload_len);
}
@@ -138,8 +138,8 @@ static int new_add_to_ipset(const char *setname, const union all_addr *ipaddr, i
add_attr(nlh,
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
addrsz, ipaddr);
nested[1]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[1];
nested[0]->nla_len = (void *)buffer + NL_ALIGN(nlh->nlmsg_len) - (void *)nested[0];
nested[1]->nla_len = (u8 *)buffer + NL_ALIGN(nlh->nlmsg_len) - (u8 *)nested[1];
nested[0]->nla_len = (u8 *)buffer + NL_ALIGN(nlh->nlmsg_len) - (u8 *)nested[0];
while (retry_send(sendto(ipset_sock, buffer, nlh->nlmsg_len, 0,
(struct sockaddr *)&snl, sizeof(snl))));

View File

@@ -19,7 +19,7 @@
#ifdef HAVE_LOOP
static ssize_t loop_make_probe(u32 uid);
void loop_send_probes()
void loop_send_probes(void)
{
struct server *serv;
struct randfd_list *rfds = NULL;

View File

@@ -647,7 +647,7 @@ static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
/*
* Clean old interfaces no longer found.
*/
static void clean_interfaces()
static void clean_interfaces(void)
{
struct irec *iface;
struct irec **up = &daemon->interfaces;

View File

@@ -4161,7 +4161,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
else if (strcmp(arg, "ignore") == 0)
new->flags |= CONFIG_DISABLE;
if (new->hostname)
else if (new->hostname)
{
dhcp_config_free(new);
ret_err(_("DHCP host has multiple names"));

View File

@@ -23,7 +23,7 @@ static size_t outpacket_counter;
void end_opt6(int container)
{
void *p = daemon->outpacket.iov_base + container + 2;
uint8_t *p = (uint8_t *)daemon->outpacket.iov_base + container + 2;
u16 len = outpacket_counter - container - 4 ;
PUTSHORT(len, p);
@@ -50,11 +50,11 @@ int save_counter(int newval)
void *expand(size_t headroom)
{
void *ret;
uint8_t *ret;
if (expand_buf(&daemon->outpacket, outpacket_counter + headroom))
{
ret = daemon->outpacket.iov_base + outpacket_counter;
ret = (uint8_t *)daemon->outpacket.iov_base + outpacket_counter;
outpacket_counter += headroom;
return ret;
}
@@ -65,7 +65,7 @@ void *expand(size_t headroom)
int new_opt6(int opt)
{
int ret = outpacket_counter;
void *p;
unsigned char *p;
if ((p = expand(4)))
{
@@ -88,7 +88,7 @@ void *put_opt6(void *data, size_t len)
void put_opt6_long(unsigned int val)
{
void *p;
unsigned char *p;
if ((p = expand(4)))
PUTLONG(val, p);
@@ -96,7 +96,7 @@ void put_opt6_long(unsigned int val)
void put_opt6_short(unsigned int val)
{
void *p;
uint8_t *p;
if ((p = expand(2)))
PUTSHORT(val, p);

View File

@@ -1559,7 +1559,7 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
return daemon->max_ttl;
}
static int cache_validated(const struct crec *crecp)
static int cache_not_validated(const struct crec *crecp)
{
return (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK));
}
@@ -1567,7 +1567,7 @@ static int cache_validated(const struct crec *crecp)
/* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int ad_reqd, int do_bit, int *stale, int *filtered)
time_t now, int ad_reqd, int do_bit, int no_cache, int *stale, int *filtered)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
@@ -1582,6 +1582,10 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
size_t len;
int rd_bit = (header->hb3 & HB3_RD);
int count = 255; /* catch loops */
/* Suppress cached answers of no_cache set. */
if (no_cache)
rd_bit = 0;
if (stale)
*stale = 0;
@@ -1656,7 +1660,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
(rd_bit && (!do_bit || cache_validated(crecp))))
(rd_bit && (!do_bit || cache_not_validated(crecp))))
{
if (crecp->flags & F_CONFIG || qtype == T_CNAME)
ans = 1;
@@ -1815,7 +1819,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
the zone is unsigned, which implies that we're doing
validation. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
(rd_bit && (!do_bit || cache_validated(crecp)) ))
(rd_bit && (!do_bit || cache_not_validated(crecp)) ))
{
do
{
@@ -1971,7 +1975,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
/* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
(rd_bit && (!do_bit || cache_validated(crecp)) ))
(rd_bit && (!do_bit || cache_not_validated(crecp)) ))
do
{
int stale_flag = 0;
@@ -2153,19 +2157,19 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (!ans)
{
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) &&
rd_bit && (!do_bit || cache_validated(crecp)))
if ((crecp = cache_find_by_name(NULL, name, now, F_RR | F_NXDOMAIN)) && rd_bit)
do
{
int flags = crecp->flags;
unsigned short rrtype;
if (flags & F_KEYTAG)
rrtype = crecp->addr.rrblock.rrtype;
else
rrtype = crecp->addr.rrdata.rrtype;
if ((flags & F_NXDOMAIN) || rrtype == qtype)
if (((flags & F_NXDOMAIN) || rrtype == qtype) &&
(!do_bit || cache_not_validated(crecp)))
{
char *rrdata = NULL;
unsigned short rrlen = 0;
@@ -2228,14 +2232,15 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
if (qtype != T_ANY && !ans && rr_on_list(daemon->filter_rr, qtype))
if (qtype != T_ANY && !ans && rr_on_list(daemon->filter_rr, qtype) && !do_bit)
{
/* We don't have a cached answer and when we get an answer from upstream we're going to
filter it anyway. If we have a cached answer for the domain for another RRtype then
that may be enough to tell us if the answer should be NODATA and save the round trip.
Cached NXDOMAIN has already been handled, so here we look for any record for the domain,
since its existence allows us to return a NODATA answer. Note that we never set the AD flag,
since we didn't authenticate the record. */
since we didn't authenticate the record; this doesn't work if we want auth data, so
don't use this shortcut in that case. */
if (cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6 | F_RR | F_CNAME))
{

View File

@@ -39,8 +39,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
static void *opt6_next(void *opts, void *end);
static void *opt6_find (uint8_t *opts, uint8_t *end, unsigned int search, unsigned int minsize);
static void *opt6_next(uint8_t *opts, uint8_t *end);
static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
static void get_context_tag(struct state *state, struct dhcp_context *context);
static int check_ia(struct state *state, void *opt, void **endp, void **ia_option);
@@ -61,11 +61,11 @@ static void calculate_times(struct dhcp_context *context, unsigned int *min_time
#define opt6_len(opt) ((int)(opt6_uint(opt, -2, 2)))
#define opt6_type(opt) (opt6_uint(opt, -4, 2))
#define opt6_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[4+(i)]))
#define opt6_ptr(opt, i) ((void *)&(((uint8_t *)(opt))[4+(i)]))
#define opt6_user_vendor_ptr(opt, i) ((void *)&(((unsigned char *)(opt))[2+(i)]))
#define opt6_user_vendor_ptr(opt, i) ((void *)&(((uint8_t *)(opt))[2+(i)]))
#define opt6_user_vendor_len(opt) ((int)(opt6_uint(opt, -4, 2)))
#define opt6_user_vendor_next(opt, end) (opt6_next(((void *) opt) - 2, end))
#define opt6_user_vendor_next(opt, end) (opt6_next(((uint8_t *) opt) - 2, end))
unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *iface_name,
@@ -107,11 +107,11 @@ unsigned short dhcp6_reply(struct dhcp_context *context, int interface, char *if
static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t sz,
struct in6_addr *client_addr, int is_unicast, time_t now)
{
void *end = inbuff + sz;
void *opts = inbuff + 34;
uint8_t *end = inbuff + sz;
uint8_t *opts = inbuff + 34;
int msg_type = *inbuff;
unsigned char *outmsgtypep;
void *opt;
uint8_t *opt;
struct dhcp_vendor *vendor;
/* if not an encapsulated relayed message, just do the stuff */
@@ -232,7 +232,7 @@ static int dhcp6_maybe_relay(struct state *state, unsigned char *inbuff, size_t
for (opt = opts; opt; opt = opt6_next(opt, end))
{
if (opt6_ptr(opt, 0) + opt6_len(opt) > end)
if ((uint8_t *)opt6_ptr(opt, 0) + opt6_len(opt) > end)
return 0;
/* Don't copy MAC address into reply. */
@@ -1307,7 +1307,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, unsigned char *inbu
reallocated. */
((unsigned char *)(daemon->outpacket.iov_base))[start_msg] = outmsgtype;
log6_opts(0, state->xid, daemon->outpacket.iov_base + start_opts, daemon->outpacket.iov_base + save_counter(-1));
log6_opts(0, state->xid, (uint8_t *)daemon->outpacket.iov_base + start_opts, (uint8_t *)daemon->outpacket.iov_base + save_counter(-1));
return 1;
@@ -2093,7 +2093,7 @@ static void log6_packet(struct state *state, char *type, struct in6_addr *addr,
string ? string : "");
}
static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize)
static void *opt6_find (uint8_t *opts, uint8_t *end, unsigned int search, unsigned int minsize)
{
u16 opt, opt_len;
void *start;
@@ -2120,7 +2120,7 @@ static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int
}
}
static void *opt6_next(void *opts, void *end)
static void *opt6_next(uint8_t *opts, uint8_t *end)
{
u16 opt_len;

View File

@@ -345,9 +345,6 @@ int expand_workspace(unsigned char ***wkspc, int *szp, int new)
if (old >= new+1)
return 1;
if (new >= 100)
return 0;
new += 5;
if (!(p = whine_realloc(*wkspc, new * sizeof(unsigned char *))))

View File

@@ -41,7 +41,7 @@ static u32 in[12];
static u32 out[8];
static int outleft = 0;
void rand_init()
void rand_init(void)
{
int fd = open(RANDFILE, O_RDONLY);
@@ -767,10 +767,10 @@ int retry_send(ssize_t rc)
/* rw = 0 -> write
rw = 1 -> read
rw = 2 -> read once
rw = 3 -> write once
rw = 2 -> write once
rw = 3 -> read once
"once" fail if all the data doesn't arrive/go in a single read/write.
"once" fails on EAGAIN, as this a timeout.
This indicates a timeout of a TCP socket.
*/
int read_write(int fd, unsigned char *packet, int size, int rw)
@@ -779,29 +779,34 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
for (done = 0; done < size; done += n)
{
do {
if (rw & 1)
n = read(fd, &packet[done], (size_t)(size - done));
else
n = write(fd, &packet[done], (size_t)(size - done));
if (n == 0)
return 0;
if (n == -1 && errno == EINTR)
continue;
/* "once" variant */
if ((rw & 2) && n != size)
return 0;
} while (n == -1 && (errno == EINTR || errno == ENOMEM || errno == ENOBUFS ||
errno == EAGAIN || errno == EWOULDBLOCK));
if (rw & 1)
n = read(fd, &packet[done], (size_t)(size - done));
else
n = write(fd, &packet[done], (size_t)(size - done));
if (n == -1)
if (n == 0)
return 0;
if (n == -1)
{
n = 0; /* don't mess with counter when we loop. */
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
continue;
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
/* "once" variant */
if (rw & 2)
return 0;
continue;
}
return 0;
}
}
return 1;
}