1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2024-10-27 18:55:09 +03:00

resolved: extend ResolveHostname() bus call so that it can parse IP addresses

If the hostname passed to ResolveHostname() is actually an IP address that is
correctly formatted as string parse it as such, avoid any DNS traffic and
return the data in parsed form.

This is useful for clients which can simply call the bus function now without
caring about the precise formatting of specified hostnames. This mimics
getaddrinfo()'s behaviour with the AI_NUMERICHOST flag set.

Note that this logic is only implemented for ResolveHostname(), but not for
calls such as ResolveRecord(), for which only DNS domain names may be used as
input.

The "authenticated" flag is set for look-ups of this type, after all no
untrusted network traffic is involved.
This commit is contained in:
Lennart Poettering 2016-02-13 20:26:30 +01:00
parent ee116b54a3
commit c3be369faa

View File

@ -23,6 +23,7 @@
#include "dns-domain.h"
#include "resolved-bus.h"
#include "resolved-def.h"
#include "resolved-dns-synthesize.h"
#include "resolved-link-bus.h"
static int reply_query_state(DnsQuery *q) {
@ -233,6 +234,65 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus
return 0;
}
static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *canonical = NULL;
union in_addr_union parsed;
int r, ff;
/* Check if the hostname is actually already an IP address formatted as string. In that case just parse it,
* let's not attempt to look it up. */
r = in_addr_from_string_auto(hostname, &ff, &parsed);
if (r < 0) /* not an address */
return 0;
if (family != AF_UNSPEC && ff != family)
return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family.");
r = sd_bus_message_new_method_return(m, &reply);
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'a', "(iiay)");
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'r', "iiay");
if (r < 0)
return r;
r = sd_bus_message_append(reply, "ii", ifindex, ff);
if (r < 0)
return r;
r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff));
if (r < 0)
return r;
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
/* When an IP address is specified we just return it as canonical name, in order to avoid a DNS
* look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner
* omissions are always done the same way). */
r = in_addr_to_string(ff, &parsed, &canonical);
if (r < 0)
return r;
r = sd_bus_message_append(reply, "st", canonical,
SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true));
if (r < 0)
return r;
return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
}
static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
Manager *m = userdata;
@ -254,16 +314,20 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
if (r < 0)
return r;
r = parse_as_address(message, ifindex, hostname, family, flags);
if (r != 0)
return r;
r = dns_name_is_valid(hostname);
if (r < 0)
return r;
if (r == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
if (r < 0)
return r;
r = dns_question_new_address(&question_utf8, family, hostname, false);
if (r < 0)
return r;