resolved: add flags to DnsQuestion items
authorSergey Bugaev <bugaevc@gmail.com>
Sat, 20 Feb 2021 14:32:24 +0000 (17:32 +0300)
committerSergey Bugaev <bugaevc@gmail.com>
Wed, 31 Mar 2021 09:54:05 +0000 (12:54 +0300)
This adds DnsQuestionItem, which is to DnsQuestion what DnsAnswerItem is to
DnsAnswer.

No functional change.

src/resolve/resolved-bus.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-question.c
src/resolve/resolved-dns-question.h
src/resolve/resolved-dns-scope.c
src/resolve/resolved-dns-stub.c
src/resolve/resolved-dns-transaction.h

index c3624669ce18b954fb29890bce42c936ce4005cd..4c9c9a47e606797fa4547415be354108473371c6 100644 (file)
@@ -765,7 +765,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
         if (!key)
                 return -ENOMEM;
 
-        r = dns_question_add(question, key);
+        r = dns_question_add(question, key, 0);
         if (r < 0)
                 return r;
 
index 8de407d21aed6c243668b7c6e46cb22b23101cf5..ab1b658237277dd7aeffadfb982baffa2f1c0da4 100644 (file)
@@ -2240,7 +2240,7 @@ static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question)
                                 /* Already in the Question, let's skip */
                                 continue;
 
-                        r = dns_question_add_raw(question, key);
+                        r = dns_question_add_raw(question, key, 0);
                         if (r < 0)
                                 return r;
                 }
@@ -2451,7 +2451,7 @@ int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
         if (p->question->n_keys != 1)
                 return 0;
 
-        return dns_resource_key_equal(p->question->keys[0], key);
+        return dns_resource_key_equal(dns_question_first_key(p->question), key);
 }
 
 int dns_packet_patch_max_udp_size(DnsPacket *p, uint16_t max_udp_size) {
index fce676e02a3e2c2d6c4db925e2ba63c379594b0b..b429c452740a7f7c41d336b090eb5f3d9983a14a 100644 (file)
@@ -232,7 +232,7 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) {
 
                 assert(dns_question_size(c->query->question_bypass->question) == 1);
 
-                if (!dns_scope_good_key(c->scope, c->query->question_bypass->question->keys[0]))
+                if (!dns_scope_good_key(c->scope, dns_question_first_key(c->query->question_bypass->question)))
                         return 0;
 
                 r = dns_query_candidate_add_transaction(c, NULL, c->query->question_bypass);
@@ -503,7 +503,7 @@ int dns_query_new(
 
                 /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
                 DNS_QUESTION_FOREACH(key, question_idna) {
-                        r = dns_question_contains(question_utf8, key);
+                        r = dns_question_contains_key(question_utf8, key);
                         if (r < 0)
                                 return r;
                         if (r > 0)
index ef40932630407471787b1f5d27802f6a1ad37b73..aefdaa0eeb76f53147848fddb3f0aa61620ae775 100644 (file)
@@ -11,7 +11,7 @@ DnsQuestion *dns_question_new(size_t n) {
         if (n > UINT16_MAX) /* We can only place 64K key in an question section at max */
                 n = UINT16_MAX;
 
-        q = malloc0(offsetof(DnsQuestion, keys) + sizeof(DnsResourceKey*) * n);
+        q = malloc0(offsetof(DnsQuestion, items) + sizeof(DnsQuestionItem) * n);
         if (!q)
                 return NULL;
 
@@ -22,18 +22,19 @@ DnsQuestion *dns_question_new(size_t n) {
 }
 
 static DnsQuestion *dns_question_free(DnsQuestion *q) {
-        size_t i;
+        DnsResourceKey *key;
 
         assert(q);
 
-        for (i = 0; i < q->n_keys; i++)
-                dns_resource_key_unref(q->keys[i]);
+        DNS_QUESTION_FOREACH(key, q)
+                dns_resource_key_unref(key);
+
         return mfree(q);
 }
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion, dns_question, dns_question_free);
 
-int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key) {
+int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key, DnsQuestionFlags flags) {
         /* Insert without checking for duplicates. */
 
         assert(key);
@@ -42,11 +43,15 @@ int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key) {
         if (q->n_keys >= q->n_allocated)
                 return -ENOSPC;
 
-        q->keys[q->n_keys++] = dns_resource_key_ref(key);
+        q->items[q->n_keys++] = (DnsQuestionItem) {
+                .key = dns_resource_key_ref(key),
+                .flags = flags,
+        };
         return 0;
 }
 
-int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
+int dns_question_add(DnsQuestion *q, DnsResourceKey *key, DnsQuestionFlags flags) {
+        DnsQuestionItem *item;
         int r;
 
         assert(key);
@@ -54,19 +59,20 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
         if (!q)
                 return -ENOSPC;
 
-        for (size_t i = 0; i < q->n_keys; i++) {
-                r = dns_resource_key_equal(q->keys[i], key);
+
+        DNS_QUESTION_FOREACH_ITEM(item, q) {
+                r = dns_resource_key_equal(item->key, key);
                 if (r < 0)
                         return r;
-                if (r > 0)
+                if (r > 0 && item->flags == flags)
                         return 0;
         }
 
-        return dns_question_add_raw(q, key);
+        return dns_question_add_raw(q, key, flags);
 }
 
 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
-        size_t i;
+        DnsResourceKey *key;
         int r;
 
         assert(rr);
@@ -74,8 +80,8 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *s
         if (!q)
                 return 0;
 
-        for (i = 0; i < q->n_keys; i++) {
-                r = dns_resource_key_match_rr(q->keys[i], rr, search_domain);
+        DNS_QUESTION_FOREACH(key, q) {
+                r = dns_resource_key_match_rr(key, rr, search_domain);
                 if (r != 0)
                         return r;
         }
@@ -84,7 +90,7 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *s
 }
 
 int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
-        size_t i;
+        DnsResourceKey *key;
         int r;
 
         assert(rr);
@@ -95,12 +101,12 @@ int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, c
         if (!IN_SET(rr->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME))
                 return 0;
 
-        for (i = 0; i < q->n_keys; i++) {
+        DNS_QUESTION_FOREACH(key, q) {
                 /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */
-                if (!dns_type_may_redirect(q->keys[i]->type))
+                if (!dns_type_may_redirect(key->type))
                         return 0;
 
-                r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain);
+                r = dns_resource_key_match_cname_or_dname(key, rr->key, search_domain);
                 if (r != 0)
                         return r;
         }
@@ -122,38 +128,39 @@ int dns_question_is_valid_for_query(DnsQuestion *q) {
         if (q->n_keys > 65535)
                 return 0;
 
-        name = dns_resource_key_name(q->keys[0]);
+        name = dns_resource_key_name(q->items[0].key);
         if (!name)
                 return 0;
 
         /* Check that all keys in this question bear the same name */
         for (i = 0; i < q->n_keys; i++) {
-                assert(q->keys[i]);
+                assert(q->items[i].key);
 
                 if (i > 0) {
-                        r = dns_name_equal(dns_resource_key_name(q->keys[i]), name);
+                        r = dns_name_equal(dns_resource_key_name(q->items[i].key), name);
                         if (r <= 0)
                                 return r;
                 }
 
-                if (!dns_type_is_valid_query(q->keys[i]->type))
+                if (!dns_type_is_valid_query(q->items[i].key->type))
                         return 0;
         }
 
         return 1;
 }
 
-int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) {
+int dns_question_contains_key(DnsQuestion *q, const DnsResourceKey *k) {
         size_t j;
         int r;
 
         assert(k);
 
-        if (!a)
+        if (!q)
                 return 0;
 
-        for (j = 0; j < a->n_keys; j++) {
-                r = dns_resource_key_equal(a->keys[j], k);
+
+        for (j = 0; j < q->n_keys; j++) {
+                r = dns_resource_key_equal(q->items[j].key, k);
                 if (r != 0)
                         return r;
         }
@@ -161,8 +168,25 @@ int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) {
         return 0;
 }
 
+static int dns_question_contains_item(DnsQuestion *q, const DnsQuestionItem *i) {
+        DnsQuestionItem *item;
+        int r;
+
+        assert(i);
+
+        DNS_QUESTION_FOREACH_ITEM(item, q) {
+                if (item->flags != i->flags)
+                        continue;
+                r = dns_resource_key_equal(item->key, i->key);
+                if (r != 0)
+                        return r;
+        }
+
+        return false;
+}
+
 int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
-        size_t j;
+        DnsQuestionItem *item;
         int r;
 
         if (a == b)
@@ -173,16 +197,15 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
         if (!b)
                 return a->n_keys == 0;
 
-        /* Checks if all keys in a are also contained b, and vice versa */
+        /* Checks if all items in a are also contained b, and vice versa */
 
-        for (j = 0; j < a->n_keys; j++) {
-                r = dns_question_contains(b, a->keys[j]);
+        DNS_QUESTION_FOREACH_ITEM(item, a) {
+                r = dns_question_contains_item(b, item);
                 if (r <= 0)
                         return r;
         }
-
-        for (j = 0; j < b->n_keys; j++) {
-                r = dns_question_contains(a, b->keys[j]);
+        DNS_QUESTION_FOREACH_ITEM(item, b) {
+                r = dns_question_contains_item(a, item);
                 if (r <= 0)
                         return r;
         }
@@ -249,7 +272,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
                 if (!k)
                         return -ENOMEM;
 
-                r = dns_question_add(n, k);
+                r = dns_question_add(n, k, 0);
                 if (r < 0)
                         return r;
         }
@@ -267,7 +290,7 @@ const char *dns_question_first_name(DnsQuestion *q) {
         if (q->n_keys < 1)
                 return NULL;
 
-        return dns_resource_key_name(q->keys[0]);
+        return dns_resource_key_name(q->items[0].key);
 }
 
 int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool convert_idna) {
@@ -306,7 +329,7 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
                 if (!key)
                         return -ENOMEM;
 
-                r = dns_question_add(q, key);
+                r = dns_question_add(q, key, 0);
                 if (r < 0)
                         return r;
         }
@@ -318,7 +341,7 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
                 if (!key)
                         return -ENOMEM;
 
-                r = dns_question_add(q, key);
+                r = dns_question_add(q, key, 0);
                 if (r < 0)
                         return r;
         }
@@ -354,7 +377,7 @@ int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_
 
         reverse = NULL;
 
-        r = dns_question_add(q, key);
+        r = dns_question_add(q, key, 0);
         if (r < 0)
                 return r;
 
@@ -426,7 +449,7 @@ int dns_question_new_service(
         if (!key)
                 return -ENOMEM;
 
-        r = dns_question_add(q, key);
+        r = dns_question_add(q, key, 0);
         if (r < 0)
                 return r;
 
@@ -436,7 +459,7 @@ int dns_question_new_service(
                 if (!key)
                         return -ENOMEM;
 
-                r = dns_question_add(q, key);
+                r = dns_question_add(q, key, 0);
                 if (r < 0)
                         return r;
         }
index 8f9a84c82d936d6e088a118febfddca6a4121f04..31b8a2ec3efc3772156d3ab1f9df1d1feeffd479 100644 (file)
@@ -2,16 +2,26 @@
 #pragma once
 
 typedef struct DnsQuestion DnsQuestion;
+typedef struct DnsQuestionItem DnsQuestionItem;
 
 #include "macro.h"
 #include "resolved-dns-rr.h"
 
 /* A simple array of resource keys */
 
+typedef enum DnsQuestionFlags {
+        DNS_QUESTION_WANTS_UNICAST_REPLY = 1 << 0, /* For mDNS: sender is willing to accept unicast replies */
+} DnsQuestionFlags;
+
+struct DnsQuestionItem {
+        DnsResourceKey *key;
+        DnsQuestionFlags flags;
+};
+
 struct DnsQuestion {
         unsigned n_ref;
         size_t n_keys, n_allocated;
-        DnsResourceKey* keys[0];
+        DnsQuestionItem items[0];
 };
 
 DnsQuestion *dns_question_new(size_t n);
@@ -22,13 +32,13 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
 int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a);
 int dns_question_new_service(DnsQuestion **ret, const char *service, const char *type, const char *domain, bool with_txt, bool convert_idna);
 
-int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key);
-int dns_question_add(DnsQuestion *q, DnsResourceKey *key);
+int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key, DnsQuestionFlags flags);
+int dns_question_add(DnsQuestion *q, DnsResourceKey *key, DnsQuestionFlags flags);
 
 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain);
 int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char* search_domain);
 int dns_question_is_valid_for_query(DnsQuestion *q);
-int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k);
+int dns_question_contains_key(DnsQuestion *q, const DnsResourceKey *k);
 int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b);
 
 int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret);
@@ -37,6 +47,10 @@ void dns_question_dump(DnsQuestion *q, FILE *f);
 
 const char *dns_question_first_name(DnsQuestion *q);
 
+static inline DnsResourceKey *dns_question_first_key(DnsQuestion *q) {
+        return (q && q->n_keys > 0) ? q->items[0].key : NULL;
+}
+
 static inline size_t dns_question_size(DnsQuestion *q) {
         return q ? q->n_keys : 0;
 }
@@ -47,12 +61,22 @@ static inline bool dns_question_isempty(DnsQuestion *q) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref);
 
-#define _DNS_QUESTION_FOREACH(u, key, q)                                \
-        for (size_t UNIQ_T(i, u) = ({                                 \
-                                (key) = ((q) && (q)->n_keys > 0) ? (q)->keys[0] : NULL; \
-                                0;                                      \
-                        });                                             \
-             (q) && (UNIQ_T(i, u) < (q)->n_keys);                       \
-             UNIQ_T(i, u)++, (key) = (UNIQ_T(i, u) < (q)->n_keys ? (q)->keys[UNIQ_T(i, u)] : NULL))
+#define _DNS_QUESTION_FOREACH(u, k, q)                                     \
+        for (size_t UNIQ_T(i, u) = ({                                      \
+                                (k) = ((q) && (q)->n_keys > 0) ? (q)->items[0].key : NULL; \
+                                0;                                         \
+                        });                                                \
+             (q) && (UNIQ_T(i, u) < (q)->n_keys);                          \
+             UNIQ_T(i, u)++, (k) = (UNIQ_T(i, u) < (q)->n_keys ? (q)->items[UNIQ_T(i, u)].key : NULL))
 
 #define DNS_QUESTION_FOREACH(key, q) _DNS_QUESTION_FOREACH(UNIQ, key, q)
+
+#define _DNS_QUESTION_FOREACH_ITEM(u, item, q)                             \
+        for (size_t UNIQ_T(i, u) = ({                                      \
+                     (item) = dns_question_isempty(q) ? NULL : (q)->items; \
+                     0;                                                    \
+             });                                                           \
+             UNIQ_T(i, u) < dns_question_size(q);                          \
+             UNIQ_T(i, u)++, (item) = (UNIQ_T(i, u) < dns_question_size(q) ? (q)->items + UNIQ_T(i, u) : NULL))
+
+#define DNS_QUESTION_FOREACH_ITEM(item, q) _DNS_QUESTION_FOREACH_ITEM(UNIQ, item, q)
index 67c6f54dc5d9f17dbc47544240fc866961b567d2..09f25a65b9ea1fa064817edab21a1194735d9843 100644 (file)
@@ -984,7 +984,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
         }
 
         assert(dns_question_size(p->question) == 1);
-        key = p->question->keys[0];
+        key = dns_question_first_key(p->question);
 
         r = dns_zone_lookup(&s->zone, key, 0, &answer, &soa, &tentative);
         if (r < 0) {
index 602720bf505d6decee5845c2b9953e9cf3076e45..6846eb2dbd21659f85f13773765a71c260123cbb 100644 (file)
@@ -879,13 +879,13 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
                 return;
         }
 
-        if (dns_type_is_obsolete(p->question->keys[0]->type)) {
+        if (dns_type_is_obsolete(dns_question_first_key(p->question)->type)) {
                 log_debug("Got message with obsolete key type, refusing.");
                 dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
                 return;
         }
 
-        if (dns_type_is_zone_transer(p->question->keys[0]->type)) {
+        if (dns_type_is_zone_transer(dns_question_first_key(p->question)->type)) {
                 log_debug("Got request for zone transfer, refusing.");
                 dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
                 return;
index a8ec6e18d5cafa68ca54ae806ddbd1716496d45e..c2d73cbedc5dac6a9ce473f4da0bf0f9ae5e1801 100644 (file)
@@ -166,10 +166,7 @@ static inline DnsResourceKey *dns_transaction_key(DnsTransaction *t) {
 
         assert(t->bypass);
 
-        if (dns_question_isempty(t->bypass->question))
-                return NULL;
-
-        return t->bypass->question->keys[0];
+        return dns_question_first_key(t->bypass->question);
 }
 
 static inline uint64_t dns_transaction_source_to_query_flags(DnsTransactionSource s) {