summaryrefslogtreecommitdiff
path: root/src/shared/dns-domain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/dns-domain.c')
-rw-r--r--src/shared/dns-domain.c128
1 files changed, 78 insertions, 50 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index e6aad39c74..4cf6355b71 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -29,6 +29,7 @@
#include "hexdecoct.h"
#include "parse-util.h"
#include "string-util.h"
+#include "strv.h"
#include "utf8.h"
int dns_label_unescape(const char **name, char *dest, size_t sz) {
@@ -181,30 +182,31 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
return r;
}
-int dns_label_escape(const char *p, size_t l, char **ret) {
- _cleanup_free_ char *s = NULL;
+int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
char *q;
- int r;
-
- assert(p);
- assert(ret);
if (l > DNS_LABEL_MAX)
return -EINVAL;
+ if (sz < 1)
+ return -ENOSPC;
- s = malloc(l * 4 + 1);
- if (!s)
- return -ENOMEM;
+ assert(p);
+ assert(dest);
- q = s;
+ q = dest;
while (l > 0) {
if (*p == '.' || *p == '\\') {
+ if (sz < 3)
+ return -ENOSPC;
+
/* Dot or backslash */
*(q++) = '\\';
*(q++) = *p;
+ sz -= 2;
+
} else if (*p == '_' ||
*p == '-' ||
(*p >= '0' && *p <= '9') ||
@@ -212,15 +214,27 @@ int dns_label_escape(const char *p, size_t l, char **ret) {
(*p >= 'A' && *p <= 'Z')) {
/* Proper character */
+
+ if (sz < 2)
+ return -ENOSPC;
+
*(q++) = *p;
+ sz -= 1;
+
} else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
/* Everything else */
+
+ if (sz < 5)
+ return -ENOSPC;
+
*(q++) = '\\';
*(q++) = '0' + (char) ((uint8_t) *p / 100);
*(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
*(q++) = '0' + (char) ((uint8_t) *p % 10);
+ sz -= 4;
+
} else
return -EINVAL;
@@ -229,8 +243,28 @@ int dns_label_escape(const char *p, size_t l, char **ret) {
}
*q = 0;
+ return (int) (q - dest);
+}
+
+int dns_label_escape_new(const char *p, size_t l, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ if (l > DNS_LABEL_MAX)
+ return -EINVAL;
+
+ s = new(char, DNS_LABEL_ESCAPED_MAX);
+ if (!s)
+ return -ENOMEM;
+
+ r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ return r;
+
*ret = s;
- r = q - s;
s = NULL;
return r;
@@ -350,28 +384,32 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
if (k > 0)
r = k;
- r = dns_label_escape(label, r, &t);
- if (r < 0)
- return r;
-
if (_ret) {
- if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
+ r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
+ if (r < 0)
+ return r;
+
if (!first)
- ret[n++] = '.';
- else
- first = false;
+ ret[n] = '.';
+ } else {
+ char escaped[DNS_LABEL_ESCAPED_MAX];
- memcpy(ret + n, t, r);
+ r = dns_label_escape(label, r, escaped, sizeof(escaped));
+ if (r < 0)
+ return r;
}
+ if (!first)
+ n++;
+ else
+ first = false;
+
n += r;
}
- if (n > DNS_NAME_MAX)
- return -EINVAL;
-
if (_ret) {
if (!GREEDY_REALLOC(ret, allocated, n + 1))
return -ENOMEM;
@@ -752,36 +790,27 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) {
return 0;
}
-int dns_name_root(const char *name) {
- char label[DNS_LABEL_MAX+1];
- int r;
+bool dns_name_is_root(const char *name) {
assert(name);
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
+ /* There are exactly two ways to encode the root domain name:
+ * as empty string, or with a single dot. */
- return r == 0 && *name == 0;
+ return STR_IN_SET(name, "", ".");
}
-int dns_name_single_label(const char *name) {
+bool dns_name_is_single_label(const char *name) {
char label[DNS_LABEL_MAX+1];
int r;
assert(name);
r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
- if (r == 0)
- return 0;
-
- r = dns_label_unescape(&name, label, sizeof(label));
- if (r < 0)
- return r;
+ if (r <= 0)
+ return false;
- return r == 0 && *name == 0;
+ return dns_name_is_root(name);
}
/* Encode a domain name according to RFC 1035 Section 3.1 */
@@ -846,12 +875,12 @@ static bool srv_type_label_is_valid(const char *label, size_t n) {
return true;
}
-int dns_srv_type_verify(const char *name) {
+bool dns_srv_type_is_valid(const char *name) {
unsigned c = 0;
int r;
if (!name)
- return 0;
+ return false;
for (;;) {
char label[DNS_LABEL_MAX];
@@ -859,18 +888,16 @@ int dns_srv_type_verify(const char *name) {
/* This more or less implements RFC 6335, Section 5.1 */
r = dns_label_unescape(&name, label, sizeof(label));
- if (r == -EINVAL)
- return 0;
if (r < 0)
- return r;
+ return false;
if (r == 0)
break;
if (c >= 2)
- return 0;
+ return false;
if (!srv_type_label_is_valid(label, r))
- return 0;
+ return false;
c++;
}
@@ -902,14 +929,15 @@ bool dns_service_name_is_valid(const char *name) {
}
int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
- _cleanup_free_ char *escaped = NULL, *n = NULL;
+ char escaped[DNS_LABEL_ESCAPED_MAX];
+ _cleanup_free_ char *n = NULL;
int r;
assert(type);
assert(domain);
assert(ret);
- if (!dns_srv_type_verify(type))
+ if (!dns_srv_type_is_valid(type))
return -EINVAL;
if (!name)
@@ -918,7 +946,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha
if (!dns_service_name_is_valid(name))
return -EINVAL;
- r = dns_label_escape(name, strlen(name), &escaped);
+ r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
if (r < 0)
return r;