mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-04 13:48:30 +00:00
Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2ba5b07a | ||
|
|
729c16a8ac | ||
|
|
80acb76f46 | ||
|
|
f1fa05d754 | ||
|
|
b148ba4752 | ||
|
|
81f619612e | ||
|
|
cb321709e9 | ||
|
|
8eb36844a0 | ||
|
|
8fa68a6e1e | ||
|
|
1269f074f8 | ||
|
|
e1faf705c9 | ||
|
|
f603a4f920 | ||
|
|
c090f1d17b | ||
|
|
fa48bdb939 | ||
|
|
d8f66f4fda | ||
|
|
629107bd6d | ||
|
|
05464a173b | ||
|
|
ae3d3d971e | ||
|
|
d1845782d6 | ||
|
|
edb5f85fd1 | ||
|
|
052aa0fcf3 |
No files matched your search
@@ -1,3 +1,30 @@
|
||||
version 2.93
|
||||
Fix a corner-case in DNSSEC validation with wildcards. If we have
|
||||
a wildcard record *.example.com and recieve a query for
|
||||
a.example.com then that's OK, but we have to check that there isn't
|
||||
an actual a.example.com record. The corner case is when we get a
|
||||
query for *.example.com in that case the non-existence check
|
||||
is not required, was being done. Thanks to Jan Breig for
|
||||
spotting this.
|
||||
|
||||
Enable support for inotify on FreeBSD 15.0-RELEASE, which added
|
||||
Linux-compatible inotify support.
|
||||
|
||||
Fix DNSSEC failure with spurious RRSIGs. The presence of wrong
|
||||
RRSIG RRs in replies caused DNSSEC validation to fail even
|
||||
when the RRs do not require validation because the zone is
|
||||
unsigned. Note that, at the time of this commit, Google
|
||||
DNS appears to have the same bug, so if you're using 8.8.8.8
|
||||
or friends as upstream, resolving the broken zones
|
||||
(eg rivcoed.org) will still fail. Thanks to Petr Menšík
|
||||
for the bug report.
|
||||
|
||||
Fix DNSSEC fail with CNAME replies to DS queries. As CNAME reply
|
||||
to a DNSSEC query was confusing the validation logic. It now
|
||||
accepts a signed CNAME reply to a DS query as proof that no DS
|
||||
exists at the domain. This fixes the DS/zone break detection logic.
|
||||
|
||||
|
||||
version 2.92
|
||||
Redesign the interaction between DNSSEC validation and per-domain
|
||||
servers, specified as --server=/<domain>/<ip-address>. This should
|
||||
@@ -24,7 +51,7 @@ version 2.92
|
||||
|
||||
Fix some edge-cases with domains and --address and --server. There
|
||||
has been some regressions with this in previous releases. This change
|
||||
fixes the priority order from loqwer to highest as:
|
||||
fixes the priority order from lower to highest as:
|
||||
--address with a IPv4 or IPv6 address (as long as the query matches the type)
|
||||
--address with # for all-zeros, as long as the query is A or AAAA)
|
||||
--address with no address, which returns NXDOMAIN or NOERROR for all types.
|
||||
@@ -61,7 +88,7 @@ version 2.92
|
||||
|
||||
Add TFTP options windowsize (RFC 7440) and timeout (RFC 2349).
|
||||
|
||||
Change the behaviour of the DHVPv6 server when a REBIND message
|
||||
Change the behaviour of the DHCPv6 server when a REBIND message
|
||||
is received but no lease exists. Under these circumstances a new
|
||||
lease is created _only_ when the --dhcp-authoritative option is
|
||||
set. This matches the behavior of the DHCPv4 server.
|
||||
|
||||
+11
-11
@@ -27,8 +27,8 @@
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
@@ -193,11 +193,11 @@
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
@@ -220,9 +220,9 @@
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
@@ -295,11 +295,11 @@
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
@@ -355,7 +355,7 @@
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
@@ -560,7 +560,7 @@
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
+10
-8
@@ -136,6 +136,8 @@ Log the results of DNS queries handled by dnsmasq. Enable a full cache dump on r
|
||||
then the log has extra information at the start of each line.
|
||||
This consists of a serial number which ties together the log lines associated with an individual query, and the IP address of the requestor. If the argument "proto" is supplied, this shows everything that "extra" does and also the network protocol used to communicate the queries. Logging of only queries to the authoritative server can be configured with
|
||||
.B --log-queries=auth
|
||||
and logging only failed replies (Error, NXDOMAIN or NODATA) can be configured with
|
||||
.B --log-queries=only_failed
|
||||
.TP
|
||||
.B \-8, --log-facility=<facility>
|
||||
Set the facility to which dnsmasq will send syslog entries, this
|
||||
@@ -918,7 +920,7 @@ fast.
|
||||
|
||||
Versions of dnsmasq prior to 2.80 defaulted to not checking unsigned replies, and used
|
||||
.B --dnssec-check-unsigned
|
||||
to switch this on. Such configurations will continue to work as before, but those which used the default of no checking will need to be altered to explicitly select no checking. The new default is because switching off checking for unsigned replies is inherently dangerous. Not only does it open the possiblity of forged replies, but it allows everything to appear to be working even when the upstream namesevers do not support DNSSEC, and in this case no DNSSEC validation at all is occurring.
|
||||
to switch this on. Such configurations will continue to work as before, but those which used the default of no checking will need to be altered to explicitly select no checking. The new default is because switching off checking for unsigned replies is inherently dangerous. Not only does it open the possibility of forged replies, but it allows everything to appear to be working even when the upstream namesevers do not support DNSSEC, and in this case no DNSSEC validation at all is occurring.
|
||||
.TP
|
||||
.B --dnssec-no-timecheck
|
||||
DNSSEC signatures are only valid for specified time windows, and should be rejected outside those windows. This generates an
|
||||
@@ -1197,7 +1199,7 @@ the appropriate network part inserted. For IPv6, an address may include a prefix
|
||||
which (in this case) specifies four addresses, 1234::50 to 1234::53. This (an the ability
|
||||
to specify multiple addresses) is useful
|
||||
when a host presents either a consistent name or hardware-ID, but varying DUIDs, since it allows
|
||||
dnsmasq to honour the static address allocation but assign a different adddress for each DUID. This
|
||||
dnsmasq to honour the static address allocation but assign a different address for each DUID. This
|
||||
typically occurs when chain netbooting, as each stage of the chain gets in turn allocates an address.
|
||||
|
||||
Note that in IPv6 DHCP, the hardware address may not be
|
||||
@@ -1347,7 +1349,7 @@ The special address 0.0.0.0 means "the address of the system running dnsmasq".
|
||||
|
||||
An option without data is valid, and includes just the option without data.
|
||||
(There is only one option with a zero length data field currently defined for DHCPv4, 80:rapid commit, so this feature is not very useful in practice). Options for which dnsmasq normally
|
||||
provides default values can be ommitted by defining the option with no data. These are
|
||||
provides default values can be omitted by defining the option with no data. These are
|
||||
netmask, broadcast, router, DNS server, domainname and hostname. Thus, for DHCPv4
|
||||
.B --dhcp-option = option:router
|
||||
will result in no router option being sent, rather than the default of the host on which dnsmasq is running. For DHCPv6, the same is true of the options DNS server and refresh time.
|
||||
@@ -1490,7 +1492,7 @@ prefix-delegation from relayed DHCP transactions. See
|
||||
for details.
|
||||
.TP
|
||||
.B --dhcp-split-relay=<local address>,[<server address>[#<server port>]],<server-facing-interface>|<server-facing-address>
|
||||
A usefully enchanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||
A usefully enhanced version of DHCPv4 relay. IPv4 DHCP normally uses a single address
|
||||
for two functions; it is used by the DHCP server to determine which network to allocate
|
||||
an address on, and it is used as the address of the relay to which the server sends packets.
|
||||
|
||||
@@ -1501,7 +1503,7 @@ local address is also used as server-ID override so that the client always sends
|
||||
via the relay. The effect of this is that server doesn't require
|
||||
a route to the client network and the clients don't require a route to the server.
|
||||
|
||||
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as descibed in
|
||||
The third parameter is mandatory. If it is an interface name it cannot be a wildcard and the same filtering as described in
|
||||
--dhcp-relay applies; answers from the server must arrve via the specified interface. If the third parameter
|
||||
is an IP address it must be an address of a local interface which is routable from the server; In this case no filtering
|
||||
is done, the reply packets can arrive via any route.
|
||||
@@ -1672,7 +1674,7 @@ likely to move IP address; for this reason it should not be generally used.
|
||||
.TP
|
||||
.B --dhcp-ignore-clid
|
||||
Dnsmasq is reading 'client identifier' (RFC 2131) option sent by clients
|
||||
(if available) to identify clients. This allow to serve same IP address
|
||||
(if available) to identify clients. This allow one to serve same IP address
|
||||
for a host using several interfaces. Use this option to disable 'client identifier'
|
||||
reading, i.e. to always identify a host using the MAC address.
|
||||
.TP
|
||||
@@ -1953,7 +1955,7 @@ 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)
|
||||
are the name of the interface where the client is connected, 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
|
||||
@@ -2304,7 +2306,7 @@ therein is updated when dnsmasq receives SIGHUP.
|
||||
.B \--conf-script=<file>[ <arg]
|
||||
Execute <file>, and treat what it emits to stdout as the contents of a configuration file.
|
||||
If the script exits with a non-zero exit code, dnsmasq treats this as a fatal error.
|
||||
The script can be passed arguments, space seperated from the filename and each other so, for instance
|
||||
The script can be passed arguments, space separated from the filename and each other so, for instance
|
||||
.B --conf-dir="/etc/dnsmasq-uncompress-ads /share/ads-domains.gz"
|
||||
|
||||
with /etc/dnsmasq-uncompress-ads containing
|
||||
|
||||
+4
-4
@@ -4,7 +4,7 @@ dnsmasq \- En lättviktig DHCP- och caching-DNS-server.
|
||||
.SH SYNOPSIS
|
||||
.B dnsmasq
|
||||
.I [OPTION]...
|
||||
.SH ”BESKRIVNING”
|
||||
.SH BESKRIVNING
|
||||
.BR dnsmasq
|
||||
är en lättviktig DNS-, TFTP-, PXE-, routerannonserings- och DHCP-server. Den är avsedd att tillhandahålla
|
||||
kopplade DNS- och DHCP-tjänster till ett LAN.
|
||||
@@ -864,8 +864,8 @@ de tas emot från uppströms.
|
||||
Dnsmasq kan kryptera bokstäverna i DNS-frågor som skickas uppströms som en säkerhetsfunktion.
|
||||
Denna teknik kan interagera dåligt med sällsynta trasiga DNS-servrar som inte bevarar bokstäverna
|
||||
i frågan i sitt svar. Första gången ett svar returneras
|
||||
som matchar frågan i alla avseenden utom bokstäverna, loggas en varning
|
||||
. Om detta sammanfaller med att DNS inte fungerar, är det
|
||||
som matchar frågan i alla avseenden utom bokstäverna, loggas en varning.
|
||||
Om detta sammanfaller med att DNS inte fungerar, är det
|
||||
nödvändigt att inaktivera funktionen. I version 2.91 är 0x20-kodning
|
||||
inaktiverad som standard och måste aktiveras med --do-0x20-encode. Standardinställningen
|
||||
kan komma att ändras i framtiden, så för att vara säker på dess status efter en uppgradering, ställ in --do-0x20-encode
|
||||
@@ -2843,7 +2843,7 @@ dnsmasq inte har något direkt sätt att bestämma vilken teckenuppsättning som
|
||||
anta att det är systemets standard.
|
||||
|
||||
|
||||
.SH-FILER
|
||||
.SH FILER
|
||||
.IR /etc/dnsmasq.conf
|
||||
|
||||
.IR /usr/local/etc/dnsmasq.conf
|
||||
|
||||
@@ -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 - 2024.
|
||||
# Conrad Kostecki <conrad@kostecki.com>, 2014 - 2025.
|
||||
# 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.91\n"
|
||||
"Project-Id-Version: dnsmasq 2.92\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-03-20 00:00+0000\n"
|
||||
"PO-Revision-Date: 2024-12-23 22:36+0100\n"
|
||||
"PO-Revision-Date: 2025-12-06 16:24+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.5\n"
|
||||
"X-Generator: Poedit 3.8\n"
|
||||
|
||||
#: cache.c:696
|
||||
msgid "Internal error in cache."
|
||||
@@ -94,22 +94,22 @@ msgstr "Anfragen nach autoritativen Zonen %u"
|
||||
#: cache.c:2078
|
||||
#, c-format
|
||||
msgid "DNSSEC per-query subqueries HWM %u"
|
||||
msgstr ""
|
||||
msgstr "DNSSEC-Unterabfragen pro Anfrage HWM %u"
|
||||
|
||||
#: cache.c:2079
|
||||
#, c-format
|
||||
msgid "DNSSEC per-query crypto work HWM %u"
|
||||
msgstr ""
|
||||
msgstr "DNSSEC-Kryptografie pro Anfrage HWM %u"
|
||||
|
||||
#: cache.c:2080
|
||||
#, c-format
|
||||
msgid "DNSSEC per-RRSet signature fails HWM %u"
|
||||
msgstr ""
|
||||
msgstr "DNSSEC-Signatur pro RRSet fehlgeschlagen HWM %u"
|
||||
|
||||
#: cache.c:2084
|
||||
#, c-format
|
||||
msgid "child processes for TCP requests: in use %zu, highest since last SIGUSR1 %zu, max allowed %zu."
|
||||
msgstr ""
|
||||
msgstr "Kindprozesse für TCP-Anfragen: aktuell in Gebrauch %zu, höchster Wert seit letztem SIGUSR1 %zu, maximal erlaubt %zu."
|
||||
|
||||
#: cache.c:2113
|
||||
#, c-format
|
||||
@@ -215,9 +215,8 @@ msgid "Don't include IPv6 addresses in DNS answers."
|
||||
msgstr "Keine IPv6-Adressen in DNS-Antworten inkludieren."
|
||||
|
||||
#: option.c:430
|
||||
#, fuzzy
|
||||
msgid "Don't include resource records of the given type in DNS answers."
|
||||
msgstr "Keine IPv4-Adressen in DNS-Antworten inkludieren."
|
||||
msgstr "Resource Records des angegebenen Typs nicht in DNS-Antworten einfügen."
|
||||
|
||||
#: option.c:431
|
||||
msgid "Enable DHCP in the range given with lease duration."
|
||||
@@ -354,9 +353,8 @@ msgid "DHCP option sent even if the client does not request it."
|
||||
msgstr "DHCP-Option, die selbst ohne Klientenanfrage gesendet wird."
|
||||
|
||||
#: option.c:463
|
||||
#, fuzzy
|
||||
msgid "DHCP option sent only to PXE clients."
|
||||
msgstr "Aufforderung, die an PXE-Klienten geschickt wird."
|
||||
msgstr "DHCP-Option wird nur an PXE-Clients gesendet."
|
||||
|
||||
#: option.c:464
|
||||
msgid "Specify port to listen for DNS requests on (defaults to 53)."
|
||||
@@ -509,14 +507,12 @@ msgid "Do not provide DHCP on this interface, only provide DNS."
|
||||
msgstr "Auf dieser Schnittstelle kein DHCP anbieten, sondern nur DNS."
|
||||
|
||||
#: option.c:500
|
||||
#, fuzzy
|
||||
msgid "Do not provide DHCPv6 on this interface."
|
||||
msgstr "Auf dieser Schnittstelle kein DHCP anbieten, sondern nur DNS."
|
||||
msgstr "DHCPv6 auf dieser Schnittstelle nicht bereitstellen."
|
||||
|
||||
#: option.c:501
|
||||
#, fuzzy
|
||||
msgid "Do not provide DHCPv4 on this interface."
|
||||
msgstr "Auf dieser Schnittstelle kein DHCP anbieten, sondern nur DNS."
|
||||
msgstr "DHCPv4 auf dieser Schnittstelle nicht bereitstellen."
|
||||
|
||||
#: option.c:502
|
||||
msgid "Enable dynamic address allocation for bootp."
|
||||
@@ -536,7 +532,7 @@ msgstr "Geben Sie zusätzliche Netzwerke an, die eine Broadcast-Domäne für DHC
|
||||
|
||||
#: option.c:506
|
||||
msgid "Enable RFC 4388 leasequery functions for DHCPv4"
|
||||
msgstr ""
|
||||
msgstr "RFC-4388-Leasequery-Funktionen für DHCPv4 aktivieren"
|
||||
|
||||
#: option.c:507
|
||||
msgid "Disable ICMP echo address checking in the DHCP server."
|
||||
@@ -858,9 +854,8 @@ msgid "Timestamp file to verify system clock for DNSSEC"
|
||||
msgstr "Zeitstempel-Datei für die Verifizierung der Systemuhrzeit für DNSSEC"
|
||||
|
||||
#: option.c:586
|
||||
#, fuzzy
|
||||
msgid "Set resource limits for DNSSEC validation"
|
||||
msgstr "Aktiviere DNSSEC-Validierung"
|
||||
msgstr "Ressourcenlimits für die DNSSEC-Validierung festlegen"
|
||||
|
||||
#: option.c:587
|
||||
msgid "Set MTU, priority, resend-interval and router-lifetime"
|
||||
@@ -907,14 +902,12 @@ msgid "Enables DHCPv4 Rapid Commit option."
|
||||
msgstr "Aktiviert die DHCPv4-\"Rapid Commit\"-Option."
|
||||
|
||||
#: option.c:598
|
||||
#, fuzzy
|
||||
msgid "Path to debug packet dump file."
|
||||
msgstr "Pfad zur Paketablagedatei zur Fehlersuche"
|
||||
msgstr "Pfad zur Dump-Datei für das Debug-Paket."
|
||||
|
||||
#: option.c:599
|
||||
#, fuzzy
|
||||
msgid "Mask which packets to dump."
|
||||
msgstr "Maskiere Pakete, welche abgelegt werden sollen"
|
||||
msgstr "Maskiere, welche Pakete protokolliert werden sollen."
|
||||
|
||||
#: option.c:600
|
||||
msgid "Call dhcp-script when lease expiry changes."
|
||||
@@ -934,26 +927,23 @@ msgstr "Unterdrückt die Round-Robin-Sortierung von DNS-Einträgen."
|
||||
|
||||
#: option.c:604
|
||||
msgid "Suppress DNS bit 0x20 encoding."
|
||||
msgstr ""
|
||||
msgstr "DNS-Bit-0x20-Codierung unterdrücken."
|
||||
|
||||
#: option.c:605
|
||||
msgid "Enable DNS bit 0x20 encoding."
|
||||
msgstr ""
|
||||
msgstr "DNS-Bit-0x20-Codierung aktivieren."
|
||||
|
||||
#: option.c:606
|
||||
#, fuzzy
|
||||
msgid "Do not add CHAOS TXT records."
|
||||
msgstr "fehlerhafter TXT-Eintrag"
|
||||
msgstr "Keine CHAOS-TXT-Einträge hinzufügen."
|
||||
|
||||
#: option.c:607
|
||||
#, fuzzy
|
||||
msgid "Cache this DNS resource record type."
|
||||
msgstr "Spezifiziere einen beliebiegen DNS Eintrag"
|
||||
msgstr "Diesen DNS-Resource-Record-Typ cachen."
|
||||
|
||||
#: option.c:608
|
||||
#, fuzzy
|
||||
msgid "Maximum number of concurrent tcp connections."
|
||||
msgstr "Maximale Anzahl gleichzeitiger TFTP-Übertragungen (%s voreingestellt)."
|
||||
msgstr "Maximale Anzahl gleichzeitiger TCP-Verbindungen."
|
||||
|
||||
#: option.c:838
|
||||
#, c-format
|
||||
@@ -1056,7 +1046,7 @@ msgstr "DHCP-Option zu lang"
|
||||
|
||||
#: option.c:1961
|
||||
msgid "No vendor-encap options allowed in dhcp-option-pxe"
|
||||
msgstr ""
|
||||
msgstr "Keine vendor-encap-Optionen in dhcp-option-pxe erlaubt"
|
||||
|
||||
#: option.c:1968
|
||||
msgid "illegal dhcp-match"
|
||||
@@ -1141,9 +1131,8 @@ msgid "recompile with HAVE_CONNTRACK defined to enable connmark-allowlist direct
|
||||
msgstr "Neukompilierung mit HAVE_CONNTRACK notwendig, um connmark-allowlist-Direktiven zu aktivieren"
|
||||
|
||||
#: option.c:3585
|
||||
#, fuzzy
|
||||
msgid "bad RR type"
|
||||
msgstr "fehlerhafter RR-Eintrag"
|
||||
msgstr "Ungültiger RR-Typ"
|
||||
|
||||
#: option.c:3644
|
||||
msgid "bad port range"
|
||||
@@ -1203,9 +1192,8 @@ msgid "duplicate dhcp-host IP address %s"
|
||||
msgstr "doppelte dhcp-host IP-Adresse %s"
|
||||
|
||||
#: option.c:4201
|
||||
#, fuzzy
|
||||
msgid "DHCP host has multiple names"
|
||||
msgstr "fehlerhafter DHCP-Hostname"
|
||||
msgstr "DHCP-Host hat mehrere Namen"
|
||||
|
||||
#: option.c:4209
|
||||
msgid "bad DHCP host name"
|
||||
@@ -1452,7 +1440,7 @@ msgstr "keine \"search\"-Anweisung in %s gefunden"
|
||||
#: option.c:6284
|
||||
#, c-format
|
||||
msgid "srv-host name %s too long after domain appended"
|
||||
msgstr ""
|
||||
msgstr "srv-Hostname %s nach Anfügen der Domain zu lang"
|
||||
|
||||
#: option.c:6293
|
||||
msgid "there must be a default domain when --dhcp-fqdn is set"
|
||||
@@ -1483,12 +1471,12 @@ msgstr "möglichen DNS-Rebind-Angriff entdeckt: %s"
|
||||
|
||||
#: forward.c:1013 forward.c:2280
|
||||
msgid "limit exceeded: per-query subqueries"
|
||||
msgstr ""
|
||||
msgstr "Limit überschritten: Unterabfragen pro Anfrage"
|
||||
|
||||
#: forward.c:1103 forward.c:2288
|
||||
#, c-format
|
||||
msgid "validation of %s failed: resource limit exceeded."
|
||||
msgstr ""
|
||||
msgstr "Validierung von %s fehlgeschlagen: Ressourcenlimit überschritten."
|
||||
|
||||
#: forward.c:1697
|
||||
#, c-format
|
||||
@@ -1496,9 +1484,9 @@ msgid "ignoring query from non-local network %s (logged only once)"
|
||||
msgstr "Ignoriere Abfrage von nicht-lokalen Netzwerk %s (Nur einmal protokolliert)"
|
||||
|
||||
#: forward.c:2120
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "TCP connection failed to %s#%d"
|
||||
msgstr "Einspeisen in ARP-Zwischenspeicher fehlgeschlagen: %s"
|
||||
msgstr "TCP-Verbindung zu %s#%d fehlgeschlagen"
|
||||
|
||||
#: forward.c:2426
|
||||
#, c-format
|
||||
@@ -1522,7 +1510,7 @@ msgstr "Maximale Anzahl gleichzeitiger DNS-Abfragen, die erreicht %s (max. %d)"
|
||||
|
||||
#: forward.c:3243
|
||||
msgid "Case mismatch in DNS reply - check bit 0x20 encoding."
|
||||
msgstr ""
|
||||
msgstr "Groß-/Kleinschreibung stimmt in der DNS-Antwort nicht überein – Bit-0x20-Codierung überprüfen."
|
||||
|
||||
#: network.c:705
|
||||
#, c-format
|
||||
@@ -1797,9 +1785,8 @@ msgid "DNS service limited to local subnets"
|
||||
msgstr "DNS-Dienst auf Unternetze eingeschränkt"
|
||||
|
||||
#: dnsmasq.c:882
|
||||
#, fuzzy
|
||||
msgid "DNS service limited to localhost"
|
||||
msgstr "DNS-Dienst auf Unternetze eingeschränkt"
|
||||
msgstr "DNS-Dienst auf localhost beschränkt"
|
||||
|
||||
#: dnsmasq.c:885
|
||||
#, c-format
|
||||
@@ -1839,9 +1826,9 @@ msgid "DNSSEC signature timestamps not checked until system time valid"
|
||||
msgstr "DNSSEC Signatur-Zeitstempel werden erst überprüft, sobald die Systemuhrzeit gültig ist"
|
||||
|
||||
#: dnsmasq.c:946
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "configured with negative trust anchor for %s"
|
||||
msgstr "konfiguriert mit Vertrauensanker für %s Schlüsselanhänger %u"
|
||||
msgstr "Mit negativem Vertrauensanker für %s konfiguriert"
|
||||
|
||||
#: dnsmasq.c:946
|
||||
#, c-format
|
||||
@@ -1867,9 +1854,8 @@ msgid "warning: ignoring resolv-file flag because no-resolv is set"
|
||||
msgstr "Warnung: Ignoriere \"resolv-file\", weil \"no-resolv\" aktiv ist"
|
||||
|
||||
#: dnsmasq.c:981
|
||||
#, fuzzy
|
||||
msgid "no upstream servers configured - please set them from DBus"
|
||||
msgstr "Warnung: keine vorgeschalteten Server konfiguriert"
|
||||
msgstr "Keine Upstream-Server konfiguriert – bitte über DBus festlegen"
|
||||
|
||||
#: dnsmasq.c:984
|
||||
msgid "warning: no upstream servers configured"
|
||||
@@ -1987,7 +1973,7 @@ msgstr "Kann keine Zeitstempel-Datei %s erzeugen: %s"
|
||||
#: dnsmasq.c:1576
|
||||
#, c-format
|
||||
msgid "TCP helper process %u died unexpectedly"
|
||||
msgstr ""
|
||||
msgstr "TCP-Hilfsprozess %u ist unerwartet abgestürzt"
|
||||
|
||||
#: dnsmasq.c:1592
|
||||
#, c-format
|
||||
@@ -2085,7 +2071,7 @@ msgstr "DHCP-Bereich %s - %s passt nicht zur Netzmaske %s"
|
||||
#: dhcp.c:680 dhcp6.c:467
|
||||
#, c-format
|
||||
msgid "DHCP relay address %s appears on more than one interface"
|
||||
msgstr ""
|
||||
msgstr "DHCP-Relay-Adresse %s erscheint auf mehr als einer Schnittstelle"
|
||||
|
||||
#: dhcp.c:978
|
||||
#, c-format
|
||||
@@ -2117,9 +2103,8 @@ msgid "too many stored leases"
|
||||
msgstr "zu viele Leases gespeichert"
|
||||
|
||||
#: lease.c:183
|
||||
#, fuzzy
|
||||
msgid "lease-change script name is too long"
|
||||
msgstr "Lease-Änderungs-Skript mit den Rechten dieses Nutzers ausführen."
|
||||
msgstr "Der Name des Lease-Change-Skripts ist zu lang"
|
||||
|
||||
#: lease.c:203
|
||||
#, c-format
|
||||
@@ -2232,7 +2217,7 @@ msgstr "PXE BIS nicht unterstützt"
|
||||
#: rfc2131.c:1088
|
||||
#, c-format
|
||||
msgid "leasequery from %s not permitted"
|
||||
msgstr ""
|
||||
msgstr "Leasequery von %s nicht erlaubt"
|
||||
|
||||
#: rfc2131.c:1259 rfc3315.c:1248
|
||||
#, c-format
|
||||
@@ -2338,14 +2323,14 @@ msgid "%u reply delay: %d"
|
||||
msgstr "%u Antwortverzögerung: %d"
|
||||
|
||||
#: rfc2131.c:3118
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "Cannot send to server via interface %s: %s"
|
||||
msgstr "DHCP-Relay kann nicht über die Schnittstelle %s gesendet werden"
|
||||
msgstr "Kann nicht über Schnittstelle %s an Server senden: %s"
|
||||
|
||||
#: rfc2131.c:3189
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "Cannot broadcast DHCP relay via interface %s: %s"
|
||||
msgstr "DHCP-Relay kann nicht über die Schnittstelle %s gesendet werden"
|
||||
msgstr "Kann DHCP-Relay nicht über Schnittstelle %s senden: %s"
|
||||
|
||||
#: rfc2131.c:3213
|
||||
#, c-format
|
||||
@@ -2413,14 +2398,14 @@ msgid "unable to get free port for TFTP"
|
||||
msgstr "konnte keinen freien Port für TFTP bekommen"
|
||||
|
||||
#: tftp.c:367
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "unsupported write request from %s"
|
||||
msgstr "nicht unterstützte Anfrage von %s"
|
||||
msgstr "Nicht unterstützte Schreibanfrage von %s"
|
||||
|
||||
#: tftp.c:371
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "empty filename in request from %s"
|
||||
msgstr "nicht unterstützte Anfrage von %s"
|
||||
msgstr "Leerer Dateiname in Anfrage von %s"
|
||||
|
||||
#: tftp.c:373
|
||||
#, c-format
|
||||
@@ -2438,9 +2423,9 @@ msgid "ignoring packet from %s (TID mismatch)"
|
||||
msgstr "Paket von %s wird ignoriert (TID-Nichtübereinstimmung)"
|
||||
|
||||
#: tftp.c:730
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "timeout sending %s to %s"
|
||||
msgstr "konnte %s nicht an %s senden"
|
||||
msgstr "Zeitüberschreitung beim Senden von %s an %s"
|
||||
|
||||
#: tftp.c:732
|
||||
#, c-format
|
||||
@@ -2494,7 +2479,7 @@ msgstr "Kann nicht an DHCPv6-Server-Socket binden: %s"
|
||||
#: dhcp6.c:152
|
||||
#, c-format
|
||||
msgid "Working around kernel bug: faulty source address scope for VRF slave %s"
|
||||
msgstr ""
|
||||
msgstr "Umgehung eines Kernel-Fehlers: fehlerhafter Quelladressbereich für VRF-Slave %s"
|
||||
|
||||
#: rfc3315.c:174
|
||||
#, c-format
|
||||
@@ -2522,9 +2507,9 @@ msgid "%u client MAC address: %s"
|
||||
msgstr "%u Klient MAC-Adresse: %s"
|
||||
|
||||
#: rfc3315.c:487
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "%u cannot determine client MAC address"
|
||||
msgstr "%u Klient MAC-Adresse: %s"
|
||||
msgstr "%u kann die MAC-Adresse des Clients nicht bestimmen"
|
||||
|
||||
#: rfc3315.c:783 rfc3315.c:880
|
||||
msgid "address unavailable"
|
||||
@@ -2651,9 +2636,9 @@ msgid "DHCP relay from %s via %s"
|
||||
msgstr "DHCP-Relay von %s über %s"
|
||||
|
||||
#: dhcp-common.c:1071
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "DHCP split-relay from %s to %s via %s"
|
||||
msgstr "DHCP Weiterleitung von %s nach %s über %s"
|
||||
msgstr "DHCP-Split-Relay von %s nach %s über %s"
|
||||
|
||||
#: dhcp-common.c:1073
|
||||
#, c-format
|
||||
@@ -2784,21 +2769,21 @@ msgstr "Systemzeit als gültig betrachtet, prüfe jetzt DNSSEC Signatur-Zeitstem
|
||||
|
||||
#: dnssec.c:431
|
||||
msgid "per-query crypto work"
|
||||
msgstr ""
|
||||
msgstr "Kryptografische Arbeit pro Anfrage"
|
||||
|
||||
#: dnssec.c:697
|
||||
msgid "per-RRSet signature fails"
|
||||
msgstr ""
|
||||
msgstr "Signatur pro RRSet fehlgeschlagen"
|
||||
|
||||
#: dnssec.c:1027
|
||||
#, c-format
|
||||
msgid "Insecure reply received for DS %s, assuming that's OK for a RFC-1918 address."
|
||||
msgstr ""
|
||||
msgstr "Unsichere Antwort für DS %s empfangen, Annahme, dass dies für eine RFC-1918-Adresse in Ordnung ist."
|
||||
|
||||
#: dnssec.c:1034
|
||||
#, c-format
|
||||
msgid "Insecure reply received for DS %s, assuming non-DNSSEC domain-specific server."
|
||||
msgstr ""
|
||||
msgstr "Unsichere Antwort für DS %s empfangen, Annahme eines nicht-DNSSEC-domänenspezifischen Servers."
|
||||
|
||||
#: dnssec.c:1041
|
||||
#, c-format
|
||||
@@ -2808,7 +2793,7 @@ msgstr "Unsichere DS-Antwort für %s, bitte Domainkonfiguration und Upstream DNS
|
||||
#: dnssec.c:1152
|
||||
#, c-format
|
||||
msgid "Negative DS reply without NS record received for %s, assuming non-DNSSEC domain-specific server."
|
||||
msgstr ""
|
||||
msgstr "Negative DS-Antwort ohne NS-Eintrag für %s empfangen, Annahme eines nicht-DNSSEC-domänenspezifischen Servers."
|
||||
|
||||
#: blockdata.c:55
|
||||
#, c-format
|
||||
@@ -2909,9 +2894,9 @@ msgid "cannot create %s: %s"
|
||||
msgstr "kann %s nicht erstellen: %s"
|
||||
|
||||
#: dump.c:76
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "cannot open pipe %s: %s"
|
||||
msgstr "Kann Logdatei %s nicht öffnen: %s"
|
||||
msgstr "Kann Pipe %s nicht öffnen: %s"
|
||||
|
||||
#: dump.c:82
|
||||
#, c-format
|
||||
|
||||
+5
-1
@@ -202,11 +202,15 @@ void *blockdata_retrieve(struct blockdata *block, size_t len, void *data)
|
||||
{
|
||||
if (len > buff_len)
|
||||
{
|
||||
if (!(new = whine_malloc(len)))
|
||||
blen = len + 1024;
|
||||
if (!(new = whine_malloc(blen)))
|
||||
return NULL;
|
||||
|
||||
if (buff)
|
||||
free(buff);
|
||||
|
||||
buff = new;
|
||||
buff_len = blen;
|
||||
}
|
||||
data = buff;
|
||||
}
|
||||
|
||||
+29
-9
@@ -855,7 +855,7 @@ void cache_end_insert(void)
|
||||
#ifdef HAVE_DNSSEC
|
||||
void cache_update_hwm(void)
|
||||
{
|
||||
/* Sneak out possibly updated crypto HWM values. */
|
||||
/* Sneak out possibly updated crypto HWM values. */
|
||||
unsigned char op = PIPE_OP_STATS;
|
||||
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
@@ -1000,6 +1000,7 @@ int cache_recv_insert(time_t now, int fd)
|
||||
}
|
||||
|
||||
case PIPE_OP_RESULT:
|
||||
case PIPE_OP_KILLED:
|
||||
{
|
||||
/* UDP validation moved to TCP to avoid truncation.
|
||||
Restart UDP validation process with the returned result. */
|
||||
@@ -1013,11 +1014,14 @@ int cache_recv_insert(time_t now, int fd)
|
||||
!read_write(fd, (unsigned char *)&ret_len, sizeof(ret_len), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)daemon->packet, ret_len, RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&forward, sizeof(forward), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ))
|
||||
!read_write(fd, (unsigned char *)&uid, sizeof(uid), RW_READ))
|
||||
return 0;
|
||||
|
||||
if (op == PIPE_OP_RESULT &&
|
||||
(!read_write(fd, (unsigned char *)&keycount, sizeof(keycount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&keycountp, sizeof(keycountp), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecount, sizeof(validatecount), RW_READ) ||
|
||||
!read_write(fd, (unsigned char *)&validatecountp, sizeof(validatecountp), RW_READ)))
|
||||
return 0;
|
||||
|
||||
/* There's a tiny chance that the frec may have been freed
|
||||
@@ -1025,9 +1029,12 @@ int cache_recv_insert(time_t now, int fd)
|
||||
the uid field which is unique modulo 2^32 for each use. */
|
||||
if (uid == forward->uid)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*validatecountp = validatecount;
|
||||
if (op == PIPE_OP_RESULT)
|
||||
{
|
||||
/* repatriate the work counters from the child process. */
|
||||
*keycountp = keycount;
|
||||
*validatecountp = validatecount;
|
||||
}
|
||||
|
||||
if (!forward->dependent)
|
||||
return_reply(now, forward, (struct dns_header *)daemon->packet, ret_len, status);
|
||||
@@ -2243,10 +2250,20 @@ static char *edestr(int ede)
|
||||
case EDE_UNS_NS3_ITER: return "unsupported NSEC3 iterations value";
|
||||
case EDE_UNABLE_POLICY: return "uanble to conform to policy";
|
||||
case EDE_SYNTHESIZED: return "synthesized";
|
||||
case EDE_US_SERVFAIL: return "upstream returned SERVFAIL";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static int error_occured(unsigned int flags) {
|
||||
if (flags & F_RCODE)
|
||||
return 1;
|
||||
else if (flags & F_NEG)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg, unsigned short type)
|
||||
{
|
||||
char *source, *dest;
|
||||
@@ -2259,6 +2276,9 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg,
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
|
||||
if(option_bool(OPT_LOG_ONLY_FAILED) && !error_occured(flags))
|
||||
return;
|
||||
|
||||
/* F_NOERR is reused here to indicate logs arrising from auth queries */
|
||||
if (!(flags & F_NOERR) && option_bool(OPT_AUTH_LOG))
|
||||
return;
|
||||
|
||||
+11
-3
@@ -142,7 +142,8 @@ HAVE_LOOP
|
||||
include functionality to probe for and remove DNS forwarding loops.
|
||||
|
||||
HAVE_INOTIFY
|
||||
use the Linux inotify facility to efficiently re-read configuration files.
|
||||
use the Linux and FreeBSD >= 15 inotify facility
|
||||
to efficiently re-read configuration files.
|
||||
|
||||
NO_ID
|
||||
Don't report *.bind CHAOS info to clients, forward such requests upstream instead.
|
||||
@@ -375,8 +376,15 @@ HAVE_SOCKADDR_SA_LEN
|
||||
#undef HAVE_DUMPFILE
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LINUX_NETWORK) && !defined(NO_INOTIFY)
|
||||
#define HAVE_INOTIFY
|
||||
#if !defined(NO_INOTIFY)
|
||||
# if defined (HAVE_LINUX_NETWORK)
|
||||
# define HAVE_INOTIFY
|
||||
# elif defined (__FreeBSD__) && __FreeBSD__ + 0 >= 15
|
||||
# include <osreldate.h>
|
||||
# if __FreeBSD_version >= 1500068 /* 15.0.0 */
|
||||
# define HAVE_INOTIFY
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* This never compiles code, it's only used by the makefile to fingerprint builds. */
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors, negative values are our definitions */
|
||||
#define EDE_US_SERVFAIL -2 /* SERVFAIL from usptream */
|
||||
#define EDE_UNSET -1 /* No extended DNS error available */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
|
||||
+85
-57
@@ -864,6 +864,9 @@ int main (int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Don't start logging malloc before logging is set up. */
|
||||
daemon->log_malloc = option_bool(OPT_LOG_MALLOC);
|
||||
|
||||
if (daemon->port == 0)
|
||||
my_syslog(LOG_INFO, _("started, version %s DNS disabled"), VERSION);
|
||||
else
|
||||
@@ -1335,11 +1338,42 @@ static void sig_handler(int sig)
|
||||
if (sig == SIGTERM || sig == SIGINT)
|
||||
exit(EC_MISC);
|
||||
}
|
||||
else if (pid != getpid())
|
||||
else if (daemon->pipe_to_parent != -1)
|
||||
{
|
||||
/* alarm is used to kill TCP children after a fixed time. */
|
||||
if (sig == SIGALRM)
|
||||
_exit(0);
|
||||
{
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (!daemon->forward_to_tcp)
|
||||
#endif
|
||||
_exit(0); /* Normal TCP child */
|
||||
#ifdef HAVE_DNSSEC
|
||||
else
|
||||
{
|
||||
/* udp_to_tcp transfer.
|
||||
If daemon->header_to_tcp is NULL the waiting is over and
|
||||
we can let things take their course, otherwise, send a failure
|
||||
return down the pipe to unblock the UDP transaction and kill
|
||||
the process. */
|
||||
if (daemon->header_to_tcp)
|
||||
{
|
||||
unsigned char op = PIPE_OP_KILLED;
|
||||
int status = STAT_ABANDONED;
|
||||
|
||||
read_write(daemon->pipe_to_parent, &op, sizeof(op), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)&status, sizeof(status), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(&daemon->plen_to_tcp), sizeof(daemon->plen_to_tcp), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(daemon->header_to_tcp), daemon->plen_to_tcp, RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(&daemon->forward_to_tcp), sizeof(daemon->forward_to_tcp), RW_WRITE);
|
||||
read_write(daemon->pipe_to_parent, (unsigned char *)(&daemon->forward_to_tcp->uid), sizeof(daemon->forward_to_tcp->uid), RW_WRITE);
|
||||
|
||||
my_syslog(LOG_INFO, _("TCP process for DNSSEC validation timed out"));
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1941,20 +1975,21 @@ static void check_dns_listeners(time_t now)
|
||||
|
||||
static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
{
|
||||
int confd, client_ok = 1;
|
||||
int confd;
|
||||
struct irec *iface = NULL;
|
||||
pid_t p;
|
||||
union mysockaddr tcp_addr;
|
||||
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||
unsigned char *buff;
|
||||
struct server *s;
|
||||
int flags, auth_dns;
|
||||
int flags, auth_dns = 0;
|
||||
struct in_addr netmask;
|
||||
int pipefd[2];
|
||||
struct iovec tcpbuff;
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
unsigned char a = 0;
|
||||
#endif
|
||||
|
||||
netmask.s_addr = 0;
|
||||
|
||||
while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||
|
||||
if (confd == -1)
|
||||
@@ -1981,58 +2016,63 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
|
||||
enumerate_interfaces(0);
|
||||
|
||||
if (option_bool(OPT_NOWILD))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
|
||||
{
|
||||
if ((iface = listener->iface))
|
||||
{
|
||||
netmask = iface->netmask;
|
||||
auth_dns = iface->dns_auth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int if_index;
|
||||
int if_index, got_index = 0;
|
||||
char intr_name[IF_NAMESIZE];
|
||||
|
||||
/* if we can find the arrival interface, check it's one that's allowed */
|
||||
/* if we can find the arrival interface, check it's one that's allowed
|
||||
tcp_interface() is not implemented on non-Linux platforms */
|
||||
if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 &&
|
||||
indextoname(listener->tcpfd, if_index, intr_name))
|
||||
{
|
||||
union all_addr addr;
|
||||
|
||||
got_index = 1;
|
||||
|
||||
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 (!iface_check(tcp_addr.sa.sa_family, &addr, intr_name, &auth_dns) &&
|
||||
!loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name))
|
||||
goto closeconandreturn;
|
||||
}
|
||||
|
||||
if (option_bool(OPT_CLEVERBIND))
|
||||
iface = listener->iface; /* May be NULL */
|
||||
else
|
||||
/* When binding the wildcard address, try and get the
|
||||
netmask of the interface for localisation. */
|
||||
for (iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (sockaddr_isequal(&iface->addr, &tcp_addr))
|
||||
{
|
||||
netmask = iface->netmask;
|
||||
break;
|
||||
}
|
||||
|
||||
/* On platforms where tcp_interface() doesn't work, we rely
|
||||
of the presence of the local address of the connection in the
|
||||
interface list to check if we're accepting this connection and
|
||||
for its auth status. */
|
||||
if (!got_index)
|
||||
{
|
||||
/* 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;
|
||||
goto closeconandreturn;
|
||||
|
||||
auth_dns = iface->dns_auth;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client_ok)
|
||||
goto closeconandreturn;
|
||||
|
||||
if (!option_bool(OPT_DEBUG))
|
||||
{
|
||||
/* The code in edns0.c qthat decorates queries with the source MAC address depends
|
||||
/* The code in edns0.c that decorates queries with the source MAC address depends
|
||||
on the code in arp.c, which populates a cache with the contents of the ARP table
|
||||
using netlink. Since the child process can't use netlink, we pre-populate
|
||||
the cache with the ARP table entry for our source here, including a negative entry
|
||||
@@ -2100,23 +2140,9 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
|
||||
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))
|
||||
{
|
||||
|
||||
/* Arrange for SIGALRM after CHILD_LIFETIME seconds to
|
||||
terminate the process. */
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
/* See comment above re: netlink socket. */
|
||||
close(daemon->netlinkfd);
|
||||
@@ -2133,10 +2159,8 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
|
||||
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);
|
||||
tcp_request(confd, now, &tcpbuff, &tcp_addr, netmask, auth_dns);
|
||||
free(tcpbuff.iov_base);
|
||||
|
||||
for (s = daemon->servers; s; s = s->next)
|
||||
if (s->tcpfd != -1)
|
||||
@@ -2239,8 +2263,12 @@ int swap_to_tcp(struct frec *forward, time_t now, int status, struct dns_header
|
||||
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];
|
||||
daemon->pipe_to_parent = pipefd[1];
|
||||
daemon->forward_to_tcp = forward;
|
||||
daemon->header_to_tcp = header;
|
||||
daemon->plen_to_tcp = *plen;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-10
@@ -289,7 +289,9 @@ struct event_desc {
|
||||
#define OPT_DO_0x20 75
|
||||
#define OPT_AUTH_LOG 76
|
||||
#define OPT_LEASEQUERY 77
|
||||
#define OPT_LAST 78
|
||||
#define OPT_LOG_ONLY_FAILED 78
|
||||
#define OPT_LOG_MALLOC 79
|
||||
#define OPT_LAST 80
|
||||
|
||||
#define OPTION_BITS (sizeof(unsigned int)*8)
|
||||
#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
|
||||
@@ -549,6 +551,7 @@ struct crec {
|
||||
#define PIPE_OP_STATS 3 /* Update parent's stats */
|
||||
#define PIPE_OP_IPSET 4 /* Update IPset */
|
||||
#define PIPE_OP_NFTSET 5 /* Update NFTset */
|
||||
#define PIPE_OP_KILLED 6 /* child killed by SIGALARM */
|
||||
|
||||
/* struct sockaddr is not large enough to hold any address,
|
||||
and specifically not big enough to hold an IPv6 address.
|
||||
@@ -760,10 +763,9 @@ struct dyndir {
|
||||
#define STAT_NEED_DS 0x40000
|
||||
#define STAT_NEED_KEY 0x50000
|
||||
#define STAT_TRUNCATED 0x60000
|
||||
#define STAT_SECURE_WILDCARD 0x70000
|
||||
#define STAT_OK 0x80000
|
||||
#define STAT_ABANDONED 0x90000
|
||||
#define STAT_ASYNC 0xa0000
|
||||
#define STAT_OK 0x70000
|
||||
#define STAT_ABANDONED 0x80000
|
||||
#define STAT_ASYNC 0x90000
|
||||
|
||||
#define DNSSEC_FAIL_NYV 0x0001 /* key not yet valid */
|
||||
#define DNSSEC_FAIL_EXP 0x0002 /* key expired */
|
||||
@@ -777,6 +779,7 @@ struct dyndir {
|
||||
#define DNSSEC_FAIL_NSEC3_ITERS 0x0200 /* too many iterations in NSEC3 */
|
||||
#define DNSSEC_FAIL_BADPACKET 0x0400 /* bad packet */
|
||||
#define DNSSEC_FAIL_WORK 0x0800 /* too much crypto */
|
||||
#define DNSSEC_FAIL_UPSTREAM 0x1000 /* SERVFAIL from UPSTREAM */
|
||||
|
||||
#define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b))
|
||||
|
||||
@@ -1205,6 +1208,7 @@ extern struct daemon {
|
||||
int log_fac; /* log facility */
|
||||
char *log_file; /* optional log file */
|
||||
int max_logs; /* queue limit */
|
||||
int log_malloc; /* log malloc/realloc/free */
|
||||
int randport_limit; /* Maximum number of source ports for query. */
|
||||
int cachesize, ftabsize;
|
||||
int port, query_port, min_port, max_port;
|
||||
@@ -1271,6 +1275,9 @@ extern struct daemon {
|
||||
int dnssec_no_time_check;
|
||||
int back_to_the_future;
|
||||
int limit[LIMIT_MAX];
|
||||
struct frec *forward_to_tcp;
|
||||
struct dns_header *header_to_tcp;
|
||||
ssize_t plen_to_tcp;
|
||||
#endif
|
||||
struct frec *frec_list;
|
||||
struct frec_src *free_frec_src;
|
||||
@@ -1462,7 +1469,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name,
|
||||
char *keyname, int class, int *validate_count);
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int *class,
|
||||
int check_unsigned, int *neganswer, int *nons, int *nsec_ttl, int *validate_count);
|
||||
int check_unsigned, int *neganswer, int *prim_ok, int *nons, int *nsec_ttl, int *validate_count);
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
int setup_timestamp(void);
|
||||
@@ -1490,8 +1497,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
|
||||
void *safe_malloc(size_t size);
|
||||
void safe_strncpy(char *dest, const char *src, size_t size);
|
||||
void safe_pipe(int *fd, int read_noblock);
|
||||
void *whine_malloc(size_t size);
|
||||
void *whine_realloc(void *ptr, size_t size);
|
||||
#define whine_malloc(x) whine_malloc_real(__func__, __LINE__, (x))
|
||||
#define whine_realloc(x, y) whine_realloc_real(__func__, __LINE__, (x), (y))
|
||||
#define free(x) free_real(__func__, __LINE__, (x))
|
||||
void free_real(const char *func, unsigned int line, void *ptr);
|
||||
void *whine_malloc_real(const char *func, unsigned int line, size_t size);
|
||||
void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size);
|
||||
int sa_len(union mysockaddr *addr);
|
||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2);
|
||||
int sockaddr_isnull(const union mysockaddr *s);
|
||||
@@ -1516,6 +1527,7 @@ int memcmp_masked(unsigned char *a, unsigned char *b, int len,
|
||||
int expand_buf(struct iovec *iov, size_t size);
|
||||
char *print_mac(char *buff, unsigned char *mac, int len);
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw);
|
||||
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw);
|
||||
void close_fds(long max_fd, int spare1, int spare2, int spare3);
|
||||
int wildcard_match(const char* wildcard, const char* match);
|
||||
int wildcard_matchn(const char* wildcard, const char* match, int num);
|
||||
@@ -1558,8 +1570,8 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *n,
|
||||
int class, char *name, struct server *server,
|
||||
int *keycount, int *validatecount);
|
||||
#endif
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, union all_addr *source,
|
||||
|
||||
+126
-127
@@ -370,45 +370,42 @@ static int explore_rrset(struct dns_header *header, size_t plen, int class, int
|
||||
|
||||
GETSHORT(type_covered, p);
|
||||
p += 16; /* algo, labels, orig_ttl, sig_expiration, sig_inception, key_tag */
|
||||
|
||||
if (gotkey)
|
||||
|
||||
if (type_covered == type)
|
||||
{
|
||||
/* If there's more than one SIG, ensure they all have same keyname */
|
||||
if (extract_name(header, plen, &p, keyname, EXTR_NAME_COMPARE, 0) != 1)
|
||||
if (!extract_name(header, plen, &p, daemon->workspacename, EXTR_NAME_EXTRACT, 0))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gotkey = 1;
|
||||
|
||||
if (!extract_name(header, plen, &p, keyname, EXTR_NAME_EXTRACT, 0))
|
||||
return 0;
|
||||
|
||||
|
||||
/* RFC 4035 5.3.1 says that the Signer's Name field MUST equal
|
||||
the name of the zone containing the RRset. We can't tell that
|
||||
for certain, but we can check that the RRset name is equal to
|
||||
or encloses the signers name, which should be enough to stop
|
||||
an attacker using signatures made with the key of an unrelated
|
||||
zone he controls. Note that the root key is always allowed. */
|
||||
if (*keyname != 0)
|
||||
zone he controls. Note that the root key is always allowed.
|
||||
Ignore sigs which aren't valid */
|
||||
if (*daemon->workspacename == 0 || hostname_issubdomain(name, daemon->workspacename) != 0)
|
||||
{
|
||||
char *name_start;
|
||||
for (name_start = name; !hostname_isequal(name_start, keyname); )
|
||||
if ((name_start = strchr(name_start, '.')))
|
||||
name_start++; /* chop a label off and try again */
|
||||
else
|
||||
return 0;
|
||||
if (gotkey)
|
||||
{
|
||||
/* If there's more than one valid SIG, they must all have same keyname */
|
||||
if (!hostname_isequal(keyname, daemon->workspacename))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(keyname, daemon->workspacename);
|
||||
gotkey = 1;
|
||||
}
|
||||
|
||||
if (gotkey)
|
||||
{
|
||||
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
||||
return 0;
|
||||
|
||||
sigs[sigidx++] = pdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (type_covered == type)
|
||||
{
|
||||
if (!expand_workspace(&sigs, &sig_sz, sigidx))
|
||||
return 0;
|
||||
|
||||
sigs[sigidx++] = pdata;
|
||||
}
|
||||
|
||||
p = pdata + 6; /* restore for ADD_RDLEN */
|
||||
}
|
||||
@@ -438,8 +435,6 @@ int dec_counter(int *counter, char *message)
|
||||
/* Validate a single RRset (class, type, name) in the supplied DNS reply
|
||||
Return code:
|
||||
STAT_SECURE if it validates.
|
||||
STAT_SECURE_WILDCARD if it validates and is the result of wildcard expansion.
|
||||
(In this case *wildcard_out points to the "body" of the wildcard within name.)
|
||||
STAT_BOGUS signature is wrong, bad packet.
|
||||
STAT_ABANDONED validation abandoned do to excess resource usage.
|
||||
STAT_NEED_KEY need DNSKEY to complete validation (name is returned in keyname)
|
||||
@@ -455,7 +450,7 @@ int dec_counter(int *counter, char *message)
|
||||
ttl_out is the floor on TTL, based on TTL and orig_ttl and expiration of sig used to validate.
|
||||
*/
|
||||
static int validate_rrset(time_t now, struct dns_header *header, size_t plen, int class, int type, int sigidx, int rrsetidx,
|
||||
char *name, char *keyname, char **wildcard_out, struct blockdata *key, int keylen,
|
||||
char *name, char *keyname, int *wildcard_offset_out, struct blockdata *key, int keylen,
|
||||
int algo_in, int keytag_in, unsigned long *ttl_out, int *validate_counter)
|
||||
{
|
||||
unsigned char *p;
|
||||
@@ -463,13 +458,15 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
struct crec *crecp = NULL;
|
||||
short *rr_desc = rrfilter_desc(type);
|
||||
u32 sig_expiration, sig_inception;
|
||||
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP | DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
unsigned long curtime = time(0);
|
||||
unsigned long curtime = time(0);
|
||||
int time_check = is_check_date(curtime);
|
||||
int failflags = DNSSEC_FAIL_NOSIG;
|
||||
|
||||
if (wildcard_out)
|
||||
*wildcard_out = NULL;
|
||||
if (sigidx != 0)
|
||||
failflags |= DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP | DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
if (wildcard_offset_out)
|
||||
*wildcard_offset_out = 0;
|
||||
|
||||
name_labels = count_labels(name); /* For 4035 5.3.2 check */
|
||||
|
||||
@@ -574,7 +571,9 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
name_start = name;
|
||||
|
||||
/* if more labels than in RRsig name, hash *.<no labels in rrsig labels field> 4035 5.3.2 */
|
||||
if (labels < name_labels)
|
||||
/* If the name is already the wildcard, we're not going to change it. */
|
||||
if (labels < name_labels &&
|
||||
!(name_labels - labels == 1 && name_start[0] == '*' && name_start[1] == '.'))
|
||||
{
|
||||
for (j = name_labels - labels; j != 0; j--)
|
||||
{
|
||||
@@ -584,11 +583,11 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
name_start++;
|
||||
}
|
||||
|
||||
if (wildcard_out)
|
||||
*wildcard_out = name_start+1;
|
||||
|
||||
if (wildcard_offset_out)
|
||||
*wildcard_offset_out = name_start - name + 1;
|
||||
|
||||
name_start--;
|
||||
*name_start = '*';
|
||||
*name_start = '*';
|
||||
}
|
||||
|
||||
wire_len = to_wire(name_start);
|
||||
@@ -687,7 +686,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
return STAT_ABANDONED;
|
||||
|
||||
if (verify(crecp->addr.key.keydata, crecp->addr.key.keylen, sig, sig_len, digest, hash->digest_size, algo))
|
||||
return (labels < name_labels) ? STAT_SECURE_WILDCARD : STAT_SECURE;
|
||||
return STAT_SECURE;
|
||||
|
||||
/* An attacker can waste a lot of our CPU by setting up a giant DNSKEY RRSET full of failing
|
||||
keys, all of which we have to try. Since many failing keys is not likely for
|
||||
@@ -992,7 +991,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
char *keyname, int class, int *validate_counter)
|
||||
{
|
||||
unsigned char *p = (unsigned char *)(header+1);
|
||||
int qtype, qclass, rc, i, neganswer = 0, nons = 0, servfail = 0, neg_ttl = 0, found_supported = 0;
|
||||
int qtype, qclass, rc, i, neganswer = 0, prim_ok = 0, nons = 0, servfail = 0, neg_ttl = 0, found_supported = 0;
|
||||
int aclass, atype, rdlen, flags;
|
||||
unsigned long ttl;
|
||||
union all_addr a;
|
||||
@@ -1003,7 +1002,7 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
if (RCODE(header) == SERVFAIL)
|
||||
servfail = neganswer = nons = 1;
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl, validate_counter);
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &prim_ok, &nons, &neg_ttl, validate_counter);
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
@@ -1020,27 +1019,32 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
{
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
if (option_bool(OPT_BOGUSPRIV) &&
|
||||
(flags = in_arpa_name_2_addr(name, &a)) &&
|
||||
((flags == F_IPV6 && private_net6(&a.addr6, 0)) || (flags == F_IPV4 && private_net(a.addr4, 0))))
|
||||
/* A INSECURE DS answer is OK if it's negative and there's a CNAME answer to the DS answer which is
|
||||
signed, since that's enough to prove that the DS record doesn't exist. */
|
||||
if (!neganswer || !prim_ok)
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming that's OK for a RFC-1918 address."), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
if (option_bool(OPT_BOGUSPRIV) &&
|
||||
(flags = in_arpa_name_2_addr(name, &a)) &&
|
||||
((flags == F_IPV6 && private_net6(&a.addr6, 0)) || (flags == F_IPV4 && private_net(a.addr4, 0))))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming that's OK for a RFC-1918 address."), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else if (lookup_domain(name, F_DOMAINSRV, NULL, NULL))
|
||||
{
|
||||
my_syslog(LOG_INFO, _("Insecure reply received for DS %s, assuming non-DNSSEC domain-specific server."), name);
|
||||
neganswer = 1;
|
||||
nons = 0; /* If we're faking a DS, fake one with an NS. */
|
||||
neg_ttl = DNSSEC_ASSUMED_DS_TTL;
|
||||
}
|
||||
else
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure", 0);
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1545,7 +1549,7 @@ static int check_nsec3_coverage(struct dns_header *header, size_t plen, int dige
|
||||
|
||||
/* returns 0 on success, or DNSSEC_FAIL_* value on failure. */
|
||||
static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, unsigned char **nsecs, int nsec_count, char *workspace1,
|
||||
char *workspace2, char *name, int type, char *wildname, int *nons, int *validate_counter)
|
||||
char *workspace2, char *name, int type, int wild_offset, int *nons, int *validate_counter)
|
||||
{
|
||||
unsigned char *salt, *p, *digest;
|
||||
int digest_len, i, iterations, salt_len, base32_len, algo = 0;
|
||||
@@ -1643,9 +1647,9 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if (*closest_encloser == '.')
|
||||
closest_encloser++;
|
||||
|
||||
if (wildname && hostname_isequal(closest_encloser, wildname))
|
||||
if (wild_offset != 0 && name - closest_encloser == wild_offset)
|
||||
break;
|
||||
|
||||
|
||||
if (dec_counter(validate_counter, NULL))
|
||||
return DNSSEC_FAIL_WORK;
|
||||
|
||||
@@ -1687,7 +1691,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
return DNSSEC_FAIL_NONSEC;
|
||||
|
||||
/* Finally, check that there's no seat of wildcard synthesis */
|
||||
if (!wildname)
|
||||
if (wild_offset == 0)
|
||||
{
|
||||
if (!(wildcard = strchr(next_closest, '.')) || wildcard == next_closest)
|
||||
return DNSSEC_FAIL_NONSEC;
|
||||
@@ -1710,7 +1714,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
|
||||
/* returns 0 on success, or DNSSEC_FAIL_* value on failure. */
|
||||
static int prove_non_existence(struct dns_header *header, size_t plen, char *keyname, char *name, int qtype, int qclass,
|
||||
char *wildname, int *nons, int *nsec_ttl, int *validate_counter)
|
||||
int wild_offset, int *nons, int *nsec_ttl, int *validate_counter)
|
||||
{
|
||||
static unsigned char **nsecset = NULL, **rrsig_labels = NULL;
|
||||
static int nsecset_sz = 0, rrsig_labels_sz = 0;
|
||||
@@ -1858,7 +1862,7 @@ static int prove_non_existence(struct dns_header *header, size_t plen, char *key
|
||||
if (type_found == T_NSEC)
|
||||
return prove_non_existence_nsec(header, plen, nsecset, rrsig_labels, nsecs_found, daemon->workspacename, keyname, name, qtype, nons);
|
||||
else if (type_found == T_NSEC3)
|
||||
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wildname, nons, validate_counter);
|
||||
return prove_non_existence_nsec3(header, plen, nsecset, nsecs_found, daemon->workspacename, keyname, name, qtype, wild_offset, nons, validate_counter);
|
||||
else
|
||||
return DNSSEC_FAIL_NONSEC;
|
||||
}
|
||||
@@ -1965,7 +1969,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
|
||||
if the nons argument is non-NULL.
|
||||
*/
|
||||
int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname,
|
||||
int *class, int check_unsigned, int *neganswer, int *nons, int *nsec_ttl, int *validate_counter)
|
||||
int *class, int check_unsigned, int *neganswer, int *prim_ok, int *nons, int *nsec_ttl, int *validate_counter)
|
||||
{
|
||||
static unsigned char **targets = NULL;
|
||||
static int target_sz = 0;
|
||||
@@ -1994,8 +1998,11 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
if (neganswer)
|
||||
*neganswer = 0;
|
||||
|
||||
if (RCODE(header) == SERVFAIL)
|
||||
return STAT_BOGUS | DNSSEC_FAIL_UPSTREAM;
|
||||
|
||||
if (RCODE(header) == SERVFAIL || ntohs(header->qdcount) != 1)
|
||||
if (ntohs(header->qdcount) != 1)
|
||||
return STAT_BOGUS;
|
||||
|
||||
if (RCODE(header) != NXDOMAIN && RCODE(header) != NOERROR)
|
||||
@@ -2103,8 +2110,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
CNAME must be <subdomain>.<dname>
|
||||
CNAME target must be <subdomain>.<dname_target>
|
||||
<subdomain>s must match for name and target. */
|
||||
if (hostname_issubdomain(name, daemon->cname) == 1 &&
|
||||
hostname_issubdomain(keyname, daemon->workspacename) == 1 &&
|
||||
if (hostname_issubdomain(daemon->cname, name) == 1 &&
|
||||
hostname_issubdomain(daemon->workspacename, keyname) == 1 &&
|
||||
name_prefix_len == strlen(daemon->workspacename) - strlen(keyname))
|
||||
{
|
||||
char save = daemon->cname[name_prefix_len];
|
||||
@@ -2183,47 +2190,32 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
else
|
||||
{
|
||||
/* Not done, validate now */
|
||||
int sigcnt, rrcnt;
|
||||
char *wildname;
|
||||
int sigcnt, rrcnt, wild_offset;
|
||||
|
||||
if (!explore_rrset(header, plen, class1, type1, name, keyname, &sigcnt, &rrcnt))
|
||||
return STAT_BOGUS;
|
||||
|
||||
/* No signatures for RRset. We can be configured to assume this is OK and return an INSECURE result. */
|
||||
if (sigcnt == 0)
|
||||
{
|
||||
/* NSEC and NSEC3 records must be signed. We make this assumption elsewhere. */
|
||||
if (type1 == T_NSEC || type1 == T_NSEC3)
|
||||
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.
|
||||
Return SECURE even if others (SOA....) are not. */
|
||||
rc = STAT_SECURE;
|
||||
else
|
||||
{
|
||||
/* unsigned RRsets in auth section are not BOGUS, but do make reply insecure. */
|
||||
if (check_unsigned && i < ntohs(header->ancount))
|
||||
{
|
||||
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 */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (!STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* NSEC and NSEC3 records must be signed. We make this assumption elsewhere. */
|
||||
if (sigcnt == 0 && (type1 == T_NSEC || type1 == T_NSEC3))
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOSIG;
|
||||
else if (sigcnt == 0 && 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.
|
||||
Return SECURE even if others (SOA....) are not. */
|
||||
rc = STAT_SECURE;
|
||||
else if (sigcnt == 0 && (!check_unsigned || i >= ntohs(header->ancount)))
|
||||
/* unsigned RRsets in auth section are not BOGUS, but do make reply insecure. */
|
||||
rc = STAT_INSECURE;
|
||||
else
|
||||
{
|
||||
/* explore_rrset() gives us key name from sigs in keyname.
|
||||
/* explore_rrset() gives us zone name from sigs in keyname, if
|
||||
it didn't find a key, use the name we're validating.
|
||||
Can't overwrite name here. */
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
if (sigcnt == 0)
|
||||
strcpy(daemon->workspacename, name);
|
||||
else
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
@@ -2233,12 +2225,12 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
/* If zone is insecure, don't need to validate RRset, and rc remains as STAT_INSECURE*/
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
unsigned long sig_ttl;
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl, validate_counter);
|
||||
rrcnt, name, keyname, &wild_offset, NULL, 0, 0, 0, &sig_ttl, validate_counter);
|
||||
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS) || STAT_ISEQUAL(rc, STAT_ABANDONED))
|
||||
{
|
||||
@@ -2247,7 +2239,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* rc is now STAT_SECURE or STAT_SECURE_WILDCARD */
|
||||
/* rc is now STAT_SECURE */
|
||||
|
||||
/* Note that RR is validated */
|
||||
daemon->rr_status[i] = sig_ttl;
|
||||
@@ -2273,8 +2265,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE_WILDCARD) &&
|
||||
((rc_nsec = prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL, validate_counter))) != 0)
|
||||
if (wild_offset != 0 &&
|
||||
((rc_nsec = prove_non_existence(header, plen, keyname, name, type1, class1, wild_offset, NULL, NULL, validate_counter))) != 0)
|
||||
return (rc_nsec & DNSSEC_FAIL_WORK) ? STAT_ABANDONED : (STAT_BOGUS | rc_nsec);
|
||||
|
||||
rc = STAT_SECURE;
|
||||
@@ -2286,6 +2278,20 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
|
||||
/* For a DS record, we are interested also in if the answer to the DS query was
|
||||
a CNAME RRset which validated. That's proof that the DS doesn't exist,
|
||||
even if it's a CNAME which is not signed, and therefore we have no proof
|
||||
of what it actually _is_. This return tells us that the answer to
|
||||
primary query is secure, even is the whole answer is insecure, because
|
||||
something down the CNAME list doesn't validate or doesn't exist.
|
||||
Note that prim_ok is only valid when neganswer is true, ie either
|
||||
the answer is the requested record or it's a CNAME that ends
|
||||
in a missing answer or an unsigned zone.
|
||||
*/
|
||||
if (prim_ok)
|
||||
*prim_ok = !targets[0];
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
@@ -2296,20 +2302,12 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (!extract_name(header, plen, &p2, name, EXTR_NAME_EXTRACT, 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 NSEC records.
|
||||
For a DS record, we return INSECURE, which almost always turns
|
||||
into BOGUS in the caller. */
|
||||
if ((rc_nsec = prove_non_existence(header, plen, keyname, name, qtype, qclass, NULL, nons, nsec_ttl, validate_counter)) != 0)
|
||||
/* NXDOMAIN or NODATA reply, unanswered question is (name, qclass, qtype)
|
||||
This situation is OK if either the answer is in an unsigned zone, or there's NSEC records. */
|
||||
if ((rc_nsec = prove_non_existence(header, plen, keyname, name, qtype, qclass, 0, nons, nsec_ttl, validate_counter)) != 0)
|
||||
{
|
||||
if (rc_nsec & DNSSEC_FAIL_WORK)
|
||||
return STAT_ABANDONED;
|
||||
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_INSECURE;
|
||||
|
||||
if ((rc_nsec & (DNSSEC_FAIL_NONSEC | DNSSEC_FAIL_NSEC3_ITERS)) &&
|
||||
!STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
|
||||
@@ -2381,8 +2379,9 @@ int errflags_to_ede(int status)
|
||||
/* We can end up with more than one flag set for some errors,
|
||||
so this encodes a rough priority so the (eg) No sig is reported
|
||||
before no-unexpired-sig. */
|
||||
|
||||
if (status & DNSSEC_FAIL_NYV)
|
||||
if (status & DNSSEC_FAIL_UPSTREAM)
|
||||
return EDE_US_SERVFAIL;
|
||||
else if (status & DNSSEC_FAIL_NYV)
|
||||
return EDE_SIG_NYV;
|
||||
else if (status & DNSSEC_FAIL_EXP)
|
||||
return EDE_SIG_EXP;
|
||||
|
||||
+148
-138
@@ -135,9 +135,9 @@ static void log_query_mysockaddr(unsigned int flags, char *name, union mysockadd
|
||||
}
|
||||
|
||||
static void server_send(struct server *server, int fd,
|
||||
const void *header, size_t plen, int flags)
|
||||
const void *header, size_t plen)
|
||||
{
|
||||
while (retry_send(sendto(fd, header, plen, flags,
|
||||
while (retry_send(sendto(fd, header, plen, 0,
|
||||
&server->addr.sa,
|
||||
sa_len(&server->addr))));
|
||||
}
|
||||
@@ -960,7 +960,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
status = dnssec_validate_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class, &orig->validate_counter);
|
||||
else
|
||||
status = dnssec_validate_reply(now, header, plen, daemon->namebuff, daemon->keyname, &forward->class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, &orig->validate_counter);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, NULL, &orig->validate_counter);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
log_resource = 1;
|
||||
@@ -1074,7 +1074,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
set_outgoing_mark(orig, fd);
|
||||
#endif
|
||||
|
||||
server_send(server, fd, header, nn, 0);
|
||||
server_send(server, fd, header, nn);
|
||||
server->queries++;
|
||||
#ifdef HAVE_DUMPFILE
|
||||
dump_packet_udp(DUMP_SEC_QUERY, (void *)header, (size_t)nn, NULL, &server->addr, fd);
|
||||
@@ -1399,6 +1399,9 @@ void return_reply(time_t now, struct frec *forward, struct dns_header *header, s
|
||||
|
||||
a.log.ede = ede;
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
|
||||
if (ede == EDE_US_SERVFAIL)
|
||||
ede = EDE_DNSSEC_BOGUS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2015,20 +2018,21 @@ void receive_query(struct listener *listen, time_t now)
|
||||
}
|
||||
|
||||
|
||||
/* Send query in packet, qsize to a server determined by first,last,start and
|
||||
get the reply. return reply size. */
|
||||
static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet, size_t qsize,
|
||||
int have_mark, unsigned int mark, struct server **servp)
|
||||
/* Send query in header, qsize to a server determined by first,last,start and
|
||||
get the reply into the buffer passed by outbuff. Return reply size. */
|
||||
static ssize_t tcp_talk(int first, int last, int start, struct dns_header *header, size_t qsize,
|
||||
struct iovec *recvbuff, int have_mark, unsigned int mark, struct server **servp)
|
||||
{
|
||||
int firstsendto = -1;
|
||||
u16 *length = (u16 *)packet;
|
||||
unsigned char *payload = &packet[2];
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
unsigned int rsize;
|
||||
u16 length;
|
||||
unsigned int rsize = 0;
|
||||
int class, rclass, type, rtype;
|
||||
unsigned char *p;
|
||||
struct blockdata *saved_question;
|
||||
struct timeval tv;
|
||||
struct iovec sendio[2];
|
||||
#ifdef MSG_FASTOPEN
|
||||
struct msghdr msg;
|
||||
#endif
|
||||
|
||||
(void)mark;
|
||||
(void)have_mark;
|
||||
@@ -2040,10 +2044,12 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
GETSHORT(type, p);
|
||||
GETSHORT(class, p);
|
||||
|
||||
/* Save question for retry. */
|
||||
if (!(saved_question = blockdata_alloc((char *)header, (size_t)qsize)))
|
||||
return 0;
|
||||
|
||||
length = htons(qsize);
|
||||
sendio[0].iov_base = &length;
|
||||
sendio[0].iov_len = sizeof(length);
|
||||
sendio[1].iov_base = header;
|
||||
sendio[1].iov_len = qsize;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int data_sent = 0, fatal = 0;
|
||||
@@ -2065,10 +2071,6 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
*servp = serv = daemon->serverarray[start];
|
||||
|
||||
retry:
|
||||
blockdata_retrieve(saved_question, qsize, header);
|
||||
|
||||
*length = htons(qsize);
|
||||
|
||||
if (serv->tcpfd == -1)
|
||||
{
|
||||
if ((serv->tcpfd = socket(serv->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
|
||||
@@ -2099,10 +2101,17 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
tv.tv_sec += TCP_TIMEOUT;
|
||||
setsockopt(serv->tcpfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
|
||||
#endif
|
||||
|
||||
#ifdef MSG_FASTOPEN
|
||||
server_send(serv, serv->tcpfd, packet, qsize + sizeof(u16), MSG_FASTOPEN);
|
||||
|
||||
msg.msg_name = &serv->addr.sa;
|
||||
msg.msg_namelen = sa_len(&serv->addr);
|
||||
msg.msg_iov = sendio;
|
||||
msg.msg_iovlen = 2;
|
||||
msg.msg_control = NULL;
|
||||
msg.msg_controllen = 0;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
while (retry_send(sendmsg(serv->tcpfd, &msg, MSG_FASTOPEN)));
|
||||
|
||||
if (errno == 0)
|
||||
data_sent = 1;
|
||||
else if (errno == ETIMEDOUT || errno == EHOSTUNREACH || errno == EINPROGRESS || errno == ECONNREFUSED)
|
||||
@@ -2128,12 +2137,13 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
serv->flags &= ~SERV_GOT_TCP;
|
||||
}
|
||||
|
||||
/* We us the _ONCE veriant of read_write() here because we've set a timeout on the tcp socket
|
||||
/* We use the _ONCE variant of read_write() here because we've set a timeout on the tcp socket
|
||||
and wish to abort if the whole data is not read/written within the timeout. */
|
||||
if ((!data_sent && !read_write(serv->tcpfd, (unsigned char *)packet, qsize + sizeof(u16), RW_WRITE_ONCE)) ||
|
||||
!read_write(serv->tcpfd, (unsigned char *)length, sizeof (*length), RW_READ_ONCE) ||
|
||||
!read_write(serv->tcpfd, payload, (rsize = ntohs(*length)), RW_READ_ONCE))
|
||||
{
|
||||
if ((!data_sent && !read_writev(serv->tcpfd, sendio, 2, RW_WRITE_ONCE)) ||
|
||||
!read_write(serv->tcpfd, (unsigned char *)&length, sizeof(length), RW_READ_ONCE) ||
|
||||
!expand_buf(recvbuff, (rsize = ntohs(length))) ||
|
||||
!read_write(serv->tcpfd, recvbuff->iov_base, rsize, RW_READ_ONCE))
|
||||
{
|
||||
/* We get data then EOF, reopen connection to same server,
|
||||
else try next. This avoids DoS from a server which accepts
|
||||
connections and then closes them. */
|
||||
@@ -2146,28 +2156,28 @@ static ssize_t tcp_talk(int first, int last, int start, unsigned char *packet,
|
||||
else
|
||||
goto failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the question section of the reply doesn't match the question we sent, then
|
||||
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 */
|
||||
p = (unsigned char *)(((struct dns_header *)recvbuff->iov_base)+1);
|
||||
if (extract_name(((struct dns_header *)recvbuff->iov_base), rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
||||
continue;
|
||||
GETSHORT(rtype, p);
|
||||
GETSHORT(rclass, p);
|
||||
|
||||
/* If the question section of the reply doesn't match the question we sent, then
|
||||
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 */
|
||||
p = (unsigned char *)(header+1);
|
||||
if (extract_name(header, rsize, &p, daemon->namebuff, EXTR_NAME_COMPARE, 4) != 1)
|
||||
continue;
|
||||
GETSHORT(rtype, p);
|
||||
GETSHORT(rclass, p);
|
||||
|
||||
if (type != rtype || class != rclass)
|
||||
continue;
|
||||
if (type != rtype || class != rclass)
|
||||
continue;
|
||||
}
|
||||
|
||||
serv->flags |= SERV_GOT_TCP;
|
||||
|
||||
*servp = serv;
|
||||
blockdata_free(saved_question);
|
||||
return rsize;
|
||||
}
|
||||
|
||||
blockdata_free(saved_question);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2179,19 +2189,16 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
int class, char *name, struct server *server,
|
||||
int *keycount, int *validatecount)
|
||||
{
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
struct dns_header *new_header = (struct dns_header *)&packet[2];
|
||||
int start, first, last, new_status;
|
||||
ssize_t n = *plenp;
|
||||
int log_save = daemon->log_display_id;
|
||||
struct iovec recvbuff;
|
||||
|
||||
recvbuff.iov_len = 0;
|
||||
recvbuff.iov_base = NULL;
|
||||
|
||||
*plenp = 0;
|
||||
|
||||
if (!packet)
|
||||
return STAT_ABANDONED;
|
||||
|
||||
memcpy(new_header, header, n);
|
||||
|
||||
/* Set TCP flag in logs. */
|
||||
daemon->log_display_id = -daemon->log_display_id;
|
||||
|
||||
@@ -2209,10 +2216,11 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC | F_SERVER, name, &server->addr,
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? "dnssec-query[DNSKEY]" : "dnssec-query[DS]", 0);
|
||||
|
||||
if ((n = tcp_talk(first, last, start, packet, n, 0, 0, &server)) == 0)
|
||||
if ((n = tcp_talk(first, last, start, header, n, &recvbuff, 0, 0, &server)) == 0)
|
||||
new_status = STAT_ABANDONED;
|
||||
else
|
||||
{
|
||||
struct dns_header *new_header = (struct dns_header *)recvbuff.iov_base;
|
||||
new_status = tcp_key_recurse(now, status, new_header, n, class, daemon->namebuff, daemon->keyname, server, 0, 0, keycount, validatecount);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_OK))
|
||||
@@ -2223,7 +2231,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
|
||||
if (n >= daemon->edns_pktsz)
|
||||
{
|
||||
/* still too bIg, strip optional sections and try again. */
|
||||
/* still too big, strip optional sections and try again. */
|
||||
new_header->nscount = htons(0);
|
||||
new_header->arcount = htons(0);
|
||||
n = resize_packet(new_header, n, NULL, 0);
|
||||
@@ -2237,6 +2245,10 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
}
|
||||
}
|
||||
|
||||
/* we have succeeded and are no longer blocked talking
|
||||
on a TCP connection, so if the watchdog alarm goes off,
|
||||
ignore it. */
|
||||
daemon->forward_to_tcp = NULL;
|
||||
/* return the stripped or truncated reply. */
|
||||
memcpy(header, new_header, n);
|
||||
*plenp = n;
|
||||
@@ -2245,7 +2257,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
|
||||
}
|
||||
|
||||
daemon->log_display_id = log_save;
|
||||
free(packet);
|
||||
free(recvbuff.iov_base);
|
||||
return new_status;
|
||||
}
|
||||
|
||||
@@ -2255,9 +2267,12 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
int have_mark, unsigned int mark, int *keycount, int *validatecount)
|
||||
{
|
||||
int first, last, start, new_status;
|
||||
unsigned char *packet = NULL;
|
||||
struct dns_header *new_header = NULL;
|
||||
struct iovec new_packet;
|
||||
struct dns_header *query_header = NULL, *new_header;
|
||||
|
||||
new_packet.iov_base = NULL;
|
||||
new_packet.iov_len = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
size_t m;
|
||||
@@ -2270,7 +2285,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class, validatecount);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, validatecount);
|
||||
!option_bool(OPT_DNSSEC_IGN_NS), NULL, NULL, NULL, NULL, validatecount);
|
||||
|
||||
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY) && !STAT_ISEQUAL(new_status, STAT_ABANDONED))
|
||||
break;
|
||||
@@ -2291,34 +2306,21 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
}
|
||||
|
||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||
Make query for same, and recurse to validate */
|
||||
if (!packet)
|
||||
{
|
||||
packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
new_header = (struct dns_header *)&packet[2];
|
||||
}
|
||||
|
||||
if (!packet)
|
||||
{
|
||||
new_status = STAT_ABANDONED;
|
||||
break;
|
||||
}
|
||||
|
||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
|
||||
Make query for same in UDP packet buffer, recurse to validate*/
|
||||
query_header = (struct dns_header *)daemon->packet;
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
m = dnssec_generate_query(query_header, ((unsigned char *)query_header) + daemon->edns_pktsz, keyname, class, 0,
|
||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
|
||||
|
||||
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
|
||||
if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1 ||
|
||||
(m = tcp_talk(first, last, start, query_header, m, &new_packet, have_mark, mark, &server)) == 0)
|
||||
{
|
||||
new_status = STAT_ABANDONED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
||||
{
|
||||
new_status = STAT_ABANDONED;
|
||||
break;
|
||||
}
|
||||
|
||||
new_header = new_packet.iov_base;
|
||||
log_save = daemon->log_display_id;
|
||||
daemon->log_display_id = -(++daemon->log_id);
|
||||
|
||||
@@ -2335,8 +2337,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet)
|
||||
free(packet);
|
||||
free(new_packet.iov_base);
|
||||
|
||||
return new_status;
|
||||
}
|
||||
@@ -2346,11 +2347,11 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
/* The daemon forks before calling this: it should deal with one connection,
|
||||
blocking as necessary, and then return. Note, need to be a bit careful
|
||||
about resources for debug mode, when the fork is suppressed: that's
|
||||
done by the caller. */
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
||||
done by the caller, which also frees bigbuff. */
|
||||
void tcp_request(int confd, time_t now, struct iovec *bigbuff,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
|
||||
{
|
||||
size_t size = 0, saved_size = 0;
|
||||
size_t size = 0;
|
||||
int norebind = 0;
|
||||
#ifdef HAVE_CONNTRACK
|
||||
int allowed = 1;
|
||||
@@ -2359,16 +2360,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
int local_auth = 0;
|
||||
#endif
|
||||
int checking_disabled, do_bit = 0, ad_reqd = 0, have_pseudoheader = 0;
|
||||
struct blockdata *saved_question = NULL;
|
||||
unsigned short qtype;
|
||||
unsigned int gotname = 0;
|
||||
/* Max TCP packet + slop + size */
|
||||
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ + sizeof(u16));
|
||||
unsigned char *payload = &packet[2];
|
||||
u16 tcp_len;
|
||||
/* largest field in header is 16-bits, so this is still sufficiently aligned */
|
||||
struct dns_header *header = (struct dns_header *)payload;
|
||||
u16 *length = (u16 *)packet;
|
||||
u16 tcp_len, out_len;
|
||||
struct dns_header *header, *out_header;
|
||||
struct server *serv;
|
||||
struct in_addr dst_addr_4;
|
||||
union mysockaddr peer_addr;
|
||||
@@ -2378,9 +2373,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
unsigned int mark = 0;
|
||||
int have_mark = 0;
|
||||
int first, last, filtered, do_stale = 0;
|
||||
|
||||
if (!packet || getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return packet;
|
||||
struct iovec out_iov[2];
|
||||
|
||||
bigbuff->iov_base = NULL;
|
||||
bigbuff->iov_len = 0;
|
||||
|
||||
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) == -1)
|
||||
return;
|
||||
|
||||
#ifdef HAVE_CONNTRACK
|
||||
/* Get connection mark of incoming query to set on outgoing connections. */
|
||||
@@ -2401,7 +2400,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (option_bool(OPT_LOCAL_SERVICE))
|
||||
{
|
||||
struct addrlist *addr;
|
||||
|
||||
|
||||
if (peer_addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
for (addr = daemon->interface_addrs; addr; addr = addr->next)
|
||||
@@ -2424,7 +2423,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
prettyprint_addr(&peer_addr, daemon->addrbuff);
|
||||
my_syslog(LOG_WARNING, _("ignoring query from non-local network %s"), daemon->addrbuff);
|
||||
return packet;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2442,18 +2441,26 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (query_count >= TCP_MAX_QUERIES)
|
||||
break;
|
||||
|
||||
/* Now get the query into the normal UDP packet buffer.
|
||||
Ignore queries long than this. If we're answering locally,
|
||||
copy the query into the output buffer, but for forwarding, tcp_talk()
|
||||
wants the query in a a different buffer from the reply.
|
||||
Note that we overwrote any saved UDP query - this onlt matters in debug mode. */
|
||||
daemon->srv_save = NULL;
|
||||
if (!read_write(confd, (unsigned char *)&tcp_len, sizeof(tcp_len), RW_READ) ||
|
||||
!(size = ntohs(tcp_len)) ||
|
||||
!read_write(confd, payload, size, RW_READ))
|
||||
!(size = ntohs(tcp_len)) || size > (size_t)daemon->packet_buff_sz ||
|
||||
!read_write(confd, (unsigned char *)daemon->packet, size, RW_READ))
|
||||
break;
|
||||
|
||||
|
||||
if (size < (int)sizeof(struct dns_header))
|
||||
continue;
|
||||
|
||||
/* Clear buffer beyond request to avoid risk of
|
||||
information disclosure. */
|
||||
memset(payload + size, 0, 65536 - size);
|
||||
/* Make sure we have a buffer big enough for the largest answer. */
|
||||
expand_buf(bigbuff, 65536 + MAXDNAME + RRFIXEDSZ);
|
||||
out_header = bigbuff->iov_base;
|
||||
|
||||
/* header == query */
|
||||
header = (struct dns_header *)daemon->packet;
|
||||
query_count++;
|
||||
|
||||
/* log_query gets called indirectly all over the place, so
|
||||
@@ -2472,9 +2479,6 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
ede = EDE_INVALID_DATA;
|
||||
else
|
||||
{
|
||||
if (saved_question)
|
||||
blockdata_free(saved_question);
|
||||
|
||||
do_bit = 0;
|
||||
|
||||
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
|
||||
@@ -2489,9 +2493,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
do_bit = 1; /* do bit */
|
||||
}
|
||||
|
||||
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;
|
||||
size = add_edns0_config(header, size, ((unsigned char *) header) + daemon->edns_pktsz, &peer_addr, now, &cacheable);
|
||||
|
||||
/* Clear buffer to avoid risk of information disclosure. */
|
||||
memset(bigbuff->iov_base, 0, bigbuff->iov_len);
|
||||
/* Copy query into output buffer for local answering */
|
||||
memcpy(out_header, header, size);
|
||||
|
||||
log_query_mysockaddr((auth_dns ? F_NOERR | F_AUTH : 0) | F_QUERY | F_FORWARD, daemon->namebuff,
|
||||
&peer_addr, NULL, qtype);
|
||||
@@ -2550,10 +2557,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#endif
|
||||
#ifdef HAVE_AUTH
|
||||
else if (auth_dns)
|
||||
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
||||
m = answer_auth(out_header, ((char *) out_header) + 65536, (size_t)size, now, &peer_addr, local_auth);
|
||||
#endif
|
||||
else
|
||||
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
|
||||
m = answer_request(out_header, ((char *) out_header) + 65536, (size_t)size,
|
||||
dst_addr_4, netmask, now, ad_reqd, do_bit, !cacheable, &stale, &filtered);
|
||||
}
|
||||
}
|
||||
@@ -2561,15 +2568,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* Do this by steam now we're not in the select() loop */
|
||||
check_log_writer(1);
|
||||
|
||||
if (m == 0 && ede == EDE_UNSET && saved_question)
|
||||
if (m == 0 && ede == EDE_UNSET)
|
||||
{
|
||||
struct server *master;
|
||||
int start;
|
||||
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 */
|
||||
checking_disabled = header->hb4 & HB4_CD;
|
||||
|
||||
@@ -2598,7 +2602,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
{
|
||||
size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
|
||||
size = add_do_bit(header, size, ((unsigned char *) header) + daemon->edns_pktsz);
|
||||
|
||||
/* For debugging, set Checking Disabled, otherwise, have the upstream check too,
|
||||
this allows it to select auth servers when one is returning bad data. */
|
||||
@@ -2608,12 +2612,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#endif
|
||||
|
||||
/* 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)
|
||||
if ((m = tcp_talk(first, last, start, header, size, bigbuff, have_mark, mark, &serv)) == 0)
|
||||
ede = EDE_NETERR;
|
||||
else
|
||||
{
|
||||
/* just in case tcp_talk() expanded buffer - should never happen */
|
||||
out_header = bigbuff->iov_base;
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!extract_name(header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
if (!extract_name(out_header, (unsigned int)size, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
strcpy(daemon->namebuff, "query");
|
||||
log_query_mysockaddr(F_SERVER | F_FORWARD, daemon->namebuff, &serv->addr, NULL, 0);
|
||||
|
||||
@@ -2629,7 +2635,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
{
|
||||
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];
|
||||
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname,
|
||||
/* tcp_key_recurse() may overwrite packetbuf, and thuse *header is now invalid */
|
||||
int status = tcp_key_recurse(now, STAT_OK, out_header, m, 0, daemon->namebuff, daemon->keyname,
|
||||
serv, have_mark, mark, &keycount, &validatecount);
|
||||
char *result, *domain = "result";
|
||||
|
||||
@@ -2655,12 +2662,14 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
|
||||
if (extract_name(header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
if (extract_name(out_header, m, NULL, daemon->namebuff, EXTR_NAME_EXTRACT, 0))
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
a.log.ede = ede;
|
||||
log_query(F_SECSTAT, domain, &a, result, 0);
|
||||
if (ede == EDE_US_SERVFAIL)
|
||||
ede = EDE_DNSSEC_BOGUS;
|
||||
|
||||
if ((daemon->limit[LIMIT_CRYPTO] - validatecount) > (int)daemon->metrics[METRIC_CRYPTO_HWM])
|
||||
daemon->metrics[METRIC_CRYPTO_HWM] = daemon->limit[LIMIT_CRYPTO] - validatecount;
|
||||
@@ -2677,18 +2686,18 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
/* restore CD bit to the value in the query */
|
||||
if (checking_disabled)
|
||||
header->hb4 |= HB4_CD;
|
||||
out_header->hb4 |= HB4_CD;
|
||||
else
|
||||
header->hb4 &= ~HB4_CD;
|
||||
out_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 (!cacheable)
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
m = process_reply(header, now, serv, (unsigned int)m,
|
||||
m = process_reply(out_header, now, serv, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
||||
ad_reqd, do_bit, !have_pseudoheader, &peer_addr, ((unsigned char *)out_header) + 65536, ede);
|
||||
|
||||
/* process_reply() adds pheader itself */
|
||||
have_pseudoheader = 0;
|
||||
@@ -2703,8 +2712,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
/* In case of local answer or no connections made. */
|
||||
if (m == 0)
|
||||
{
|
||||
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
||||
((char *) header) + 65536, first, last, ede)))
|
||||
if (!(m = make_local_answer(flags, gotname, size, out_header, daemon->namebuff,
|
||||
((char *) out_header) + 65536, first, last, ede)))
|
||||
break;
|
||||
}
|
||||
else if (ede == EDE_UNSET)
|
||||
@@ -2720,14 +2729,12 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != EDE_UNSET)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, 0, NULL, 0, do_bit, 0);
|
||||
m = add_pseudoheader(out_header, m, ((unsigned char *) out_header) + 65536, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
|
||||
check_log_writer(1);
|
||||
|
||||
*length = htons(m);
|
||||
check_log_writer(1);
|
||||
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -2737,7 +2744,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
report_addresses(header, m, mark);
|
||||
#endif
|
||||
|
||||
if (!read_write(confd, packet, m + sizeof(u16), RW_WRITE))
|
||||
/* use scatter-gather IO so that length doesn't end up in separate packet. */
|
||||
out_len = htons(m);
|
||||
out_iov[0].iov_len = sizeof(out_len);
|
||||
out_iov[0].iov_base = &out_len;
|
||||
out_iov[1].iov_len = m;
|
||||
out_iov[1].iov_base = bigbuff->iov_base;
|
||||
if (!read_writev(confd, out_iov, 2, RW_WRITE))
|
||||
break;
|
||||
|
||||
/* If we answered with stale data, this process will now try and get fresh data into
|
||||
@@ -2753,18 +2766,15 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
daemon->log_source_addr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we ran once to get fresh data, confd is already closed. */
|
||||
|
||||
/* If we ran once to get fresh data, confd is already closed. */
|
||||
if (!do_stale)
|
||||
{
|
||||
shutdown(confd, SHUT_RDWR);
|
||||
close(confd);
|
||||
}
|
||||
|
||||
blockdata_free(saved_question);
|
||||
|
||||
check_log_writer(1);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/* return a UDP socket bound to a random port, have to cope with straying into
|
||||
@@ -3265,7 +3275,7 @@ void resend_query(void)
|
||||
{
|
||||
if (daemon->srv_save)
|
||||
server_send(daemon->srv_save, daemon->fd_save,
|
||||
daemon->packet, daemon->packet_len, 0);
|
||||
daemon->packet, daemon->packet_len);
|
||||
}
|
||||
|
||||
/* A server record is going away, remove references to it */
|
||||
|
||||
@@ -197,6 +197,7 @@ struct myoption {
|
||||
#define LOPT_DO_ENCODE 388
|
||||
#define LOPT_LEASEQUERY 389
|
||||
#define LOPT_SPLIT_RELAY 390
|
||||
#define LOPT_LOG_MALLOC 391
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
static const struct option opts[] =
|
||||
@@ -398,6 +399,7 @@ static const struct myoption opts[] =
|
||||
{ "no-ident", 0, 0, LOPT_NO_IDENT },
|
||||
{ "max-tcp-connections", 1, 0, LOPT_MAX_PROCS },
|
||||
{ "leasequery", 2, 0, LOPT_LEASEQUERY },
|
||||
{ "log-malloc", 0, 0, LOPT_LOG_MALLOC },
|
||||
{ NULL, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -606,6 +608,7 @@ static struct {
|
||||
{ LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL },
|
||||
{ LOPT_CACHE_RR, ARG_DUP, "<RR-type>", gettext_noop("Cache this DNS resource record type."), NULL },
|
||||
{ LOPT_MAX_PROCS, ARG_ONE, "<integer>", gettext_noop("Maximum number of concurrent tcp connections."), NULL },
|
||||
{ LOPT_LOG_MALLOC, OPT_LOG_MALLOC, NULL, gettext_noop("Log memory allocation for debugging."), NULL },
|
||||
{ 0, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -3463,6 +3466,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
|
||||
}
|
||||
else if (strcmp(arg, "auth") == 0)
|
||||
set_option_bool(OPT_AUTH_LOG);
|
||||
else if (strcmp(arg, "only_failed") == 0)
|
||||
set_option_bool(OPT_LOG_ONLY_FAILED);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+10
-2
@@ -1596,9 +1596,14 @@ 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)
|
||||
{
|
||||
state->ia_type = opt6_type(opt);
|
||||
*ia_option = NULL;
|
||||
|
||||
/* must be a minimal option to check without stepping outside received packet. */
|
||||
if (opt6_ptr(opt, 4) > state->end)
|
||||
return 0;
|
||||
|
||||
state->ia_type = opt6_type(opt);
|
||||
|
||||
if (state->ia_type != OPTION6_IA_NA && state->ia_type != OPTION6_IA_TA)
|
||||
return 0;
|
||||
|
||||
@@ -1608,7 +1613,10 @@ static int check_ia(struct state *state, void *opt, void **endp, void **ia_optio
|
||||
if (state->ia_type == OPTION6_IA_TA && opt6_len(opt) < 4)
|
||||
return 0;
|
||||
|
||||
*endp = opt6_ptr(opt, opt6_len(opt));
|
||||
/* Check we don't overflow the received packet. */
|
||||
if ((*endp = opt6_ptr(opt, opt6_len(opt))) > state->end)
|
||||
return 0;
|
||||
|
||||
state->iaid = opt6_uint(opt, 0, 4);
|
||||
*ia_option = opt6_find(opt6_ptr(opt, state->ia_type == OPTION6_IA_NA ? 12 : 4), *endp, OPTION6_IAADDR, 24);
|
||||
|
||||
|
||||
+84
-48
@@ -341,26 +341,6 @@ void safe_pipe(int *fd, int read_noblock)
|
||||
die(_("cannot create pipe: %s"), NULL, EC_MISC);
|
||||
}
|
||||
|
||||
void *whine_malloc(size_t size)
|
||||
{
|
||||
void *ret = calloc(1, size);
|
||||
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *whine_realloc(void *ptr, size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2)
|
||||
{
|
||||
if (s1->sa.sa_family == s2->sa.sa_family)
|
||||
@@ -443,8 +423,8 @@ int hostname_issubdomain(char *a, char *b)
|
||||
for (ap = a; *ap; ap++);
|
||||
for (bp = b; *bp; bp++);
|
||||
|
||||
/* a shorter than b or a empty. */
|
||||
if ((bp - b) < (ap - a) || ap == a)
|
||||
/* a shorter than b */
|
||||
if ((ap - a) < (bp - b))
|
||||
return 0;
|
||||
|
||||
do
|
||||
@@ -459,12 +439,12 @@ int hostname_issubdomain(char *a, char *b)
|
||||
|
||||
if (c1 != c2)
|
||||
return 0;
|
||||
} while (ap != a);
|
||||
} while (bp != b);
|
||||
|
||||
if (bp == b)
|
||||
if (ap == a)
|
||||
return 2;
|
||||
|
||||
if (*(--bp) == '.')
|
||||
if (*(--ap) == '.')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -777,43 +757,60 @@ int retry_send(ssize_t rc)
|
||||
"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)
|
||||
int read_writev(int fd, struct iovec *iov, int iovcnt, int rw)
|
||||
{
|
||||
ssize_t n, done;
|
||||
|
||||
for (done = 0; done < size; done += n)
|
||||
{
|
||||
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;
|
||||
int cur = 0;
|
||||
ssize_t n, done = 0;
|
||||
|
||||
while (cur < iovcnt)
|
||||
{
|
||||
iov[cur].iov_len -= done;
|
||||
iov[cur].iov_base = ((char *)iov[cur].iov_base) + done;
|
||||
|
||||
if (rw & 1)
|
||||
n = readv(fd, &iov[cur], iovcnt - cur);
|
||||
else
|
||||
n = writev(fd, &iov[cur], iovcnt - cur);
|
||||
|
||||
iov[cur].iov_len += done;
|
||||
iov[cur].iov_base = ((char *)iov[cur].iov_base) - done;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(rw & 2) && (errno == EAGAIN || errno == EWOULDBLOCK))
|
||||
continue;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n == 0 && (rw & 1))
|
||||
return 0;
|
||||
|
||||
done += n;
|
||||
while ((size_t)done >= iov[cur].iov_len)
|
||||
done -= iov[cur++].iov_len;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int read_write(int fd, unsigned char *packet, int size, int rw)
|
||||
{
|
||||
struct iovec iov;
|
||||
|
||||
/* size == 0 is not an error, just a NOOP. */
|
||||
if (size == 0)
|
||||
return 1;
|
||||
|
||||
iov.iov_len = (size_t)size;
|
||||
iov.iov_base = packet;
|
||||
|
||||
return read_writev(fd, &iov, 1, rw);
|
||||
}
|
||||
|
||||
/* close all fds except STDIN, STDOUT and STDERR, spare1, spare2 and spare3 */
|
||||
void close_fds(long max_fd, int spare1, int spare2, int spare3)
|
||||
{
|
||||
@@ -949,3 +946,42 @@ int kernel_version(void)
|
||||
return version * 256 + (split ? atoi(split) : 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff)
|
||||
|
||||
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
|
||||
{
|
||||
void *ret = calloc(1, size);
|
||||
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size);
|
||||
else if (daemon->log_malloc)
|
||||
my_syslog(LOG_INFO, _("malloc: %s:%u %zu bytes at %x"), func, line, size, hash_ptr(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size)
|
||||
{
|
||||
unsigned int old = hash_ptr(ptr);
|
||||
void *ret = realloc(ptr, size);
|
||||
|
||||
if (!ret)
|
||||
my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size);
|
||||
else if (daemon->log_malloc)
|
||||
my_syslog(LOG_INFO, _("realloc: %s:%u %zu bytes from %x to %x"), func, line, size, old, hash_ptr(ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#undef free
|
||||
void free_real(const char *func, unsigned int line, void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
if (daemon->log_malloc)
|
||||
my_syslog(LOG_INFO, _("free: %s:%u block at %x"), func, line, hash_ptr(ptr));
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user