summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-11-25 21:56:48 +0100
committerLennart Poettering <lennart@poettering.net>2015-11-25 22:00:07 +0100
commit422baca0f230913158078fddf884e06c8c64a316 (patch)
treef43086c3de4206488dbc7f8accaad9c629da93ca /src/shared
parent7e8131e9c6c150732503899a092206578fdc13de (diff)
dns-domain: rework dns_label_escape() to not imply memory allocation
The new dns_label_escape() call now operates on a buffer passed in, similar to dns_label_unescape(). This should make decoding a bit faster, and nicer.
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/dns-domain.c88
-rw-r--r--src/shared/dns-domain.h5
2 files changed, 66 insertions, 27 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 5a9b091ac4..4cf6355b71 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -182,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') ||
@@ -213,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;
@@ -230,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;
@@ -351,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;
@@ -892,7 +929,8 @@ 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);
@@ -908,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;
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 2f557d618e..99c72574db 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -26,11 +26,12 @@
#include "in-addr-util.h"
#define DNS_LABEL_MAX 63
-#define DNS_NAME_MAX 255
+#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1)
int dns_label_unescape(const char **name, char *dest, size_t sz);
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
-int dns_label_escape(const char *p, size_t l, char **ret);
+int dns_label_escape(const char *p, size_t l, char *dest, size_t sz);
+int dns_label_escape_new(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);