mirror of
https://github.com/systemd/systemd.git
synced 2025-01-13 17:18:18 +03:00
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.
This commit is contained in:
parent
7e8131e9c6
commit
422baca0f2
@ -360,7 +360,6 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
|
||||
/* End of name */
|
||||
break;
|
||||
else if (c <= 63) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
const char *label;
|
||||
|
||||
/* Literal label */
|
||||
@ -369,21 +368,20 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char *
|
||||
if (pos > optlen)
|
||||
return -EMSGSIZE;
|
||||
|
||||
r = dns_label_escape(label, c, &t);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) {
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
ret[n++] = '.';
|
||||
else
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ret[n++] = '.';
|
||||
|
||||
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
memcpy(ret + n, t, r);
|
||||
n += r;
|
||||
continue;
|
||||
} else {
|
||||
|
@ -1145,7 +1145,6 @@ int dns_packet_read_name(
|
||||
/* End of name */
|
||||
break;
|
||||
else if (c <= 63) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
const char *label;
|
||||
|
||||
/* Literal label */
|
||||
@ -1153,21 +1152,20 @@ int dns_packet_read_name(
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = dns_label_escape(label, c, &t);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
|
||||
if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
|
||||
r = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
ret[n++] = '.';
|
||||
else
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ret[n++] = '.';
|
||||
|
||||
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
memcpy(ret + n, t, r);
|
||||
n += r;
|
||||
continue;
|
||||
} else if (allow_compression && (c & 0xc0) == 0xc0) {
|
||||
|
@ -351,7 +351,7 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = dns_label_escape(label, r, &n);
|
||||
r = dns_label_escape_new(label, r, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to escape host name: %m");
|
||||
|
||||
|
@ -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;
|
||||
|
||||
if (!first)
|
||||
ret[n++] = '.';
|
||||
else
|
||||
first = false;
|
||||
r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memcpy(ret + n, t, r);
|
||||
if (!first)
|
||||
ret[n] = '.';
|
||||
} else {
|
||||
char escaped[DNS_LABEL_ESCAPED_MAX];
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -126,7 +126,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
|
||||
r = dns_label_escape(what, l, &t);
|
||||
r = dns_label_escape_new(what, l, &t);
|
||||
assert_se(r == ret);
|
||||
|
||||
if (r < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user