}
static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
- int c = 0, r, ifindex;
+ int c = 0, r;
assert(m);
assert(canonical);
- r = sd_bus_message_read(m, "i", &ifindex);
+ r = sd_bus_message_enter_container(m, 'a', "(iiay)");
if (r < 0)
return r;
- r = sd_bus_message_enter_container(m, 'a', "(iay)");
- if (r < 0)
- return r;
+ while ((r = sd_bus_message_enter_container(m, 'r', "iiay")) > 0) {
+ int family, ifindex;
- while ((r = sd_bus_message_enter_container(m, 'r', "iay")) > 0) {
- int family;
+ assert_cc(sizeof(int32_t) == sizeof(int));
- r = sd_bus_message_read(m, "i", &family);
+ r = sd_bus_message_read(m, "ii", &ifindex, &family);
if (r < 0)
return r;
const char *canonical = NULL;
size_t l, ms, idx;
char *r_name;
- int c, r, i = 0, ifindex;
+ int c, r, i = 0;
assert(name);
assert(pat);
/* Second, append addresses */
r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
- r = sd_bus_message_read(reply, "i", &ifindex);
- if (r < 0)
- goto fail;
-
- if (ifindex < 0) {
- r = -EINVAL;
- goto fail;
- }
-
- r = sd_bus_message_enter_container(reply, 'a', "(iay)");
+ r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
if (r < 0)
goto fail;
- while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
- int family;
+ while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
+ int family, ifindex;
const void *a;
size_t sz;
- r = sd_bus_message_read(reply, "i", &family);
+ assert_cc(sizeof(int32_t) == sizeof(int));
+
+ r = sd_bus_message_read(reply, "ii", &ifindex, &family);
if (r < 0)
goto fail;
+ if (ifindex < 0) {
+ r = -EINVAL;
+ goto fail;
+ }
+
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
if (r < 0)
goto fail;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
size_t l, idx, ms, alen;
const char *canonical;
- int c, r, i = 0, ifindex;
+ int c, r, i = 0;
assert(name);
assert(result);
/* Third, append addresses */
r_addr = buffer + idx;
- r = sd_bus_message_read(reply, "i", &ifindex);
- if (r < 0)
- goto fail;
-
- if (ifindex < 0) {
- r = -EINVAL;
- goto fail;
- }
-
- r = sd_bus_message_enter_container(reply, 'a', "(iay)");
+ r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
if (r < 0)
goto fail;
- while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
- int family;
+ while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
+ int ifindex, family;
const void *a;
size_t sz;
- r = sd_bus_message_read(reply, "i", &family);
+ r = sd_bus_message_read(reply, "ii", &ifindex, &family);
if (r < 0)
goto fail;
+ if (ifindex < 0) {
+ r = -EINVAL;
+ goto fail;
+ }
+
r = sd_bus_message_read_array(reply, 'y', &a, &sz);
if (r < 0)
goto fail;
return NSS_STATUS_UNAVAIL;
}
- r = sd_bus_message_read(reply, "i", &ifindex);
+ r = sd_bus_message_enter_container(reply, 'a', "(is)");
if (r < 0)
goto fail;
- if (ifindex < 0) {
- r = -EINVAL;
- goto fail;
- }
+ while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
- r = sd_bus_message_enter_container(reply, 'a', "s");
- if (r < 0)
- goto fail;
+ if (ifindex < 0) {
+ r = -EINVAL;
+ goto fail;
+ }
- while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
c++;
ms += ALIGN(strlen(n) + 1);
}
/* Fourth, place aliases */
i = 0;
r_name = buffer + idx;
- while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
+ while ((r = sd_bus_message_read(reply, "(is)", &ifindex, &n)) > 0) {
char *p;
size_t l;
static bool arg_legend = true;
static uint64_t arg_flags = 0;
-static void print_source(int ifindex, uint64_t flags, usec_t rtt) {
+static void print_source(uint64_t flags, usec_t rtt) {
char rtt_str[FORMAT_TIMESTAMP_MAX];
if (!arg_legend)
return;
- if (ifindex <= 0 && flags == 0)
+ if (flags == 0)
return;
fputs("\n-- Information acquired via", stdout);
flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "");
- if (ifindex > 0) {
- char ifname[IF_NAMESIZE] = "";
- printf(" interface %s", strna(if_indextoname(ifindex, ifname)));
- }
-
assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
printf(" in %s", rtt_str);
_cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *canonical = NULL;
+ char ifname[IF_NAMESIZE] = "";
unsigned c = 0;
- int r, ifindex;
+ int r;
uint64_t flags;
usec_t ts;
assert(name);
- log_debug("Resolving %s (family %s, ifindex %i).", name, af_to_name(arg_family) ?: "*", arg_ifindex);
+ if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
+ return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
+
+ log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
r = sd_bus_message_new_method_call(
bus,
ts = now(CLOCK_MONOTONIC) - ts;
- r = sd_bus_message_read(reply, "i", &ifindex);
+ r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
if (r < 0)
return bus_log_parse_error(r);
- r = sd_bus_message_enter_container(reply, 'a', "(iay)");
- if (r < 0)
- return bus_log_parse_error(r);
-
- while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
+ while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
const void *a;
- int family;
size_t sz;
_cleanup_free_ char *pretty = NULL;
- char ifname[IF_NAMESIZE] = "";
+ int ifindex, family;
+
+ assert_cc(sizeof(int) == sizeof(int32_t));
- r = sd_bus_message_read(reply, "i", &family);
+ r = sd_bus_message_read(reply, "ii", &ifindex, &family);
if (r < 0)
return bus_log_parse_error(r);
}
if (sz != FAMILY_ADDRESS_SIZE(family)) {
- log_error("%s: systemd-resolved returned address of invalid size %zu for family %s",
- name, sz, af_to_name(family) ?: "unknown");
+ log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
continue;
}
- if (ifindex > 0) {
- char *t;
-
- t = if_indextoname(ifindex, ifname);
- if (!t) {
- log_error("Failed to resolve interface name for index %i", ifindex);
- continue;
- }
- }
+ ifname[0] = 0;
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
r = in_addr_to_string(family, a, &pretty);
- if (r < 0) {
- log_error_errno(r, "%s: failed to print address: %m", name);
- continue;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to print address for %s: %m", name);
printf("%*s%s %s%s%s\n",
(int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
return -ESRCH;
}
- print_source(ifindex, flags, ts);
+ print_source(flags, ts);
return 0;
}
char ifname[IF_NAMESIZE] = "";
uint64_t flags;
unsigned c = 0;
- const char *n;
usec_t ts;
int r;
assert(IN_SET(family, AF_INET, AF_INET6));
assert(address);
+ if (ifindex <= 0)
+ ifindex = arg_ifindex;
+
r = in_addr_to_string(family, address, &pretty);
if (r < 0)
return log_oom();
- if (ifindex > 0) {
- char *t;
-
- t = if_indextoname(ifindex, ifname);
- if (!t) {
- log_error("Failed to resolve interface name for index %i", ifindex);
- return -errno;
- }
- }
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_set_auto_start(req, false);
- if (r < 0)
- return bus_log_create_error(r);
-
r = sd_bus_message_append(req, "ii", ifindex, family);
if (r < 0)
return bus_log_create_error(r);
ts = now(CLOCK_MONOTONIC) - ts;
- r = sd_bus_message_read(reply, "i", &ifindex);
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_enter_container(reply, 'a', "s");
+ r = sd_bus_message_enter_container(reply, 'a', "(is)");
if (r < 0)
return bus_log_create_error(r);
- while ((r = sd_bus_message_read(reply, "s", &n)) > 0) {
+ while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
+ const char *n;
+
+ assert_cc(sizeof(int) == sizeof(int32_t));
- printf("%*s%s%s%s %s\n",
+ r = sd_bus_message_read(reply, "is", &ifindex, &n);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ ifname[0] = 0;
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+
+ printf("%*s%*s%*s%s %s\n",
(int) strlen(pretty), c == 0 ? pretty : "",
- isempty(ifname) ? "" : "%", ifname,
+ isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
+ (int) strlen(ifname), c == 0 ? ifname : "",
c == 0 ? ":" : " ",
n);
return -ESRCH;
}
- print_source(ifindex, flags, ts);
+ print_source(flags, ts);
return 0;
}
_cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char ifname[IF_NAMESIZE] = "";
unsigned n = 0;
uint64_t flags;
- int r, ifindex;
+ int r;
usec_t ts;
assert(name);
- log_debug("Resolving %s %s %s.", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type));
+ if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
+ return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
+
+ log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type), isempty(ifname) ? "*" : ifname);
r = sd_bus_message_new_method_call(
bus,
ts = now(CLOCK_MONOTONIC) - ts;
- r = sd_bus_message_read(reply, "i", &ifindex);
+ r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
if (r < 0)
return bus_log_parse_error(r);
- r = sd_bus_message_enter_container(reply, 'a', "(qqay)");
- if (r < 0)
- return bus_log_parse_error(r);
-
- while ((r = sd_bus_message_enter_container(reply, 'r', "qqay")) > 0) {
+ while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
_cleanup_free_ char *s = NULL;
uint16_t c, t;
+ int ifindex;
const void *d;
size_t l;
- r = sd_bus_message_read(reply, "qq", &c, &t);
+ assert_cc(sizeof(int) == sizeof(int32_t));
+
+ r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
if (r < 0)
return bus_log_parse_error(r);
return r;
}
- printf("%s\n", s);
+ ifname[0] = 0;
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+
+ printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
n++;
}
if (r < 0)
return -ESRCH;
}
- print_source(ifindex, flags, ts);
+ print_source(flags, ts);
return 0;
}
}
}
-static int append_address(sd_bus_message *reply, DnsResourceRecord *rr) {
+static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifindex) {
int r;
assert(reply);
assert(rr);
- r = sd_bus_message_open_container(reply, 'r', "iay");
+ r = sd_bus_message_open_container(reply, 'r', "iiay");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "i", ifindex);
if (r < 0)
return r;
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "i", q->answer_ifindex);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_open_container(reply, 'a', "(iay)");
+ r = sd_bus_message_open_container(reply, 'a', "(iiay)");
if (r < 0)
goto finish;
answer = dns_answer_ref(q->answer);
for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->rrs[i]);
+ r = dns_question_matches_rr(q->question, answer->items[i].rr);
if (r < 0)
goto finish;
if (r == 0) {
/* Hmm, if this is not an address record,
maybe it's a cname? If so, remember this */
- r = dns_question_matches_cname(q->question, answer->rrs[i]);
+ r = dns_question_matches_cname(q->question, answer->items[i].rr);
if (r < 0)
goto finish;
if (r > 0)
- cname = dns_resource_record_ref(answer->rrs[i]);
+ cname = dns_resource_record_ref(answer->items[i].rr);
continue;
}
- r = append_address(reply, answer->rrs[i]);
+ r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
if (r < 0)
goto finish;
if (!canonical)
- canonical = dns_resource_record_ref(answer->rrs[i]);
+ canonical = dns_resource_record_ref(answer->items[i].rr);
added ++;
}
/* Before we restart the query, let's see if any of
* the RRs we already got already answers our query */
for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->rrs[i]);
+ r = dns_question_matches_rr(q->question, answer->items[i].rr);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = append_address(reply, answer->rrs[i]);
+ r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex);
if (r < 0)
goto finish;
if (!canonical)
- canonical = dns_resource_record_ref(answer->rrs[i]);
+ canonical = dns_resource_record_ref(answer->items[i].rr);
added++;
}
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "i", q->answer_ifindex);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_open_container(reply, 'a', "s");
+ r = sd_bus_message_open_container(reply, 'a', "(is)");
if (r < 0)
goto finish;
answer = dns_answer_ref(q->answer);
for (i = 0; i < answer->n_rrs; i++) {
- r = dns_question_matches_rr(q->question, answer->rrs[i]);
+ r = dns_question_matches_rr(q->question, answer->items[i].rr);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = sd_bus_message_append(reply, "s", answer->rrs[i]->ptr.name);
+ r = sd_bus_message_append(reply, "(is)", answer->items[i].ifindex, answer->items[i].rr->ptr.name);
if (r < 0)
goto finish;
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "i", q->answer_ifindex);
- if (r < 0)
- goto finish;
-
- r = sd_bus_message_open_container(reply, 'a', "(qqay)");
+ r = sd_bus_message_open_container(reply, 'a', "(iqqay)");
if (r < 0)
goto finish;
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
size_t start;
- r = dns_question_matches_rr(q->question, answer->rrs[i]);
+ r = dns_question_matches_rr(q->question, answer->items[i].rr);
if (r < 0)
goto finish;
if (r == 0)
if (r < 0)
goto finish;
- r = dns_packet_append_rr(p, answer->rrs[i], &start);
+ r = dns_packet_append_rr(p, answer->items[i].rr, &start);
if (r < 0)
goto finish;
- r = sd_bus_message_open_container(reply, 'r', "qqay");
+ r = sd_bus_message_open_container(reply, 'r', "iqqay");
if (r < 0)
goto finish;
- r = sd_bus_message_append(reply, "qq", answer->rrs[i]->key->class, answer->rrs[i]->key->type);
+ r = sd_bus_message_append(reply, "iqq",
+ answer->items[i].ifindex,
+ answer->items[i].rr->key->class,
+ answer->items[i].rr->key->type);
if (r < 0)
goto finish;
static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("ResolveHostname", "isit", "ia(iay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResolveAddress", "iiayt", "iast", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResolveRecord", "isqqt", "ia(qqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END,
};
DnsAnswer *dns_answer_new(unsigned n) {
DnsAnswer *a;
- a = malloc0(offsetof(DnsAnswer, rrs) + sizeof(DnsResourceRecord*) * n);
+ a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n);
if (!a)
return NULL;
unsigned i;
for (i = 0; i < a->n_rrs; i++)
- dns_resource_record_unref(a->rrs[i]);
+ dns_resource_record_unref(a->items[i].rr);
free(a);
} else
return NULL;
}
-int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr) {
+int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex) {
unsigned i;
int r;
- assert(a);
assert(rr);
+ if (!a)
+ return -ENOSPC;
+
for (i = 0; i < a->n_rrs; i++) {
- r = dns_resource_record_equal(a->rrs[i], rr);
+ if (a->items[i].ifindex != ifindex)
+ continue;
+
+ r = dns_resource_record_equal(a->items[i].rr, rr);
if (r < 0)
return r;
if (r > 0) {
/* Entry already exists, keep the entry with
* the higher RR, or the one with TTL 0 */
- if (rr->ttl == 0 || (rr->ttl > a->rrs[i]->ttl && a->rrs[i]->ttl != 0)) {
+ if (rr->ttl == 0 || (rr->ttl > a->items[i].rr->ttl && a->items[i].rr->ttl != 0)) {
dns_resource_record_ref(rr);
- dns_resource_record_unref(a->rrs[i]);
- a->rrs[i] = rr;
+ dns_resource_record_unref(a->items[i].rr);
+ a->items[i].rr = rr;
}
return 0;
if (a->n_rrs >= a->n_allocated)
return -ENOSPC;
- a->rrs[a->n_rrs++] = dns_resource_record_ref(rr);
+ a->items[a->n_rrs].rr = dns_resource_record_ref(rr);
+ a->items[a->n_rrs].ifindex = ifindex;
+ a->n_rrs++;
+
return 1;
}
soa->soa.expire = 1;
soa->soa.minimum = ttl;
- return dns_answer_add(a, soa);
+ return dns_answer_add(a, soa, 0);
}
int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
unsigned i;
int r;
- assert(a);
assert(key);
+ if (!a)
+ return 0;
+
for (i = 0; i < a->n_rrs; i++) {
- r = dns_resource_key_match_rr(key, a->rrs[i]);
+ r = dns_resource_key_match_rr(key, a->items[i].rr);
if (r < 0)
return r;
if (r > 0)
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) {
unsigned i;
- assert(a);
assert(key);
assert(ret);
+ if (!a)
+ return 0;
+
/* For a SOA record we can never find a matching SOA record */
if (key->type == DNS_TYPE_SOA)
return 0;
for (i = 0; i < a->n_rrs; i++) {
- if (a->rrs[i]->key->class != DNS_CLASS_IN)
+ if (a->items[i].rr->key->class != DNS_CLASS_IN)
continue;
- if (a->rrs[i]->key->type != DNS_TYPE_SOA)
+ if (a->items[i].rr->key->type != DNS_TYPE_SOA)
continue;
- if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->rrs[i]->key))) {
- *ret = a->rrs[i];
+ if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->items[i].rr->key))) {
+ *ret = a->items[i].rr;
return 1;
}
}
if (a) {
for (i = 0; i < a->n_rrs; i++) {
- r = dns_answer_add(ret, a->rrs[i]);
+ r = dns_answer_add(ret, a->items[i].rr, a->items[i].ifindex);
if (r < 0)
return NULL;
}
if (b) {
for (i = 0; i < b->n_rrs; i++) {
- r = dns_answer_add(ret, b->rrs[i]);
+ r = dns_answer_add(ret, b->items[i].rr, b->items[i].ifindex);
if (r < 0)
return NULL;
}
}
void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
- DnsResourceRecord **rrs;
+ DnsAnswerItem *items;
unsigned i, start, end;
- assert(a);
+
+ if (!a)
+ return;
if (a->n_rrs <= 1)
return;
/* RFC 4795, Section 2.6 suggests we should order entries
* depending on whether the sender is a link-local address. */
- rrs = newa(DnsResourceRecord*, a->n_rrs);
+ items = newa(DnsAnswerItem, a->n_rrs);
for (i = 0; i < a->n_rrs; i++) {
- if (a->rrs[i]->key->class == DNS_CLASS_IN &&
- ((a->rrs[i]->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->rrs[i]->a.in_addr) != prefer_link_local) ||
- (a->rrs[i]->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->rrs[i]->aaaa.in6_addr) != prefer_link_local)))
+ if (a->items[i].rr->key->class == DNS_CLASS_IN &&
+ ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) ||
+ (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local)))
/* Order address records that are are not preferred to the end of the array */
- rrs[end--] = a->rrs[i];
+ items[end--] = a->items[i];
else
/* Order all other records to the beginning of the array */
- rrs[start++] = a->rrs[i];
+ items[start++] = a->items[i];
}
assert(start == end+1);
- memcpy(a->rrs, rrs, sizeof(DnsResourceRecord*) * a->n_rrs);
+ memcpy(a->items, items, sizeof(DnsAnswerItem) * a->n_rrs);
+}
+
+int dns_answer_reserve(DnsAnswer **a, unsigned n_free) {
+ DnsAnswer *n;
+
+ if (n_free <= 0)
+ return 0;
+
+ if (*a) {
+ unsigned ns;
+
+ if ((*a)->n_ref > 1)
+ return -EBUSY;
+
+ ns = (*a)->n_rrs + n_free;
+
+ if ((*a)->n_allocated >= ns)
+ return 0;
+
+ n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns);
+ if (!n)
+ return -ENOMEM;
+
+ n->n_allocated = ns;
+ } else {
+ n = dns_answer_new(n_free);
+ if (!n)
+ return -ENOMEM;
+ }
+
+ *a = n;
+ return 0;
}
***/
typedef struct DnsAnswer DnsAnswer;
+typedef struct DnsAnswerItem DnsAnswerItem;
#include "resolved-dns-rr.h"
-/* A simple array of resource records */
+/* A simple array of resource records. We keep track of the
+ * originating ifindex for each RR where that makes sense, so that we
+ * can qualify A and AAAA RRs referring to a local link with the
+ * right ifindex. */
+
+struct DnsAnswerItem {
+ DnsResourceRecord *rr;
+ int ifindex;
+};
struct DnsAnswer {
unsigned n_ref;
unsigned n_rrs, n_allocated;
- DnsResourceRecord* rrs[0];
+ DnsAnswerItem items[0];
};
DnsAnswer *dns_answer_new(unsigned n);
DnsAnswer *dns_answer_ref(DnsAnswer *a);
DnsAnswer *dns_answer_unref(DnsAnswer *a);
-int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr);
+int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex);
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl);
int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key);
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret);
DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b);
void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local);
+int dns_answer_reserve(DnsAnswer **a, unsigned n_free);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref);
return 0;
for (i = 0; i < answer->n_rrs; i++)
- dns_cache_remove(c, answer->rrs[i]->key);
+ dns_cache_remove(c, answer->items[i].rr->key);
/* We only care for positive replies and NXDOMAINs, on all
* other replies we will simply flush the respective entries,
/* Second, add in positive entries for all contained RRs */
for (i = 0; i < MIN(max_rrs, answer->n_rrs); i++) {
- r = dns_cache_put_positive(c, answer->rrs[i], timestamp, owner_family, owner_address);
+ r = dns_cache_put_positive(c, answer->items[i].rr, timestamp, owner_family, owner_address);
if (r < 0)
goto fail;
}
for (i = 0; i < q->n_keys; i++)
dns_cache_remove(c, q->keys[i]);
for (i = 0; i < answer->n_rrs; i++)
- dns_cache_remove(c, answer->rrs[i]->key);
+ dns_cache_remove(c, answer->items[i].rr->key);
return r;
}
j = hashmap_get(c->by_key, q->keys[i]);
LIST_FOREACH(by_key, j, j) {
if (j->rr) {
- r = dns_answer_add(answer, j->rr);
+ r = dns_answer_add(answer, j->rr, 0);
if (r < 0)
return r;
}
if (r < 0)
goto finish;
- r = dns_answer_add(answer, rr);
+ r = dns_answer_add(answer, rr, p->ifindex);
if (r < 0)
goto finish;
}
#include "hostname-util.h"
#include "dns-domain.h"
+#include "local-addresses.h"
#include "resolved-dns-query.h"
static int SYNTHESIZE_IFINDEX(int ifindex) {
- /* When the caller asked for resolving on a specific interface,
- * we synthesize the answer for that interface. However, if
- * nothing specific was claimed, we synthesize the answer for
+ /* When the caller asked for resolving on a specific
+ * interface, we synthesize the answer for that
+ * interface. However, if nothing specific was claimed and we
+ * only return localhost RRs, we synthesize the answer for
* localhost. */
if (ifindex > 0)
return DNS_PROTOCOL_DNS;
}
-static void dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
+static int dns_type_to_af(uint16_t t) {
+ switch (t) {
+
+ case DNS_TYPE_A:
+ return AF_INET;
+
+ case DNS_TYPE_AAAA:
+ return AF_INET6;
+
+ case DNS_TYPE_ANY:
+ return AF_UNSPEC;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int synthesize_localhost_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
+ int r;
+
+ assert(q);
+ assert(key);
+ assert(answer);
+
+ r = dns_answer_reserve(answer, 2);
+ if (r < 0)
+ return r;
+
+ if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
+ if (!rr)
+ return -ENOMEM;
+
+ rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
+
+ r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+ }
+
+ if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
+ if (!rr)
+ return -ENOMEM;
+
+ rr->aaaa.in6_addr = in6addr_loopback;
+
+ r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from);
+ if (!rr)
+ return -ENOMEM;
+
+ rr->ptr.name = strdup(to);
+ if (!rr->ptr.name)
+ return -ENOMEM;
+
+ return dns_answer_add(*answer, rr, ifindex);
+}
+
+static int synthesize_localhost_ptr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
+ int r;
+
+ assert(q);
+ assert(key);
+ assert(answer);
+
+ r = dns_answer_reserve(answer, 1);
+ if (r < 0)
+ return r;
+
+ if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) {
+ r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int answer_add_addresses_rr(
+ DnsAnswer **answer,
+ const char *name,
+ struct local_address *addresses,
+ unsigned n_addresses) {
+
+ unsigned j;
+ int r;
+
+ assert(answer);
+ assert(name);
+
+ r = dns_answer_reserve(answer, n_addresses);
+ if (r < 0)
+ return r;
+
+ for (j = 0; j < n_addresses; j++) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+
+ r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name);
+ if (r < 0)
+ return r;
+
+ r = dns_answer_add(*answer, rr, addresses[j].ifindex);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int answer_add_addresses_ptr(
+ DnsAnswer **answer,
+ const char *name,
+ struct local_address *addresses,
+ unsigned n_addresses,
+ int af, const union in_addr_union *match) {
+
+ unsigned j;
+ int r;
+
+ assert(answer);
+ assert(name);
+
+ for (j = 0; j < n_addresses; j++) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+
+ if (af != AF_UNSPEC) {
+
+ if (addresses[j].family != af)
+ continue;
+
+ if (match && !in_addr_equal(af, match, &addresses[j].address))
+ continue;
+ }
+
+ r = dns_answer_reserve(answer, 1);
+ if (r < 0)
+ return r;
+
+ r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name);
+ if (r < 0)
+ return r;
+
+ r = dns_answer_add(*answer, rr, addresses[j].ifindex);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int synthesize_system_hostname_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
+ _cleanup_free_ struct local_address *addresses = NULL;
+ int n = 0, af;
+
+ assert(q);
+ assert(key);
+ assert(answer);
+
+ af = dns_type_to_af(key->type);
+ if (af >= 0) {
+ n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
+ if (n < 0)
+ return n;
+
+ if (n == 0) {
+ struct local_address buffer[2];
+
+ /* If we have no local addresses then use ::1
+ * and 127.0.0.2 as local ones. */
+
+ if (af == AF_INET || af == AF_UNSPEC)
+ buffer[n++] = (struct local_address) {
+ .family = AF_INET,
+ .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
+ .address.in.s_addr = htobe32(0x7F000002),
+ };
+
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ buffer[n++] = (struct local_address) {
+ .family = AF_INET6,
+ .ifindex = SYNTHESIZE_IFINDEX(q->ifindex),
+ .address.in6 = in6addr_loopback,
+ };
+
+ return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
+ }
+ }
+
+ return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+}
+
+static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
+ _cleanup_free_ struct local_address *addresses = NULL;
+ int n, r;
+
+ assert(q);
+ assert(address);
+ assert(answer);
+
+ if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) {
+
+ /* Always map the IPv4 address 127.0.0.2 to the local
+ * hostname, in addition to "localhost": */
+
+ r = dns_answer_reserve(answer, 3);
+ if (r < 0)
+ return r;
+
+ r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+
+ r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+
+ r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex));
+ if (r < 0)
+ return r;
+
+ return 0;
+ }
+
+ n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses);
+ if (n < 0)
+ return n;
+
+ r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address);
+ if (r < 0)
+ return r;
+
+ return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address);
+}
+
+static int synthesize_gateway_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) {
+ _cleanup_free_ struct local_address *addresses = NULL;
+ int n = 0, af;
+
+ assert(q);
+ assert(key);
+ assert(answer);
+
+ af = dns_type_to_af(key->type);
+ if (af >= 0) {
+ n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
+ if (n < 0)
+ return n;
+ }
+
+ return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+}
+
+static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) {
+ _cleanup_free_ struct local_address *addresses = NULL;
+ int n;
+
+ assert(q);
+ assert(address);
+ assert(answer);
+
+ n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses);
+ if (n < 0)
+ return n;
+
+ return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address);
+}
+
+static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
unsigned i;
int r;
DNS_TRANSACTION_NO_SERVERS,
DNS_TRANSACTION_TIMEOUT,
DNS_TRANSACTION_ATTEMPTS_MAX_REACHED))
- return;
+ return 0;
for (i = 0; i < q->question->n_keys; i++) {
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+ union in_addr_union address;
const char *name;
+ int af;
if (q->question->keys[i]->class != DNS_CLASS_IN &&
q->question->keys[i]->class != DNS_CLASS_ANY)
if (is_localhost(name)) {
- switch (q->question->keys[i]->type) {
-
- case DNS_TYPE_A:
- case DNS_TYPE_ANY:
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
- if (!rr) {
- log_oom();
- return;
- }
+ r = synthesize_localhost_rr(q, q->question->keys[i], &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
- rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
- break;
+ } else if (manager_is_own_hostname(q->manager, name)) {
- case DNS_TYPE_AAAA:
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
- if (!rr) {
- log_oom();
- return;
- }
+ r = synthesize_system_hostname_rr(q, q->question->keys[i], &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize system hostname RRs: %m");
- rr->aaaa.in6_addr = in6addr_loopback;
- break;
- }
+ } else if (is_gateway_hostname(name)) {
- } else if (IN_SET(q->question->keys[i]->type, DNS_TYPE_PTR, DNS_TYPE_ANY) &&
- (dns_name_endswith(name, "127.in-addr.arpa") > 0 ||
- dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)) {
+ r = synthesize_gateway_rr(q, q->question->keys[i], &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, name);
- if (!rr) {
- log_oom();
- return;
- }
+ } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) ||
+ dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
- rr->ptr.name = strdup("localhost");
- if (!rr->ptr.name) {
- log_oom();
- return;
- }
- }
+ r = synthesize_localhost_ptr(q, q->question->keys[i], &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m");
- if (!rr)
- continue;
+ } else if (dns_name_address(name, &af, &address) > 0) {
- if (!answer) {
- answer = dns_answer_new(q->question->n_keys);
- if (!answer) {
- log_oom();
- return;
- }
- }
+ r = synthesize_system_hostname_ptr(q, af, &address, &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m");
- r = dns_answer_add(answer, rr);
- if (r < 0) {
- log_error_errno(r, "Failed to add synthetic RR to answer: %m");
- return;
+ r = synthesize_gateway_ptr(q, af, &address, &answer);
+ if (r < 0)
+ return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m");
}
}
if (!answer)
- return;
+ return 0;
dns_answer_unref(q->answer);
q->answer = answer;
answer = NULL;
- q->answer_ifindex = SYNTHESIZE_IFINDEX(q->ifindex);
q->answer_family = SYNTHESIZE_FAMILY(q->flags);
q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags);
q->answer_rcode = DNS_RCODE_SUCCESS;
*state = DNS_TRANSACTION_SUCCESS;
+
+ return 1;
}
int dns_query_go(DnsQuery *q) {
}
q->answer = dns_answer_unref(q->answer);
- q->answer_ifindex = 0;
q->answer_rcode = 0;
q->answer_family = AF_UNSPEC;
q->answer_protocol = _DNS_PROTOCOL_INVALID;
if (IN_SET(state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE)) {
q->answer = dns_answer_ref(answer);
q->answer_rcode = rcode;
- q->answer_ifindex = (scope && scope->link) ? scope->link->ifindex : 0;
q->answer_protocol = scope ? scope->protocol : _DNS_PROTOCOL_INVALID;
q->answer_family = scope ? scope->family : AF_UNSPEC;
}
/* Discovered data */
DnsAnswer *answer;
- int answer_ifindex;
int answer_family;
DnsProtocol answer_protocol;
int answer_rcode;
return 0;
}
+int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
+ DnsResourceRecord *rr;
+
+ assert(ret);
+ assert(address);
+ assert(family);
+
+ if (family == AF_INET) {
+
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
+ if (!rr)
+ return -ENOMEM;
+
+ rr->a.in_addr = address->in;
+
+ } else if (family == AF_INET6) {
+
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
+ if (!rr)
+ return -ENOMEM;
+
+ rr->aaaa.in6_addr = address->in6;
+ } else
+ return -EAFNOSUPPORT;
+
+ *ret = rr;
+
+ return 0;
+}
+
int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
int r;
DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr);
DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr);
int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name);
+int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name);
int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b);
int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref);
if (dns_name_root(domain) != 0)
return DNS_SCOPE_NO;
- if (is_localhost(domain))
- return DNS_SCOPE_NO;
-
- /* Never resolve any loopback IP address via DNS, LLMNR or mDNS */
- if (dns_name_endswith(domain, "127.in-addr.arpa") > 0 ||
+ /* Never resolve any loopback hostname or IP address via DNS,
+ * LLMNR or mDNS. Instead, always rely on synthesized RRs for
+ * these. */
+ if (is_localhost(domain) ||
+ dns_name_endswith(domain, "127.in-addr.arpa") > 0 ||
dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)
return DNS_SCOPE_NO;
}
if (s->protocol == DNS_PROTOCOL_MDNS) {
- if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
- dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
- (dns_name_endswith(domain, "local") > 0 && dns_name_equal(domain, "local") == 0))
+ if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
+ (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) ||
+ (dns_name_endswith(domain, "local") > 0 && /* only resolve names ending in .local via mDNS */
+ dns_name_equal(domain, "local") == 0 && /* but not the single-label "local" name itself */
+ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via mDNS */
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
}
if (s->protocol == DNS_PROTOCOL_LLMNR) {
- if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
- dns_name_endswith(domain, "ip6.arpa") > 0 ||
- (dns_name_single_label(domain) > 0 &&
- dns_name_equal(domain, "gateway") <= 0)) /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
+ if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) ||
+ (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) ||
+ (dns_name_single_label(domain) > 0 && /* only resolve single label names via LLMNR */
+ !is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */
+ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */
return DNS_SCOPE_MAYBE;
return DNS_SCOPE_NO;
if (answer) {
for (i = 0; i < answer->n_rrs; i++) {
- r = dns_packet_append_rr(p, answer->rrs[i], NULL);
+ r = dns_packet_append_rr(p, answer->items[i].rr, NULL);
if (r < 0)
return r;
}
if (soa) {
for (i = 0; i < soa->n_rrs; i++) {
- r = dns_packet_append_rr(p, soa->rrs[i], NULL);
+ r = dns_packet_append_rr(p, soa->items[i].rr, NULL);
if (r < 0)
return r;
}
dns_zone_verify_conflicts(&s->zone, p->question->keys[n]);
if (p->answer)
for (n = 0; n < p->answer->n_rrs; n++)
- dns_zone_verify_conflicts(&s->zone, p->answer->rrs[n]->key);
+ dns_zone_verify_conflicts(&s->zone, p->answer->items[n].rr->key);
}
void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) {
/* Check for conflicts against the local zone. If we
* found one, we won't check any further */
- r = dns_zone_check_conflicts(&scope->zone, p->answer->rrs[i]);
+ r = dns_zone_check_conflicts(&scope->zone, p->answer->items[i].rr);
if (r != 0)
continue;
/* Check for conflicts against the local cache. If so,
* send out an advisory query, to inform everybody */
- r = dns_cache_check_conflicts(&scope->cache, p->answer->rrs[i], p->family, &p->sender);
+ r = dns_cache_check_conflicts(&scope->cache, p->answer->items[i].rr, p->family, &p->sender);
if (r <= 0)
continue;
- dns_scope_notify_conflict(scope, p->answer->rrs[i]);
+ dns_scope_notify_conflict(scope, p->answer->items[i].rr);
}
}
if (k < 0)
return k;
if (k > 0) {
- r = dns_answer_add(answer, j->rr);
+ r = dns_answer_add(answer, j->rr, 0);
if (r < 0)
return r;
if (j->state != DNS_ZONE_ITEM_PROBING)
tentative = false;
- r = dns_answer_add(answer, j->rr);
+ r = dns_answer_add(answer, j->rr, 0);
if (r < 0)
return r;
}
i->state = DNS_ZONE_ITEM_WITHDRAWN;
/* Maybe change the hostname */
- if (dns_name_equal(i->scope->manager->hostname, DNS_RESOURCE_KEY_NAME(i->rr->key)) > 0)
+ if (manager_is_own_hostname(i->scope->manager, DNS_RESOURCE_KEY_NAME(i->rr->key)) > 0)
manager_next_hostname(i->scope->manager);
}
a->link->llmnr_support == SUPPORT_YES &&
a->link->manager->llmnr_support == SUPPORT_YES) {
- if (!a->link->manager->host_ipv4_key) {
- a->link->manager->host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->hostname);
- if (!a->link->manager->host_ipv4_key) {
+ if (!a->link->manager->llmnr_host_ipv4_key) {
+ a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
+ if (!a->link->manager->llmnr_host_ipv4_key) {
r = -ENOMEM;
goto fail;
}
}
if (!a->llmnr_address_rr) {
- a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv4_key);
+ a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
}
if (!a->llmnr_ptr_rr) {
- r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
+ r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
if (r < 0)
goto fail;
a->link->llmnr_support == SUPPORT_YES &&
a->link->manager->llmnr_support == SUPPORT_YES) {
- if (!a->link->manager->host_ipv6_key) {
- a->link->manager->host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->hostname);
- if (!a->link->manager->host_ipv6_key) {
+ if (!a->link->manager->llmnr_host_ipv6_key) {
+ a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
+ if (!a->link->manager->llmnr_host_ipv6_key) {
r = -ENOMEM;
goto fail;
}
}
if (!a->llmnr_address_rr) {
- a->llmnr_address_rr = dns_resource_record_new(a->link->manager->host_ipv6_key);
+ a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
if (!a->llmnr_address_rr) {
r = -ENOMEM;
goto fail;
}
if (!a->llmnr_ptr_rr) {
- r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->hostname);
+ r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
if (r < 0)
goto fail;
return 0;
}
-static int determine_hostname(char **ret) {
+static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
_cleanup_free_ char *h = NULL, *n = NULL;
- int r;
+ char label[DNS_LABEL_MAX];
+ const char *p;
+ int r, k;
- assert(ret);
+ assert(llmnr_hostname);
+ assert(mdns_hostname);
+
+ /* Extract and normalize the first label of the locally
+ * configured hostname, and check it's not "localhost". */
h = gethostname_malloc();
if (!h)
return log_oom();
- if (!utf8_is_valid(h)) {
+ p = h;
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r < 0)
+ return log_error_errno(r, "Failed to unescape host name: %m");
+ if (r == 0) {
+ log_error("Couldn't find a single label in hosntame.");
+ return -EINVAL;
+ }
+
+ k = dns_label_undo_idna(label, r, label, sizeof(label));
+ if (k < 0)
+ return log_error_errno(k, "Failed to undo IDNA: %m");
+ if (k > 0)
+ r = k;
+
+ if (!utf8_is_valid(label)) {
log_error("System hostname is not UTF-8 clean.");
return -EINVAL;
}
- r = dns_name_normalize(h, &n);
- if (r < 0) {
- log_error("System hostname '%s' cannot be normalized.", h);
- return r;
+ r = dns_label_escape(label, r, &n);
+ if (r < 0)
+ return log_error_errno(r, "Failed to escape host name: %m");
+
+ if (is_localhost(n)) {
+ log_debug("System hostname is 'localhost', ignoring.");
+ return -EINVAL;
}
- *ret = n;
+ r = dns_name_concat(n, "local", mdns_hostname);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine mDNS hostname: %m");
+
+ *llmnr_hostname = n;
n = NULL;
return 0;
}
static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
- _cleanup_free_ char *h = NULL;
+ _cleanup_free_ char *llmnr_hostname = NULL, *mdns_hostname = NULL;
Manager *m = userdata;
int r;
assert(m);
- r = determine_hostname(&h);
+ r = determine_hostname(&llmnr_hostname, &mdns_hostname);
if (r < 0)
return 0; /* ignore invalid hostnames */
- if (streq(h, m->hostname))
+ if (streq(llmnr_hostname, m->llmnr_hostname) && streq(mdns_hostname, m->mdns_hostname))
return 0;
- log_info("System hostname changed to '%s'.", h);
- free(m->hostname);
- m->hostname = h;
- h = NULL;
+ log_info("System hostname changed to '%s'.", llmnr_hostname);
+
+ free(m->llmnr_hostname);
+ free(m->mdns_hostname);
+
+ m->llmnr_hostname = llmnr_hostname;
+ m->mdns_hostname = mdns_hostname;
+
+ llmnr_hostname = mdns_hostname = NULL;
manager_refresh_rrs(m);
return log_error_errno(r, "Failed to add hostname event source: %m");
}
- r = determine_hostname(&m->hostname);
+ r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname);
if (r < 0) {
log_info("Defaulting to hostname 'linux'.");
- m->hostname = strdup("linux");
- if (!m->hostname)
+ m->llmnr_hostname = strdup("linux");
+ if (!m->llmnr_hostname)
+ return log_oom();
+
+ m->mdns_hostname = strdup("linux.local");
+ if (!m->mdns_hostname)
return log_oom();
} else
- log_info("Using system hostname '%s'.", m->hostname);
+ log_info("Using system hostname '%s'.", m->llmnr_hostname);
return 0;
}
sd_event_unref(m->event);
- dns_resource_key_unref(m->host_ipv4_key);
- dns_resource_key_unref(m->host_ipv6_key);
+ dns_resource_key_unref(m->llmnr_host_ipv4_key);
+ dns_resource_key_unref(m->llmnr_host_ipv6_key);
safe_close(m->hostname_fd);
sd_event_source_unref(m->hostname_event_source);
- free(m->hostname);
+ free(m->llmnr_hostname);
+ free(m->mdns_hostname);
free(m);
assert(m);
- m->host_ipv4_key = dns_resource_key_unref(m->host_ipv4_key);
- m->host_ipv6_key = dns_resource_key_unref(m->host_ipv6_key);
+ m->llmnr_host_ipv4_key = dns_resource_key_unref(m->llmnr_host_ipv4_key);
+ m->llmnr_host_ipv6_key = dns_resource_key_unref(m->llmnr_host_ipv6_key);
HASHMAP_FOREACH(l, m->links, i) {
link_add_rrs(l, true);
int manager_next_hostname(Manager *m) {
const char *p;
uint64_t u, a;
- char *h;
+ char *h, *k;
+ int r;
assert(m);
- p = strchr(m->hostname, 0);
+ p = strchr(m->llmnr_hostname, 0);
assert(p);
- while (p > m->hostname) {
+ while (p > m->llmnr_hostname) {
if (!strchr("0123456789", p[-1]))
break;
random_bytes(&a, sizeof(a));
u += 1 + a % 10;
- if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->hostname), m->hostname, u) < 0)
+ if (asprintf(&h, "%.*s%" PRIu64, (int) (p - m->llmnr_hostname), m->llmnr_hostname, u) < 0)
return -ENOMEM;
- log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->hostname, h);
+ r = dns_name_concat(h, "local", &k);
+ if (r < 0) {
+ free(h);
+ return r;
+ }
+
+ log_info("Hostname conflict, changing published hostname from '%s' to '%s'.", m->llmnr_hostname, h);
+
+ free(m->llmnr_hostname);
+ m->llmnr_hostname = h;
- free(m->hostname);
- m->hostname = h;
+ free(m->mdns_hostname);
+ m->mdns_hostname = k;
manager_refresh_rrs(m);
}
}
+int manager_is_own_hostname(Manager *m, const char *name) {
+ _cleanup_free_ char *l = NULL;
+ int r;
+
+ assert(m);
+ assert(name);
+
+ if (m->llmnr_hostname) {
+ r = dns_name_equal(name, m->llmnr_hostname);
+ if (r != 0)
+ return r;
+ }
+
+ if (m->mdns_hostname)
+ return dns_name_equal(name, m->mdns_hostname);
+
+ return 0;
+}
+
static const char* const support_table[_SUPPORT_MAX] = {
[SUPPORT_NO] = "no",
[SUPPORT_YES] = "yes",
sd_event_source *bus_retry_event_source;
/* The hostname we publish on LLMNR and mDNS */
- char *hostname;
- DnsResourceKey *host_ipv4_key;
- DnsResourceKey *host_ipv6_key;
+ char *llmnr_hostname;
+ char *mdns_hostname;
+ DnsResourceKey *llmnr_host_ipv4_key;
+ DnsResourceKey *llmnr_host_ipv6_key;
/* Watch the system hostname */
int hostname_fd;
#define EXTRA_CMSG_SPACE 1024
+int manager_is_own_hostname(Manager *m, const char *name);
+
const char* support_to_string(Support p) _const_;
int support_from_string(const char *s) _pure_;