mirror of
https://github.com/systemd/systemd.git
synced 2025-03-09 12:58:26 +03:00
Merge pull request #17194 from poettering/dot-suffix
resolved: turn off search domain logic for queries for dot-suffixed domains
This commit is contained in:
commit
a182fa895b
@ -260,7 +260,12 @@ finish:
|
||||
dns_query_free(q);
|
||||
}
|
||||
|
||||
static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) {
|
||||
static int validate_and_mangle_flags(
|
||||
const char *name,
|
||||
uint64_t *flags,
|
||||
uint64_t ok,
|
||||
sd_bus_error *error) {
|
||||
|
||||
assert(flags);
|
||||
|
||||
/* Checks that the client supplied interface index and flags parameter actually are valid and make
|
||||
@ -277,15 +282,16 @@ static int validate_and_mangle_ifindex_and_flags(int ifindex, uint64_t *flags, u
|
||||
* to mean "all supported protocols".
|
||||
*/
|
||||
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
|
||||
|
||||
if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
|
||||
*flags |= SD_RESOLVED_PROTOCOLS_ALL;
|
||||
|
||||
/* Imply SD_RESOLVED_NO_SEARCH if permitted and name is dot suffixed. */
|
||||
if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0)
|
||||
*flags |= SD_RESOLVED_NO_SEARCH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -371,10 +377,13 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
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 = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
|
||||
r = validate_and_mangle_flags(hostname, &flags, SD_RESOLVED_NO_SEARCH, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -527,7 +536,10 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
r = validate_and_mangle_flags(NULL, &flags, 0, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -679,6 +691,9 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
r = dns_name_is_valid(name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -692,7 +707,7 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd
|
||||
if (dns_type_is_obsolete(type))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type);
|
||||
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, 0, error);
|
||||
r = validate_and_mangle_flags(name, &flags, 0, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1205,6 +1220,9 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ifindex < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
|
||||
|
||||
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);
|
||||
|
||||
@ -1227,7 +1245,7 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s
|
||||
if (name && !type)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type.");
|
||||
|
||||
r = validate_and_mangle_ifindex_and_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
|
||||
r = validate_and_mangle_flags(name, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -93,7 +93,11 @@ static void vl_on_disconnect(VarlinkServer *s, Varlink *link, void *userdata) {
|
||||
dns_query_complete(q, DNS_TRANSACTION_ABORTED);
|
||||
}
|
||||
|
||||
static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) {
|
||||
static bool validate_and_mangle_flags(
|
||||
const char *name,
|
||||
uint64_t *flags,
|
||||
uint64_t ok) {
|
||||
|
||||
assert(flags);
|
||||
|
||||
/* This checks that the specified client-provided flags parameter actually makes sense, and mangles
|
||||
@ -116,6 +120,12 @@ static bool validate_and_mangle_flags(uint64_t *flags, uint64_t ok) {
|
||||
if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */
|
||||
*flags |= SD_RESOLVED_PROTOCOLS_ALL;
|
||||
|
||||
/* If the SD_RESOLVED_NO_SEARCH flag is acceptable, and the query name is dot-suffixed, turn off
|
||||
* search domains. Note that DNS name normalization drops the dot suffix, hence we propagate this
|
||||
* into the flags field as early as we can. */
|
||||
if (name && FLAGS_SET(ok, SD_RESOLVED_NO_SEARCH) && dns_name_dot_suffixed(name) > 0)
|
||||
*flags |= SD_RESOLVED_NO_SEARCH;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -285,7 +295,7 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va
|
||||
if (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
|
||||
if (!validate_and_mangle_flags(&p.flags, SD_RESOLVED_NO_SEARCH))
|
||||
if (!validate_and_mangle_flags(p.name, &p.flags, SD_RESOLVED_NO_SEARCH))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
r = parse_as_address(link, &p);
|
||||
@ -460,7 +470,7 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var
|
||||
if (FAMILY_ADDRESS_SIZE(p.family) != p.address_size)
|
||||
return varlink_error(link, "io.systemd.UserDatabase.BadAddressSize", NULL);
|
||||
|
||||
if (!validate_and_mangle_flags(&p.flags, 0))
|
||||
if (!validate_and_mangle_flags(NULL, &p.flags, 0))
|
||||
return varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
r = dns_question_new_reverse(&question, p.family, &p.address);
|
||||
|
@ -41,8 +41,9 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f
|
||||
/* Trailing dash */
|
||||
return -EINVAL;
|
||||
|
||||
if (*n == '.')
|
||||
if (n[0] == '.' && (n[1] != 0 || !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT)))
|
||||
n++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -139,7 +140,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags f
|
||||
return -EINVAL;
|
||||
|
||||
/* More than one trailing dot? */
|
||||
if (*n == '.')
|
||||
if (n[0] == '.' && !FLAGS_SET(flags, DNS_LABEL_LEAVE_TRAILING_DOT))
|
||||
return -EINVAL;
|
||||
|
||||
if (sz >= 1 && d)
|
||||
@ -1372,3 +1373,19 @@ int dns_name_is_valid_or_address(const char *name) {
|
||||
|
||||
return dns_name_is_valid(name);
|
||||
}
|
||||
|
||||
int dns_name_dot_suffixed(const char *name) {
|
||||
const char *p = name;
|
||||
int r;
|
||||
|
||||
for (;;) {
|
||||
if (streq(p, "."))
|
||||
return true;
|
||||
|
||||
r = dns_label_unescape(&p, NULL, DNS_LABEL_MAX, DNS_LABEL_LEAVE_TRAILING_DOT);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,9 @@
|
||||
#define DNS_N_LABELS_MAX 127
|
||||
|
||||
typedef enum DNSLabelFlags {
|
||||
DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
|
||||
DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */
|
||||
DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */
|
||||
DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */
|
||||
DNS_LABEL_LEAVE_TRAILING_DOT = 1 << 2, /* Leave trailing dot in place */
|
||||
} DNSLabelFlags;
|
||||
|
||||
int dns_label_unescape(const char **name, char *dest, size_t sz, DNSLabelFlags flags);
|
||||
@ -110,3 +111,5 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret);
|
||||
int dns_name_apply_idna(const char *name, char **ret);
|
||||
|
||||
int dns_name_is_valid_or_address(const char *name);
|
||||
|
||||
int dns_name_dot_suffixed(const char *name);
|
||||
|
@ -780,6 +780,20 @@ static void test_dns_name_is_valid_or_address(void) {
|
||||
assert_se(dns_name_is_valid_or_address("::1") > 0);
|
||||
}
|
||||
|
||||
static void test_dns_name_dot_suffixed(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(dns_name_dot_suffixed("") == 0);
|
||||
assert_se(dns_name_dot_suffixed(".") > 0);
|
||||
assert_se(dns_name_dot_suffixed("foo") == 0);
|
||||
assert_se(dns_name_dot_suffixed("foo.") > 0);
|
||||
assert_se(dns_name_dot_suffixed("foo\\..") > 0);
|
||||
assert_se(dns_name_dot_suffixed("foo\\.") == 0);
|
||||
assert_se(dns_name_dot_suffixed("foo.bar.") > 0);
|
||||
assert_se(dns_name_dot_suffixed("foo.bar\\.\\.\\..") > 0);
|
||||
assert_se(dns_name_dot_suffixed("foo.bar\\.\\.\\.\\.") == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
@ -810,6 +824,7 @@ int main(int argc, char *argv[]) {
|
||||
test_dns_name_common_suffix();
|
||||
test_dns_name_apply_idna();
|
||||
test_dns_name_is_valid_or_address();
|
||||
test_dns_name_dot_suffixed();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user