diff options
author | Nick Owens <nick.owens@coreos.com> | 2015-06-02 11:49:43 -0700 |
---|---|---|
committer | Nick Owens <nick.owens@coreos.com> | 2015-06-10 11:15:45 -0700 |
commit | 4ad7f2761da661853dcc29d542efb4727abb1101 (patch) | |
tree | 03b8323c906c775a7cdb626314a82baf7eef9018 /src/resolve/resolved-dns-domain.c | |
parent | a8467435a0c4962cab89574f65e7318ef389351f (diff) |
resolve: move dns routines into shared
Diffstat (limited to 'src/resolve/resolved-dns-domain.c')
-rw-r--r-- | src/resolve/resolved-dns-domain.c | 613 |
1 files changed, 0 insertions, 613 deletions
diff --git a/src/resolve/resolved-dns-domain.c b/src/resolve/resolved-dns-domain.c deleted file mode 100644 index e1eb3ddfe5..0000000000 --- a/src/resolve/resolved-dns-domain.c +++ /dev/null @@ -1,613 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. - ***/ - -#ifdef HAVE_LIBIDN -#include <idna.h> -#include <stringprep.h> -#endif - -#include "resolved-dns-domain.h" - -int dns_label_unescape(const char **name, char *dest, size_t sz) { - const char *n; - char *d; - int r = 0; - - assert(name); - assert(*name); - assert(dest); - - n = *name; - d = dest; - - for (;;) { - if (*n == '.') { - n++; - break; - } - - if (*n == 0) - break; - - if (sz <= 0) - return -ENOSPC; - - if (r >= DNS_LABEL_MAX) - return -EINVAL; - - if (*n == '\\') { - /* Escaped character */ - - n++; - - if (*n == 0) - /* Ending NUL */ - return -EINVAL; - - else if (*n == '\\' || *n == '.') { - /* Escaped backslash or dot */ - *(d++) = *(n++); - sz--; - r++; - - } else if (n[0] >= '0' && n[0] <= '9') { - unsigned k; - - /* Escaped literal ASCII character */ - - if (!(n[1] >= '0' && n[1] <= '9') || - !(n[2] >= '0' && n[2] <= '9')) - return -EINVAL; - - k = ((unsigned) (n[0] - '0') * 100) + - ((unsigned) (n[1] - '0') * 10) + - ((unsigned) (n[2] - '0')); - - /* Don't allow CC characters or anything that doesn't fit in 8bit */ - if (k < ' ' || k > 255 || k == 127) - return -EINVAL; - - *(d++) = (char) k; - sz--; - r++; - - n += 3; - } else - return -EINVAL; - - } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) { - - /* Normal character */ - *(d++) = *(n++); - sz--; - r++; - } else - return -EINVAL; - } - - /* Empty label that is not at the end? */ - if (r == 0 && *n) - return -EINVAL; - - if (sz >= 1) - *d = 0; - - *name = n; - return r; -} - -int dns_label_escape(const char *p, size_t l, char **ret) { - _cleanup_free_ char *s = NULL; - char *q; - int r; - - assert(p); - assert(ret); - - if (l > DNS_LABEL_MAX) - return -EINVAL; - - s = malloc(l * 4 + 1); - if (!s) - return -ENOMEM; - - q = s; - while (l > 0) { - - if (*p == '.' || *p == '\\') { - - /* Dot or backslash */ - *(q++) = '\\'; - *(q++) = *p; - - } else if (*p == '_' || - *p == '-' || - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z')) { - - /* Proper character */ - *(q++) = *p; - } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) { - - /* Everything else */ - *(q++) = '\\'; - *(q++) = '0' + (char) ((uint8_t) *p / 100); - *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); - *(q++) = '0' + (char) ((uint8_t) *p % 10); - - } else - return -EINVAL; - - p++; - l--; - } - - *q = 0; - *ret = s; - r = q - s; - s = NULL; - - return r; -} - -int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { -#ifdef HAVE_LIBIDN - _cleanup_free_ uint32_t *input = NULL; - size_t input_size; - const char *p; - bool contains_8bit = false; - - assert(encoded); - assert(decoded); - assert(decoded_max >= DNS_LABEL_MAX); - - if (encoded_size <= 0) - return 0; - - for (p = encoded; p < encoded + encoded_size; p++) - if ((uint8_t) *p > 127) - contains_8bit = true; - - if (!contains_8bit) - return 0; - - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - if (idna_to_ascii_4i(input, input_size, decoded, 0) != 0) - return -EINVAL; - - return strlen(decoded); -#else - return 0; -#endif -} - -int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { -#ifdef HAVE_LIBIDN - size_t input_size, output_size; - _cleanup_free_ uint32_t *input = NULL; - _cleanup_free_ char *result = NULL; - uint32_t *output = NULL; - size_t w; - - /* To be invoked after unescaping */ - - assert(encoded); - assert(decoded); - - if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1) - return 0; - - if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0) - return 0; - - input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); - if (!input) - return -ENOMEM; - - output_size = input_size; - output = newa(uint32_t, output_size); - - idna_to_unicode_44i(input, input_size, output, &output_size, 0); - - result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w); - if (!result) - return -ENOMEM; - if (w <= 0) - return 0; - if (w+1 > decoded_max) - return -EINVAL; - - memcpy(decoded, result, w+1); - return w; -#else - return 0; -#endif -} - -int dns_name_normalize(const char *s, char **_ret) { - _cleanup_free_ char *ret = NULL; - size_t n = 0, allocated = 0; - const char *p = s; - bool first = true; - int r; - - assert(s); - - for (;;) { - _cleanup_free_ char *t = NULL; - char label[DNS_LABEL_MAX]; - int k; - - r = dns_label_unescape(&p, label, sizeof(label)); - if (r < 0) - return r; - if (r == 0) { - if (*p != 0) - return -EINVAL; - break; - } - - k = dns_label_undo_idna(label, r, label, sizeof(label)); - if (k < 0) - return k; - if (k > 0) - r = k; - - r = dns_label_escape(label, r, &t); - if (r < 0) - return r; - - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) - return -ENOMEM; - - if (!first) - ret[n++] = '.'; - else - first = false; - - memcpy(ret + n, t, r); - n += r; - } - - if (n > DNS_NAME_MAX) - return -EINVAL; - - if (!GREEDY_REALLOC(ret, allocated, n + 1)) - return -ENOMEM; - - ret[n] = 0; - - if (_ret) { - *_ret = ret; - ret = NULL; - } - - return 0; -} - -unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) { - const char *p = s; - unsigned long ul = hash_key[0]; - int r; - - assert(p); - - while (*p) { - char label[DNS_LABEL_MAX+1]; - int k; - - r = dns_label_unescape(&p, label, sizeof(label)); - if (r < 0) - break; - - k = dns_label_undo_idna(label, r, label, sizeof(label)); - if (k < 0) - break; - if (k > 0) - r = k; - - label[r] = 0; - ascii_strlower(label); - - ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key); - } - - return ul; -} - -int dns_name_compare_func(const void *a, const void *b) { - const char *x = a, *y = b; - int r, q, k, w; - - assert(a); - assert(b); - - for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; - - if (*x == 0 && *y == 0) - return 0; - - r = dns_label_unescape(&x, la, sizeof(la)); - q = dns_label_unescape(&y, lb, sizeof(lb)); - if (r < 0 || q < 0) - return r - q; - - k = dns_label_undo_idna(la, r, la, sizeof(la)); - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); - if (k < 0 || w < 0) - return k - w; - if (k > 0) - r = k; - if (w > 0) - r = w; - - la[r] = lb[q] = 0; - r = strcasecmp(la, lb); - if (r != 0) - return r; - } -} - -const struct hash_ops dns_name_hash_ops = { - .hash = dns_name_hash_func, - .compare = dns_name_compare_func -}; - -int dns_name_equal(const char *x, const char *y) { - int r, q, k, w; - - assert(x); - assert(y); - - for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; - - if (*x == 0 && *y == 0) - return true; - - r = dns_label_unescape(&x, la, sizeof(la)); - if (r < 0) - return r; - - k = dns_label_undo_idna(la, r, la, sizeof(la)); - if (k < 0) - return k; - if (k > 0) - r = k; - - q = dns_label_unescape(&y, lb, sizeof(lb)); - if (q < 0) - return q; - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); - if (w < 0) - return w; - if (w > 0) - q = w; - - la[r] = lb[q] = 0; - if (strcasecmp(la, lb)) - return false; - } -} - -int dns_name_endswith(const char *name, const char *suffix) { - const char *n, *s, *saved_n = NULL; - int r, q, k, w; - - assert(name); - assert(suffix); - - n = name; - s = suffix; - - for (;;) { - char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; - - r = dns_label_unescape(&n, ln, sizeof(ln)); - if (r < 0) - return r; - k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); - if (k < 0) - return k; - if (k > 0) - r = k; - - if (!saved_n) - saved_n = n; - - q = dns_label_unescape(&s, ls, sizeof(ls)); - if (q < 0) - return q; - w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); - if (w < 0) - return w; - if (w > 0) - q = w; - - if (r == 0 && q == 0) - return true; - if (r == 0 && saved_n == n) - return false; - - ln[r] = ls[q] = 0; - - if (r != q || strcasecmp(ln, ls)) { - - /* Not the same, let's jump back, and try with the next label again */ - s = suffix; - n = saved_n; - saved_n = NULL; - } - } -} - -int dns_name_reverse(int family, const union in_addr_union *a, char **ret) { - const uint8_t *p; - int r; - - assert(a); - assert(ret); - - p = (const uint8_t*) a; - - if (family == AF_INET) - r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]); - else if (family == AF_INET6) - r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa", - hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4), - hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4), - hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4), - hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4), - hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4), - hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4), - hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4), - hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4)); - else - return -EAFNOSUPPORT; - if (r < 0) - return -ENOMEM; - - return 0; -} - -int dns_name_address(const char *p, int *family, union in_addr_union *address) { - int r; - - assert(p); - assert(family); - assert(address); - - r = dns_name_endswith(p, "in-addr.arpa"); - if (r < 0) - return r; - if (r > 0) { - uint8_t a[4]; - unsigned i; - - for (i = 0; i < ELEMENTSOF(a); i++) { - char label[DNS_LABEL_MAX+1]; - - r = dns_label_unescape(&p, label, sizeof(label)); - if (r < 0) - return r; - if (r == 0) - return -EINVAL; - if (r > 3) - return -EINVAL; - - r = safe_atou8(label, &a[i]); - if (r < 0) - return r; - } - - r = dns_name_equal(p, "in-addr.arpa"); - if (r <= 0) - return r; - - *family = AF_INET; - address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | - ((uint32_t) a[2] << 16) | - ((uint32_t) a[1] << 8) | - (uint32_t) a[0]); - - return 1; - } - - r = dns_name_endswith(p, "ip6.arpa"); - if (r < 0) - return r; - if (r > 0) { - struct in6_addr a; - unsigned i; - - for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) { - char label[DNS_LABEL_MAX+1]; - int x, y; - - r = dns_label_unescape(&p, label, sizeof(label)); - if (r <= 0) - return r; - if (r != 1) - return -EINVAL; - x = unhexchar(label[0]); - if (x < 0) - return -EINVAL; - - r = dns_label_unescape(&p, label, sizeof(label)); - if (r <= 0) - return r; - if (r != 1) - return -EINVAL; - y = unhexchar(label[0]); - if (y < 0) - return -EINVAL; - - a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x; - } - - r = dns_name_equal(p, "ip6.arpa"); - if (r <= 0) - return r; - - *family = AF_INET6; - address->in6 = a; - return 1; - } - - return 0; -} - -int dns_name_root(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; - - return r == 0 && *name == 0; -} - -int dns_name_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; - - return r == 0 && *name == 0; -} |