resolve: generate a nice clean error when clients try to resolve a name when the...
authorLennart Poettering <lennart@poettering.net>
Wed, 20 Jan 2016 20:28:22 +0000 (21:28 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Jan 2016 14:59:40 +0000 (15:59 +0100)
src/libsystemd/sd-bus/bus-common-errors.c
src/libsystemd/sd-bus/bus-common-errors.h
src/resolve/resolved-bus.c
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-scope.h
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-transaction.h

index 9ddc9b5..e344b3b 100644 (file)
@@ -80,6 +80,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_RR_TYPE_UNSUPPORTED,          EOPNOTSUPP),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_LINK,                 ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY,                    EBUSY),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN,                 ENETDOWN),
 
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER,             ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS,         EBUSY),
index e93b6ac..130779e 100644 (file)
@@ -79,6 +79,7 @@
 #define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported"
 #define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink"
 #define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy"
+#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown"
 #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError."
 
 #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer"
index 9110ea5..66c2c25 100644 (file)
@@ -59,6 +59,9 @@ static int reply_query_state(DnsQuery *q) {
         case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED:
                 return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type");
 
+        case DNS_TRANSACTION_NETWORK_DOWN:
+                return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down");
+
         case DNS_TRANSACTION_RCODE_FAILURE: {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
index fc5bf40..165a52f 100644 (file)
@@ -891,7 +891,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
                     DNS_TRANSACTION_RCODE_FAILURE,
                     DNS_TRANSACTION_NO_SERVERS,
                     DNS_TRANSACTION_TIMEOUT,
-                    DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
+                    DNS_TRANSACTION_ATTEMPTS_MAX_REACHED,
+                    DNS_TRANSACTION_NETWORK_DOWN))
                 return 0;
 
         DNS_QUESTION_FOREACH(key, q->question_utf8) {
index 8a52d66..ac4887a 100644 (file)
@@ -1015,3 +1015,22 @@ bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) {
 
         return dns_name_is_single_label(name);
 }
+
+bool dns_scope_network_good(DnsScope *s) {
+        Iterator i;
+        Link *l;
+
+        /* Checks whether the network is in good state for lookups on this scope. For mDNS/LLMNR/Classic DNS scopes
+         * bound to links this is easy, as they don't even exist if the link isn't in a suitable state. For the global
+         * DNS scope we check whether there are any links that are up and have an address. */
+
+        if (s->link)
+                return true;
+
+        HASHMAP_FOREACH(l, s->manager->links, i) {
+                if (link_relevant(l, AF_UNSPEC, false))
+                        return true;
+        }
+
+        return false;
+}
index a0676bd..f9b63d5 100644 (file)
@@ -107,3 +107,5 @@ void dns_scope_dump(DnsScope *s, FILE *f);
 DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s);
 
 bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name);
+
+bool dns_scope_network_good(DnsScope *s);
index 5640cd1..d485cd9 100644 (file)
@@ -1094,6 +1094,14 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
 
         dns_transaction_stop_timeout(t);
 
+        r = dns_scope_network_good(t->scope);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                dns_transaction_complete(t, DNS_TRANSACTION_NETWORK_DOWN);
+                return 0;
+        }
+
         if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {
                 dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);
                 return 0;
@@ -2969,6 +2977,7 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX]
         [DNS_TRANSACTION_DNSSEC_FAILED] = "dnssec-failed",
         [DNS_TRANSACTION_NO_TRUST_ANCHOR] = "no-trust-anchor",
         [DNS_TRANSACTION_RR_TYPE_UNSUPPORTED] = "rr-type-unsupported",
+        [DNS_TRANSACTION_NETWORK_DOWN] = "network-down",
 };
 DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState);
 
index 76cf6e7..80a2591 100644 (file)
@@ -40,6 +40,7 @@ enum DnsTransactionState {
         DNS_TRANSACTION_DNSSEC_FAILED,
         DNS_TRANSACTION_NO_TRUST_ANCHOR,
         DNS_TRANSACTION_RR_TYPE_UNSUPPORTED,
+        DNS_TRANSACTION_NETWORK_DOWN,
         _DNS_TRANSACTION_STATE_MAX,
         _DNS_TRANSACTION_STATE_INVALID = -1
 };