summaryrefslogtreecommitdiff
path: root/src/resolve/resolved-dns-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/resolved-dns-server.c')
-rw-r--r--src/resolve/resolved-dns-server.c96
1 files changed, 53 insertions, 43 deletions
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 5acfcb4239..9b7b471600 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -21,6 +21,7 @@
#include "alloc-util.h"
#include "resolved-dns-server.h"
+#include "resolved-dns-stub.h"
#include "resolved-resolv-conf.h"
#include "siphash24.h"
#include "string-table.h"
@@ -244,6 +245,26 @@ static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) {
assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0);
}
+static void dns_server_reset_counters(DnsServer *s) {
+ assert(s);
+
+ s->n_failed_udp = 0;
+ s->n_failed_tcp = 0;
+ s->packet_truncated = false;
+ s->verified_usec = 0;
+
+ /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the
+ * grace period ends, but not when lowering the possible feature level, as a lower level feature level should
+ * not make RRSIGs appear or OPT appear, but rather make them disappear. If the reappear anyway, then that's
+ * indication for a differently broken OPT/RRSIG implementation, and we really don't want to support that
+ * either.
+ *
+ * This is particularly important to deal with certain Belkin routers which break OPT for certain lookups (A),
+ * but pass traffic through for others (AAAA). If we detect the broken behaviour on one lookup we should not
+ * reenable it for another, because we cannot validate things anyway, given that the RRSIG/OPT data will be
+ * incomplete. */
+}
+
void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size) {
assert(s);
@@ -304,17 +325,6 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le
s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
}
-void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level) {
- assert(s);
-
- /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */
-
- if (s->possible_feature_level != level)
- return;
-
- s->packet_failed = true;
-}
-
void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level) {
assert(s);
@@ -352,6 +362,24 @@ void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level) {
s->packet_bad_opt = true;
}
+void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level) {
+ assert(s);
+
+ /* Invoked whenever we got a FORMERR, SERVFAIL or NOTIMP rcode from a server and downgrading the feature level
+ * for the transaction made it go away. In this case we immediately downgrade to the feature level that made
+ * things work. */
+
+ if (s->verified_feature_level > level)
+ s->verified_feature_level = level;
+
+ if (s->possible_feature_level > level) {
+ s->possible_feature_level = level;
+ dns_server_reset_counters(s);
+ }
+
+ log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", dns_server_string(s));
+}
+
static bool dns_server_grace_period_expired(DnsServer *s) {
usec_t ts;
@@ -371,27 +399,6 @@ static bool dns_server_grace_period_expired(DnsServer *s) {
return true;
}
-static void dns_server_reset_counters(DnsServer *s) {
- assert(s);
-
- s->n_failed_udp = 0;
- s->n_failed_tcp = 0;
- s->packet_failed = false;
- s->packet_truncated = false;
- s->verified_usec = 0;
-
- /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the
- * grace period ends, but not when lowering the possible feature level, as a lower level feature level should
- * not make RRSIGs appear or OPT appear, but rather make them disappear. If the reappear anyway, then that's
- * indication for a differently broken OPT/RRSIG implementation, and we really don't want to support that
- * either.
- *
- * This is particularly important to deal with certain Belkin routers which break OPT for certain lookups (A),
- * but pass traffic through for others (AAAA). If we detect the broken behaviour on one lookup we should not
- * reenable it for another, because we cannot validate things anyway, given that the RRSIG/OPT data will be
- * incomplete. */
-}
-
DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
assert(s);
@@ -454,16 +461,6 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) {
log_debug("Lost too many UDP packets, downgrading feature level...");
s->possible_feature_level--;
- } else if (s->packet_failed &&
- s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) {
-
- /* We got a failure packet, and are at a feature level above UDP. Note that in this case we
- * downgrade no further than UDP, under the assumption that a failure packet indicates an
- * incompatible packet contents, but not a problem with the transport. */
-
- log_debug("Got server failure, downgrading feature level...");
- s->possible_feature_level--;
-
} else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS &&
s->packet_truncated &&
s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) {
@@ -517,7 +514,7 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature
else
packet_size = server->received_udp_packet_max;
- return dns_packet_append_opt(packet, packet_size, edns_do, NULL);
+ return dns_packet_append_opt(packet, packet_size, edns_do, 0, NULL);
}
int dns_server_ifindex(const DnsServer *s) {
@@ -750,6 +747,19 @@ void manager_next_dns_server(Manager *m) {
manager_set_dns_server(m, m->dns_servers);
}
+bool dns_server_address_valid(int family, const union in_addr_union *sa) {
+
+ /* Refuses the 0 IP addresses as well as 127.0.0.53 (which is our own DNS stub) */
+
+ if (in_addr_is_null(family, sa))
+ return false;
+
+ if (family == AF_INET && sa->in.s_addr == htobe32(INADDR_DNS_STUB))
+ return false;
+
+ return true;
+}
+
static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = {
[DNS_SERVER_SYSTEM] = "system",
[DNS_SERVER_FALLBACK] = "fallback",