mirror of
https://github.com/systemd/systemd.git
synced 2025-03-22 06:50:18 +03:00
Merge pull request #1002 from poettering/resolved-various
resolved: synthesize more RRs locally and other fixes
This commit is contained in:
commit
ef7051360a
src
basic
nss-myhostname
nss-resolve
resolve-host
resolve
resolved-bus.cresolved-dns-answer.cresolved-dns-answer.hresolved-dns-cache.cresolved-dns-packet.cresolved-dns-query.cresolved-dns-query.hresolved-dns-question.cresolved-dns-rr.cresolved-dns-rr.hresolved-dns-scope.cresolved-dns-transaction.cresolved-dns-zone.cresolved-link.cresolved-manager.cresolved-manager.h
shared
test
@ -151,6 +151,17 @@ bool is_localhost(const char *hostname) {
|
||||
endswith_no_case(hostname, ".localdomain.");
|
||||
}
|
||||
|
||||
bool is_gateway_hostname(const char *hostname) {
|
||||
assert(hostname);
|
||||
|
||||
/* This tries to identify the valid syntaxes for the our
|
||||
* synthetic "gateway" host. */
|
||||
|
||||
return
|
||||
strcaseeq(hostname, "gateway") ||
|
||||
strcaseeq(hostname, "gateway.");
|
||||
}
|
||||
|
||||
int sethostname_idempotent(const char *s) {
|
||||
char buf[HOST_NAME_MAX + 1] = {};
|
||||
|
||||
|
@ -33,6 +33,7 @@ bool hostname_is_valid(const char *s, bool relax) _pure_;
|
||||
char* hostname_cleanup(char *s);
|
||||
|
||||
bool is_localhost(const char *hostname);
|
||||
bool is_gateway_hostname(const char *hostname);
|
||||
|
||||
int sethostname_idempotent(const char *s);
|
||||
|
||||
|
@ -43,13 +43,6 @@
|
||||
NSS_GETHOSTBYNAME_PROTOTYPES(myhostname);
|
||||
NSS_GETHOSTBYADDR_PROTOTYPES(myhostname);
|
||||
|
||||
static bool is_gateway(const char *hostname) {
|
||||
assert(hostname);
|
||||
|
||||
return streq(hostname, "gateway") ||
|
||||
streq(hostname, "gateway.");
|
||||
}
|
||||
|
||||
enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
const char *name,
|
||||
struct gaih_addrtuple **pat,
|
||||
@ -81,7 +74,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
|
||||
canonical = "localhost";
|
||||
local_address_ipv4 = htonl(INADDR_LOOPBACK);
|
||||
|
||||
} else if (is_gateway(name)) {
|
||||
} else if (is_gateway_hostname(name)) {
|
||||
|
||||
n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
|
||||
if (n_addresses <= 0) {
|
||||
@ -351,7 +344,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
|
||||
canonical = "localhost";
|
||||
local_address_ipv4 = htonl(INADDR_LOOPBACK);
|
||||
|
||||
} else if (is_gateway(name)) {
|
||||
} else if (is_gateway_hostname(name)) {
|
||||
|
||||
n_addresses = local_gateways(NULL, 0, af, &addresses);
|
||||
if (n_addresses <= 0) {
|
||||
|
@ -61,23 +61,21 @@ static bool bus_error_shall_fallback(sd_bus_error *e) {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -126,7 +124,7 @@ enum nss_status _nss_resolve_gethostbyname4_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);
|
||||
@ -218,28 +216,26 @@ enum nss_status _nss_resolve_gethostbyname4_r(
|
||||
/* Second, append addresses */
|
||||
r_tuple_first = (struct gaih_addrtuple*) (buffer + idx);
|
||||
|
||||
r = sd_bus_message_read(reply, "i", &ifindex);
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (ifindex < 0) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
|
||||
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;
|
||||
@ -308,7 +304,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
_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);
|
||||
@ -420,28 +416,24 @@ enum nss_status _nss_resolve_gethostbyname3_r(
|
||||
/* Third, append addresses */
|
||||
r_addr = buffer + idx;
|
||||
|
||||
r = sd_bus_message_read(reply, "i", &ifindex);
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (ifindex < 0) {
|
||||
r = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(iay)");
|
||||
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;
|
||||
@ -603,20 +595,17 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
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);
|
||||
}
|
||||
@ -661,7 +650,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
|
||||
/* 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;
|
||||
|
||||
|
@ -41,13 +41,13 @@ static uint16_t arg_class = 0;
|
||||
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);
|
||||
@ -58,11 +58,6 @@ static void print_source(int ifindex, uint64_t flags, usec_t rtt) {
|
||||
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);
|
||||
@ -76,14 +71,18 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
_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,
|
||||
@ -109,22 +108,19 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
|
||||
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;
|
||||
|
||||
r = sd_bus_message_read(reply, "i", &family);
|
||||
assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
|
||||
r = sd_bus_message_read(reply, "ii", &ifindex, &family);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
@ -142,26 +138,17 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
}
|
||||
|
||||
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 ? ":" : " ",
|
||||
@ -192,7 +179,7 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
print_source(ifindex, flags, ts);
|
||||
print_source(flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -204,7 +191,6 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
char ifname[IF_NAMESIZE] = "";
|
||||
uint64_t flags;
|
||||
unsigned c = 0;
|
||||
const char *n;
|
||||
usec_t ts;
|
||||
int r;
|
||||
|
||||
@ -212,19 +198,15 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
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);
|
||||
|
||||
@ -238,10 +220,6 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
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);
|
||||
@ -264,19 +242,31 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
|
||||
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;
|
||||
|
||||
printf("%*s%s%s%s %s\n",
|
||||
assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
|
||||
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);
|
||||
|
||||
@ -298,7 +288,7 @@ static int resolve_address(sd_bus *bus, int family, const union in_addr_union *a
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
print_source(ifindex, flags, ts);
|
||||
print_source(flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -333,14 +323,18 @@ static int resolve_record(sd_bus *bus, const char *name) {
|
||||
|
||||
_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,
|
||||
@ -367,23 +361,22 @@ static int resolve_record(sd_bus *bus, const char *name) {
|
||||
|
||||
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);
|
||||
|
||||
@ -415,7 +408,11 @@ static int resolve_record(sd_bus *bus, const char *name) {
|
||||
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)
|
||||
@ -434,7 +431,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
print_source(ifindex, flags, ts);
|
||||
print_source(flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -91,13 +91,17 @@ static int reply_query_state(DnsQuery *q) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -145,11 +149,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
||||
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;
|
||||
|
||||
@ -157,27 +157,27 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
||||
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 ++;
|
||||
}
|
||||
@ -204,18 +204,18 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
|
||||
/* 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++;
|
||||
}
|
||||
@ -373,11 +373,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
||||
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;
|
||||
|
||||
@ -385,13 +381,13 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
|
||||
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;
|
||||
|
||||
@ -525,11 +521,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
||||
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;
|
||||
|
||||
@ -540,7 +532,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
||||
_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)
|
||||
@ -550,15 +542,18 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
|
||||
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;
|
||||
|
||||
@ -662,9 +657,9 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
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;
|
||||
|
||||
@ -54,7 +54,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) {
|
||||
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
|
||||
@ -63,25 +63,30 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) {
|
||||
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;
|
||||
@ -91,7 +96,10 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -118,18 +126,20 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) {
|
||||
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)
|
||||
@ -142,24 +152,26 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -184,7 +196,7 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
|
||||
|
||||
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;
|
||||
}
|
||||
@ -192,7 +204,7 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
|
||||
|
||||
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;
|
||||
}
|
||||
@ -205,9 +217,11 @@ DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) {
|
||||
}
|
||||
|
||||
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;
|
||||
@ -218,19 +232,51 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) {
|
||||
/* 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;
|
||||
}
|
||||
|
@ -22,22 +22,31 @@
|
||||
***/
|
||||
|
||||
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);
|
||||
@ -45,4 +54,6 @@ int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **r
|
||||
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);
|
||||
|
@ -426,7 +426,7 @@ int dns_cache_put(
|
||||
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,
|
||||
@ -443,7 +443,7 @@ int dns_cache_put(
|
||||
|
||||
/* 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;
|
||||
}
|
||||
@ -478,7 +478,7 @@ 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;
|
||||
}
|
||||
@ -566,7 +566,7 @@ int dns_cache_lookup(DnsCache *c, DnsQuestion *q, int *rcode, DnsAnswer **ret) {
|
||||
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;
|
||||
}
|
||||
|
@ -1795,7 +1795,7 @@ int dns_packet_extract(DnsPacket *p) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = dns_answer_add(answer, rr);
|
||||
r = dns_answer_add(answer, rr, p->ifindex);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "hostname-util.h"
|
||||
#include "dns-domain.h"
|
||||
#include "local-addresses.h"
|
||||
|
||||
#include "resolved-dns-query.h"
|
||||
|
||||
@ -216,9 +217,10 @@ static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) {
|
||||
|
||||
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)
|
||||
@ -261,7 +263,289 @@ static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) {
|
||||
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;
|
||||
@ -276,11 +560,12 @@ static void dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state)
|
||||
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)
|
||||
@ -290,78 +575,55 @@ static void dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state)
|
||||
|
||||
if (is_localhost(name)) {
|
||||
|
||||
switch (q->question->keys[i]->type) {
|
||||
r = synthesize_localhost_rr(q, q->question->keys[i], &answer);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to synthesize localhost RRs: %m");
|
||||
|
||||
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;
|
||||
}
|
||||
} else if (manager_is_own_hostname(q->manager, name)) {
|
||||
|
||||
rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK);
|
||||
break;
|
||||
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");
|
||||
|
||||
case DNS_TYPE_AAAA:
|
||||
rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
|
||||
if (!rr) {
|
||||
log_oom();
|
||||
return;
|
||||
}
|
||||
} else if (is_gateway_hostname(name)) {
|
||||
|
||||
rr->aaaa.in6_addr = in6addr_loopback;
|
||||
break;
|
||||
}
|
||||
r = synthesize_gateway_rr(q, q->question->keys[i], &answer);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to synthesize gateway RRs: %m");
|
||||
|
||||
} 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)) {
|
||||
} 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 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, name);
|
||||
if (!rr) {
|
||||
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");
|
||||
|
||||
rr->ptr.name = strdup("localhost");
|
||||
if (!rr->ptr.name) {
|
||||
log_oom();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (dns_name_address(name, &af, &address) > 0) {
|
||||
|
||||
if (!rr)
|
||||
continue;
|
||||
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");
|
||||
|
||||
if (!answer) {
|
||||
answer = dns_answer_new(q->question->n_keys);
|
||||
if (!answer) {
|
||||
log_oom();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -437,7 +699,6 @@ 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;
|
||||
@ -584,7 +845,6 @@ void dns_query_ready(DnsQuery *q) {
|
||||
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;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ struct DnsQuery {
|
||||
|
||||
/* Discovered data */
|
||||
DnsAnswer *answer;
|
||||
int answer_ifindex;
|
||||
int answer_family;
|
||||
DnsProtocol answer_protocol;
|
||||
int answer_rcode;
|
||||
|
@ -68,9 +68,11 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(key);
|
||||
|
||||
if (!q)
|
||||
return -ENOSPC;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
r = dns_resource_key_equal(q->keys[i], key);
|
||||
if (r < 0)
|
||||
@ -90,9 +92,11 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) {
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(rr);
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
r = dns_resource_key_match_rr(q->keys[i], rr);
|
||||
if (r != 0)
|
||||
@ -106,9 +110,11 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) {
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(rr);
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
r = dns_resource_key_match_cname(q->keys[i], rr);
|
||||
if (r != 0)
|
||||
@ -123,7 +129,8 @@ int dns_question_is_valid(DnsQuestion *q) {
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
if (q->n_keys <= 0)
|
||||
return 0;
|
||||
@ -151,16 +158,19 @@ int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) {
|
||||
unsigned j;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(other);
|
||||
|
||||
/* Checks if all keys in "other" are also contained in "q" */
|
||||
|
||||
if (!other)
|
||||
return 1;
|
||||
|
||||
for (j = 0; j < other->n_keys; j++) {
|
||||
DnsResourceKey *b = other->keys[j];
|
||||
bool found = false;
|
||||
unsigned i;
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
DnsResourceKey *a = q->keys[i];
|
||||
|
||||
@ -192,9 +202,11 @@ int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) {
|
||||
unsigned j;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(k);
|
||||
|
||||
if (!a)
|
||||
return 0;
|
||||
|
||||
for (j = 0; j < a->n_keys; j++) {
|
||||
r = dns_resource_key_equal(a->keys[j], k);
|
||||
if (r != 0)
|
||||
@ -208,8 +220,10 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
|
||||
unsigned j;
|
||||
int r;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
if (!a)
|
||||
return !b || b->n_keys == 0;
|
||||
if (!b)
|
||||
return a->n_keys == 0;
|
||||
|
||||
/* Checks if all keys in a are also contained b, and vice versa */
|
||||
|
||||
@ -234,10 +248,19 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **
|
||||
unsigned i;
|
||||
int r;
|
||||
|
||||
assert(q);
|
||||
assert(name);
|
||||
assert(ret);
|
||||
|
||||
if (!q) {
|
||||
n = dns_question_new(0);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = n;
|
||||
n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
|
||||
if (r < 0)
|
||||
@ -281,9 +304,11 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **
|
||||
int dns_question_endswith(DnsQuestion *q, const char *suffix) {
|
||||
unsigned i;
|
||||
|
||||
assert(q);
|
||||
assert(suffix);
|
||||
|
||||
if (!q)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
int k;
|
||||
|
||||
@ -298,10 +323,12 @@ int dns_question_endswith(DnsQuestion *q, const char *suffix) {
|
||||
int dns_question_extract_reverse_address(DnsQuestion *q, int *family, union in_addr_union *address) {
|
||||
unsigned i;
|
||||
|
||||
assert(q);
|
||||
assert(family);
|
||||
assert(address);
|
||||
|
||||
if (!q)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < q->n_keys; i++) {
|
||||
int k;
|
||||
|
||||
|
@ -350,6 +350,36 @@ int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const u
|
||||
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;
|
||||
|
||||
|
@ -191,6 +191,7 @@ DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, c
|
||||
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);
|
||||
|
@ -328,11 +328,11 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
|
||||
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;
|
||||
|
||||
@ -350,19 +350,22 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co
|
||||
}
|
||||
|
||||
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;
|
||||
@ -490,7 +493,7 @@ static int dns_scope_make_reply_packet(
|
||||
|
||||
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;
|
||||
}
|
||||
@ -500,7 +503,7 @@ static int dns_scope_make_reply_packet(
|
||||
|
||||
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;
|
||||
}
|
||||
@ -525,7 +528,7 @@ static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) {
|
||||
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) {
|
||||
@ -793,16 +796,16 @@ void dns_scope_check_conflicts(DnsScope *scope, 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);
|
||||
}
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
||||
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server);
|
||||
else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
|
||||
|
||||
/* When we already received a query to this (but it was truncated), send to its sender address */
|
||||
/* When we already received a reply to this (but it was truncated), send to its sender address */
|
||||
if (t->received)
|
||||
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL);
|
||||
else {
|
||||
@ -292,7 +292,6 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
dns_server_unref(t->server);
|
||||
t->server = dns_server_ref(server);
|
||||
t->received = dns_packet_unref(t->received);
|
||||
|
@ -422,7 +422,7 @@ int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswe
|
||||
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;
|
||||
|
||||
@ -448,7 +448,7 @@ int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswe
|
||||
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;
|
||||
}
|
||||
@ -505,7 +505,7 @@ void dns_zone_item_conflict(DnsZoneItem *i) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -419,16 +419,16 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
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;
|
||||
@ -439,7 +439,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -476,16 +476,16 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
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;
|
||||
@ -496,7 +496,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -310,51 +310,84 @@ static int manager_network_monitor_listen(Manager *m) {
|
||||
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);
|
||||
|
||||
@ -381,14 +414,18 @@ static int manager_watch_hostname(Manager *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;
|
||||
}
|
||||
@ -492,12 +529,13 @@ Manager *manager_free(Manager *m) {
|
||||
|
||||
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);
|
||||
|
||||
@ -1229,8 +1267,8 @@ void manager_refresh_rrs(Manager *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);
|
||||
@ -1241,14 +1279,15 @@ void manager_refresh_rrs(Manager *m) {
|
||||
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;
|
||||
|
||||
@ -1268,13 +1307,22 @@ int manager_next_hostname(Manager *m) {
|
||||
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;
|
||||
}
|
||||
|
||||
free(m->hostname);
|
||||
m->hostname = h;
|
||||
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->mdns_hostname);
|
||||
m->mdns_hostname = k;
|
||||
|
||||
manager_refresh_rrs(m);
|
||||
|
||||
@ -1356,6 +1404,25 @@ void manager_flush_dns_servers(Manager *m, DnsServerType t) {
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -91,9 +91,10 @@ struct Manager {
|
||||
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;
|
||||
@ -140,5 +141,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||
|
||||
#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_;
|
||||
|
@ -308,14 +308,14 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
|
||||
#endif
|
||||
}
|
||||
|
||||
int dns_name_normalize(const char *s, char **_ret) {
|
||||
int dns_name_concat(const char *a, const char *b, char **_ret) {
|
||||
_cleanup_free_ char *ret = NULL;
|
||||
size_t n = 0, allocated = 0;
|
||||
const char *p = s;
|
||||
const char *p = a;
|
||||
bool first = true;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(a);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
@ -328,6 +328,14 @@ int dns_name_normalize(const char *s, char **_ret) {
|
||||
if (r == 0) {
|
||||
if (*p != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (b) {
|
||||
/* Now continue with the second string, if there is one */
|
||||
p = b;
|
||||
b = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -341,27 +349,29 @@ int dns_name_normalize(const char *s, char **_ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
|
||||
return -ENOMEM;
|
||||
if (_ret) {
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
if (!first)
|
||||
ret[n++] = '.';
|
||||
else
|
||||
first = false;
|
||||
if (!first)
|
||||
ret[n++] = '.';
|
||||
else
|
||||
first = false;
|
||||
|
||||
memcpy(ret + n, t, r);
|
||||
}
|
||||
|
||||
memcpy(ret + n, t, r);
|
||||
n += r;
|
||||
}
|
||||
|
||||
if (n > DNS_NAME_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
ret[n] = 0;
|
||||
|
||||
if (_ret) {
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
ret[n] = 0;
|
||||
*_ret = ret;
|
||||
ret = NULL;
|
||||
}
|
||||
|
@ -35,9 +35,17 @@ int dns_label_escape(const char *p, size_t l, char **ret);
|
||||
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
|
||||
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
|
||||
|
||||
int dns_name_normalize(const char *s, char **_ret);
|
||||
int dns_name_concat(const char *a, const char *b, char **ret);
|
||||
|
||||
static inline int dns_name_normalize(const char *s, char **ret) {
|
||||
/* dns_name_concat() normalizes as a side-effect */
|
||||
return dns_name_concat(s, NULL, ret);
|
||||
}
|
||||
|
||||
static inline int dns_name_is_valid(const char *s) {
|
||||
int r;
|
||||
|
||||
/* dns_name_normalize() verifies as a side effect */
|
||||
r = dns_name_normalize(s, NULL);
|
||||
if (r == -EINVAL)
|
||||
return 0;
|
||||
|
@ -251,6 +251,39 @@ static void test_dns_name_reverse(void) {
|
||||
test_dns_name_reverse_one("::1", "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");
|
||||
}
|
||||
|
||||
static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
assert_se(dns_name_concat(a, b, &p) == r);
|
||||
assert_se(streq_ptr(p, result));
|
||||
}
|
||||
|
||||
static void test_dns_name_concat(void) {
|
||||
test_dns_name_concat_one("foo", "bar", 0, "foo.bar");
|
||||
test_dns_name_concat_one("foo.foo", "bar.bar", 0, "foo.foo.bar.bar");
|
||||
test_dns_name_concat_one("foo", NULL, 0, "foo");
|
||||
test_dns_name_concat_one("foo.", "bar.", 0, "foo.bar");
|
||||
}
|
||||
|
||||
static void test_dns_name_is_valid_one(const char *s, int ret) {
|
||||
assert_se(dns_name_is_valid(s) == ret);
|
||||
}
|
||||
|
||||
static void test_dns_name_is_valid(void) {
|
||||
test_dns_name_is_valid_one("foo", 1);
|
||||
test_dns_name_is_valid_one("foo.", 1);
|
||||
test_dns_name_is_valid_one("Foo", 1);
|
||||
test_dns_name_is_valid_one("foo.bar", 1);
|
||||
test_dns_name_is_valid_one("foo.bar.baz", 1);
|
||||
test_dns_name_is_valid_one("", 1);
|
||||
test_dns_name_is_valid_one("foo..bar", 0);
|
||||
test_dns_name_is_valid_one(".foo.bar", 0);
|
||||
test_dns_name_is_valid_one("foo.bar.", 1);
|
||||
test_dns_name_is_valid_one("\\zbar", 0);
|
||||
test_dns_name_is_valid_one("ä", 1);
|
||||
test_dns_name_is_valid_one("\n", 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
test_dns_label_unescape();
|
||||
@ -263,6 +296,8 @@ int main(int argc, char *argv[]) {
|
||||
test_dns_name_root();
|
||||
test_dns_name_single_label();
|
||||
test_dns_name_reverse();
|
||||
test_dns_name_concat();
|
||||
test_dns_name_is_valid();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user