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;
}
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);
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);
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);
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;
}
}
int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
- size_t i;
+ DnsResourceKey *key;
int r;
assert(rr);
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;
}
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;
}
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)
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;
}
if (!k)
return -ENOMEM;
- r = dns_question_add(n, k);
+ r = dns_question_add(n, k, 0);
if (r < 0)
return r;
}
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) {
if (!key)
return -ENOMEM;
- r = dns_question_add(q, key);
+ r = dns_question_add(q, key, 0);
if (r < 0)
return r;
}
if (!key)
return -ENOMEM;
- r = dns_question_add(q, key);
+ r = dns_question_add(q, key, 0);
if (r < 0)
return r;
}
reverse = NULL;
- r = dns_question_add(q, key);
+ r = dns_question_add(q, key, 0);
if (r < 0)
return r;
if (!key)
return -ENOMEM;
- r = dns_question_add(q, key);
+ r = dns_question_add(q, key, 0);
if (r < 0)
return r;
if (!key)
return -ENOMEM;
- r = dns_question_add(q, key);
+ r = dns_question_add(q, key, 0);
if (r < 0)
return r;
}
#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);
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);
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;
}
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)