dns-domain.c revision 0cf40f5527501f80044c1a2612781dd552d46591
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2014 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is free software; you can redistribute it and/or modify it
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering under the terms of the GNU Lesser General Public License as published by
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (at your option) any later version.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering systemd is distributed in the hope that it will be useful, but
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Lesser General Public License for more details.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering You should have received a copy of the GNU Lesser General Public License
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_unescape(const char **name, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == '.') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == '\\') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Ending NUL */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped backslash or dot */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped literal ASCII character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Don't allow anything that doesn't
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * fit in 8bit. Note that we do allow
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * control characters, as some servers
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * (e.g. cloudflare) are happy to
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * generate labels with them
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(d++) = (char) k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Normal character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Empty label that is not at the end? */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == 0 && *n)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* @label_terminal: terminal character of a label, updated to point to the terminal character of
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * the previous label (always skipping one dot) or to NULL if there are no more
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* no more labels */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(*terminal == '.' || *terminal == 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Skip current terminal character (and accept domain names ending it ".") */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (terminal >= name && *terminal == '.')
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Reached the first label, so indicate that there are no more */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Find the start of the last label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *y;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (y = terminal - 1; y >= name && *y == '\\'; y--)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* The '.' was not escaped */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* DNS labels must be between 1 and 63 characters long. A
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * zero-length label does not exist. See RFC 2182, Section
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (l > 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Dot or backslash */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '\\';
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (*p == '_' ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Proper character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Everything else */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '\\';
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '0' + (char) ((uint8_t) *p / 100);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '0' + (char) ((uint8_t) *p % 10);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return (int) (q - dest);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_escape_new(const char *p, size_t l, char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Converts an U-label into an A-label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (p = encoded; p < encoded + encoded_size; p++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Verify that the the result is not longer than one DNS label. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If there's room, append a trailing NUL byte, but only then */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return (int) l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* To be invoked after unescaping. Converts an A-label into an U-label. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna idna_to_unicode_44i(input, input_size, output, &output_size, 0);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* Append trailing NUL byte if there's space, but only then. */
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnaint dns_name_concat(const char *a, const char *b, char **_ret) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna const char *p = a;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = dns_label_unescape(&p, label, sizeof(label));
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* Now continue with the second string, if there is one */
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna k = dns_label_undo_idna(label, r, label, sizeof(label));
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_escape(label, r, escaped, sizeof(escaped));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!GREEDY_REALLOC(ret, allocated, n + 1))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid dns_name_hash_func(const void *s, struct siphash *state) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *p = s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(label, r, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* enforce that all names are terminated by the empty label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_compare_func(const void *a, const void *b) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *x, *y;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, q, k, w;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering x = (const char *) a + strlen(a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y = (const char *) b + strlen(b);
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0 || q < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(la, r, la, sizeof(la));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k < 0 || w < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringconst struct hash_ops dns_name_hash_ops = {
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersenstatic int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Clobbers all arguments on failure... */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(dest, r, dest, sz);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k == 0) /* not an IDNA name */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_equal(const char *x, const char *y) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape_undo_idna(&x, la, sizeof(la));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = dns_label_unescape_undo_idna(&y, lb, sizeof(lb));
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyerint dns_name_endswith(const char *name, const char *suffix) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && q == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && saved_n == n)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Not the same, let's jump back, and try with the next label again */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint dns_name_startswith(const char *name, const char *prefix) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering const char *n, *p;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&p, lp, sizeof(lp));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && q == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && saved_after == n) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Not the same, let's jump back, and try with the next label again */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Found it! Now generate the new name */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering prefix = strndupa(name, saved_before - name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_name_concat(prefix, new_suffix, ret);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint dns_name_between(const char *a, const char *b, const char *c) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Determine if b is strictly greater than a and strictly smaller than c.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering We consider the order of names to be circular, so that if a is
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering strictly greater than c, we consider b to be between them if it is
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering either greater than a or smaller than c. This is how the canonical
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering DNS name order used in NSEC records work. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (n < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* a<---b--->c */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return dns_name_compare_func(a, b) < 0 &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* <--b--c a--b--> */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return dns_name_compare_func(b, c) < 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p = (const uint8_t*) a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering 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",
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_address(const char *p, int *family, union in_addr_union *address) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_endswith(p, "in-addr.arpa");
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen if (r > 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < ELEMENTSOF(a); i++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* There are exactly two ways to encode the root domain name:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * as empty string, or with a single dot. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool dns_name_is_single_label(const char *name) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/* Encode a domain name according to RFC 1035 Section 3.1, without compression */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Reserve a byte for label length */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Convert and copy a single label. Note that
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * dns_label_unescape() returns 0 when it hits the end
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * of the domain name, which we rely on here to encode
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * the trailing NUL byte. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&domain, (char *) out, len);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Optionally, output the name in DNSSEC canonical
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * format, as described in RFC 4034, section 6.2. Or
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * in other words: in lower-case. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ascii_strlower_n((char*) out, (size_t) r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Fill label length, move forward */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } while (r != 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Verify the maximum size of the encoded name. The trailing
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * dot + NUL byte account are included this time, hence
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool srv_type_label_is_valid(const char *label, size_t n) {
if (!name)
size_t l;
if (!name)
return -EINVAL;
if (!name)
return -EINVAL;
return dns_service_name_is_valid(s);
if (an < 0)
return an;
if (an > 0) {
if (bn < 0)
return bn;
if (bn > 0) {
if (cn < 0)
return cn;
if (cn > 0)
cn = 0;
an = 0;
if (!name)
return -ENOMEM;
if (!type)
return -ENOMEM;
goto finish;
if (!type)
return -ENOMEM;
goto finish;
d = joined;
if (_domain) {
if (_type) {
if (_name) {
p = name;
if (n > DNS_N_LABELS_MAX)
return -EINVAL;
table[n] = p;
r = dns_name_parent(&p);
if ((unsigned) n < n_labels)
return -EINVAL;
return (int) (n - n_labels);
assert(a);
r = dns_name_parent(&a);
*ret = a;
p = name;
r = dns_name_parent(&p);
if (n >= DNS_N_LABELS_MAX)
return -EINVAL;
assert(a);
assert(b);
return dns_name_equal(a, b);
assert(a);
assert(b);
bool first = true;
return -ENOMEM;
if (first)
first = false;
if (n > DNS_HOSTNAME_MAX)
return -EINVAL;
return -ENOMEM;
buf[n] = 0;