Skip to content

Commit c1dafe4

Browse files
committed
resolve: add RFC4501 URI support to systemd-resolve-host
1 parent 8e54f5d commit c1dafe4

File tree

2 files changed

+138
-11
lines changed

2 files changed

+138
-11
lines changed

src/resolve-host/resolve-host.c

Lines changed: 137 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
328328
return 0;
329329
}
330330

331-
static int resolve_record(sd_bus *bus, const char *name) {
332-
331+
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
333332
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
334333
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
335334
char ifname[IF_NAMESIZE] = "";
@@ -343,7 +342,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
343342
if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
344343
return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
345344

346-
log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type), isempty(ifname) ? "*" : ifname);
345+
log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
347346

348347
r = sd_bus_message_new_method_call(
349348
bus,
@@ -355,7 +354,7 @@ static int resolve_record(sd_bus *bus, const char *name) {
355354
if (r < 0)
356355
return bus_log_create_error(r);
357356

358-
r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, arg_flags);
357+
r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
359358
if (r < 0)
360359
return bus_log_create_error(r);
361360

@@ -442,6 +441,127 @@ static int resolve_record(sd_bus *bus, const char *name) {
442441
return 0;
443442
}
444443

444+
static int resolve_rfc4501(sd_bus *bus, const char *name) {
445+
uint16_t type = 0, class = 0;
446+
const char *p, *q, *n;
447+
int r;
448+
449+
assert(bus);
450+
assert(name);
451+
assert(startswith(name, "dns:"));
452+
453+
/* Parse RFC 4501 dns: URIs */
454+
455+
p = name + 4;
456+
457+
if (p[0] == '/') {
458+
const char *e;
459+
460+
if (p[1] != '/')
461+
goto invalid;
462+
463+
e = strchr(p + 2, '/');
464+
if (!e)
465+
goto invalid;
466+
467+
if (e != p + 2)
468+
log_warning("DNS authority specification not supported; ignoring specified authority.");
469+
470+
p = e + 1;
471+
}
472+
473+
q = strchr(p, '?');
474+
if (q) {
475+
n = strndupa(p, q - p);
476+
q++;
477+
478+
for (;;) {
479+
const char *f;
480+
481+
f = startswith_no_case(q, "class=");
482+
if (f) {
483+
_cleanup_free_ char *t = NULL;
484+
const char *e;
485+
486+
if (class != 0) {
487+
log_error("DNS class specified twice.");
488+
return -EINVAL;
489+
}
490+
491+
e = strchrnul(f, ';');
492+
t = strndup(f, e - f);
493+
if (!t)
494+
return log_oom();
495+
496+
r = dns_class_from_string(t);
497+
if (r < 0) {
498+
log_error("Unknown DNS class %s.", t);
499+
return -EINVAL;
500+
}
501+
502+
class = r;
503+
504+
if (*e == ';') {
505+
q = e + 1;
506+
continue;
507+
}
508+
509+
break;
510+
}
511+
512+
f = startswith_no_case(q, "type=");
513+
if (f) {
514+
_cleanup_free_ char *t = NULL;
515+
const char *e;
516+
517+
if (type != 0) {
518+
log_error("DNS type specified twice.");
519+
return -EINVAL;
520+
}
521+
522+
e = strchrnul(f, ';');
523+
t = strndup(f, e - f);
524+
if (!t)
525+
return log_oom();
526+
527+
r = dns_type_from_string(t);
528+
if (r < 0) {
529+
log_error("Unknown DNS type %s.", t);
530+
return -EINVAL;
531+
}
532+
533+
type = r;
534+
535+
if (*e == ';') {
536+
q = e + 1;
537+
continue;
538+
}
539+
540+
break;
541+
}
542+
543+
goto invalid;
544+
}
545+
} else
546+
n = p;
547+
548+
if (type == 0)
549+
type = arg_type;
550+
if (type == 0)
551+
type = DNS_TYPE_A;
552+
553+
if (class == 0)
554+
class = arg_class;
555+
if (class == 0)
556+
class = DNS_CLASS_IN;
557+
558+
return resolve_record(bus, n, class, type);
559+
560+
invalid:
561+
log_error("Invalid DNS URI: %s", name);
562+
return -EINVAL;
563+
}
564+
445565
static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
446566
const char *canonical_name, *canonical_type, *canonical_domain;
447567
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
@@ -1009,6 +1129,9 @@ static int parse_argv(int argc, char *argv[]) {
10091129
if (arg_type != 0 && arg_class == 0)
10101130
arg_class = DNS_CLASS_IN;
10111131

1132+
if (arg_class != 0 && arg_type == 0)
1133+
arg_type = DNS_TYPE_A;
1134+
10121135
return 1 /* work to do */;
10131136
}
10141137

@@ -1042,11 +1165,15 @@ int main(int argc, char **argv) {
10421165
int family, ifindex, k;
10431166
union in_addr_union a;
10441167

1045-
k = parse_address(argv[optind], &family, &a, &ifindex);
1046-
if (k >= 0)
1047-
k = resolve_address(bus, family, &a, ifindex);
1048-
else
1049-
k = resolve_host(bus, argv[optind]);
1168+
if (startswith(argv[optind], "dns:"))
1169+
k = resolve_rfc4501(bus, argv[optind]);
1170+
else {
1171+
k = parse_address(argv[optind], &family, &a, &ifindex);
1172+
if (k >= 0)
1173+
k = resolve_address(bus, family, &a, ifindex);
1174+
else
1175+
k = resolve_host(bus, argv[optind]);
1176+
}
10501177

10511178
if (r == 0)
10521179
r = k;
@@ -1065,7 +1192,7 @@ int main(int argc, char **argv) {
10651192
while (argv[optind]) {
10661193
int k;
10671194

1068-
k = resolve_record(bus, argv[optind]);
1195+
k = resolve_record(bus, argv[optind], arg_class, arg_type);
10691196
if (r == 0)
10701197
r = k;
10711198

src/resolve/RFCs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ Y https://tools.ietf.org/html/rfc3597 → Handling of Unknown DNS Resource Recor
2525
Y https://tools.ietf.org/html/rfc4255 → Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints
2626
Y https://tools.ietf.org/html/rfc4343 → Domain Name System (DNS) Case Insensitivity Clarification
2727
~ https://tools.ietf.org/html/rfc4470 → Minimally Covering NSEC Records and DNSSEC On-line Signing
28-
https://tools.ietf.org/html/rfc4501 → Domain Name System Uniform Resource Identifiers
28+
Y https://tools.ietf.org/html/rfc4501 → Domain Name System Uniform Resource Identifiers
2929
Y https://tools.ietf.org/html/rfc4509 → Use of SHA-256 in DNSSEC Delegation Signer (DS) Resource Records (RRs)
3030
~ https://tools.ietf.org/html/rfc4592 → The Role of Wildcards in the Domain Name System
3131
~ https://tools.ietf.org/html/rfc4697 → Observed DNS Resolution Misbehavior

0 commit comments

Comments
 (0)