1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "resolved-dns-domain.h"
24 int dns_label_unescape(const char **name, char *dest, size_t sz) {
49 /* Escaped character */
57 else if (*n == '\\' || *n == '.') {
58 /* Escaped backslash or dot */
63 } else if (n[0] >= '0' && n[0] <= '9') {
66 /* Escaped literal ASCII character */
68 if (!(n[1] >= '0' && n[1] <= '9') ||
69 !(n[2] >= '0' && n[2] <= '9'))
72 k = ((unsigned) (n[0] - '0') * 100) +
73 ((unsigned) (n[1] - '0') * 10) +
74 ((unsigned) (n[2] - '0'));
76 /* Don't allow CC characters or anything that doesn't fit in 8bit */
77 if (k < ' ' || k > 255 || k == 127)
88 } else if (*n >= ' ' && *n != 127) {
90 /* Normal character */
98 /* Empty label that is not at the end? */
109 int dns_label_escape(const char *p, size_t l, char **ret) {
110 _cleanup_free_ char *s = NULL;
117 s = malloc(l * 4 + 1);
124 if (*p == '.' || *p == '\\') {
126 /* Dot or backslash */
130 } else if (*p == '_' ||
132 (*p >= '0' && *p <= '9') ||
133 (*p >= 'a' && *p <= 'z') ||
134 (*p >= 'A' && *p <= 'Z')) {
136 /* Proper character */
138 } else if (*p >= ' ' && *p != 127) {
140 /* Everything else */
142 *(q++) = '0' + (char) ((unsigned) *p / 100);
143 *(q++) = '0' + (char) (((unsigned) *p / 10) % 10);
144 *(q++) = '0' + (char) ((unsigned) *p % 10);
161 int dns_name_normalize(const char *s, char **_ret) {
162 _cleanup_free_ char *ret = NULL;
163 size_t n = 0, allocated = 0;
172 _cleanup_free_ char *t = NULL;
173 char label[DNS_LABEL_MAX];
175 r = dns_label_unescape(&p, label, sizeof(label));
184 r = dns_label_escape(label, r, &t);
188 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
196 memcpy(ret + n, t, r);
200 if (!GREEDY_REALLOC(ret, allocated, n + 1))
210 unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
212 unsigned long ul = 0;
218 char label[DNS_LABEL_MAX+1];
220 r = dns_label_unescape(&p, label, sizeof(label));
225 ascii_strlower(label);
227 ul = hash_key[0] * ul + ul + string_hash_func(label, hash_key);
233 int dns_name_compare_func(const void *a, const void *b) {
234 const char *x = a, *y = b;
241 char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
243 if (*x == 0 && *y == 0)
246 r = dns_label_unescape(&x, la, sizeof(la));
247 q = dns_label_unescape(&y, lb, sizeof(lb));
252 r = strcasecmp(la, lb);
258 int dns_name_equal(const char *x, const char *y) {
265 char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
267 if (*x == 0 && *y == 0)
270 r = dns_label_unescape(&x, la, sizeof(la));
274 q = dns_label_unescape(&y, lb, sizeof(lb));
279 if (strcasecmp(la, lb))
284 int dns_name_endswith(const char *name, const char *suffix) {
285 const char *n, *s, *saved_n = NULL;
295 char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1];
297 r = dns_label_unescape(&n, ln, sizeof(ln));
304 q = dns_label_unescape(&s, ls, sizeof(ls));
308 if (r == 0 && q == 0)
310 if (r == 0 && saved_n == n)
315 if (r != q || strcasecmp(ln, ls)) {
317 /* Not the same, let's jump back, and try with the next label again */
325 int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
332 p = (const uint8_t*) a;
334 if (family == AF_INET)
335 r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
336 else if (family == AF_INET6)
337 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",
338 hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
339 hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
340 hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
341 hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
342 hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
343 hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
344 hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
345 hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
347 return -EAFNOSUPPORT;
354 int dns_name_root(const char *name) {
355 char label[DNS_LABEL_MAX+1];
360 r = dns_label_unescape(&name, label, sizeof(label));
364 return r == 0 && *name == 0;
367 int dns_name_single_label(const char *name) {
368 char label[DNS_LABEL_MAX+1];
373 r = dns_label_unescape(&name, label, sizeof(label));
380 r = dns_label_unescape(&name, label, sizeof(label));
384 return r == 0 && *name == 0;