dns-domain.c revision 1dfbf0007af3023c2e3ae8282a0d0f229f3a89e3
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2014 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringint dns_label_unescape(const char **name, char *dest, size_t sz) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *n;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (*n == '.') {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (*n == '\\') {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Escaped character */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* Ending NUL */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* Escaped backslash or dot */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering *(d++) = *(n++);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Escaped literal ASCII character */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Don't allow CC characters or anything that doesn't fit in 8bit */
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering *(d++) = (char) k;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek /* Normal character */
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek *(d++) = *(n++);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek /* Empty label that is not at the end? */
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (r == 0 && *n)
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen/* @label_terminal: terminal character of a label, updated to point to the terminal character of
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen * the previous label (always skipping one dot) or to NULL if there are no more
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersenint dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* no more labels */
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek assert(**label_terminal == '.' || **label_terminal == 0);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* skip current terminal character */
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* reached the first label, so indicate that there are no more */
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek /* find the start of the last label */
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen unsigned slashes = 0;
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen for (y = terminal - 1; y >= name && *y == '\\'; y--)
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen /* the '.' was not escaped */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringint dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
7c1ff6ac3d9e3acae1d601d40728cf7ccc9a7730Tom Gundersen /* DNS labels must be between 1 and 63 characters long. A
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen * zero-length label does not exist. See RFC 2182, Section
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering while (l > 0) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* Dot or backslash */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering *(q++) = '\\';
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt } else if (*p == '_' ||
return -ENOSPC;
return -ENOSPC;
return -EINVAL;
return (int) (q - dest);
assert(p);
if (l <= 0 || l > DNS_LABEL_MAX)
return -EINVAL;
return -ENOMEM;
*ret = s;
s = NULL;
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
#ifdef HAVE_LIBIDN
bool contains_8bit = false;
if (encoded_size <= 0)
return -EINVAL;
contains_8bit = true;
if (!contains_8bit) {
return -EINVAL;
if (!input)
return -ENOMEM;
return -EINVAL;
if (l <= 0 || l > DNS_LABEL_MAX)
return -EINVAL;
if (l > decoded_max)
return -ENOSPC;
if (decoded_max > l)
decoded[l] = 0;
int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
#ifdef HAVE_LIBIDN
size_t w;
return -EINVAL;
if (!input)
return -ENOMEM;
if (!result)
return -ENOMEM;
return -EINVAL;
if (w > decoded_max)
return -ENOSPC;
if (decoded_max > w)
decoded[w] = 0;
bool first = true;
assert(a);
return -EINVAL;
b = NULL;
if (_ret) {
return -ENOMEM;
if (!first)
if (!first)
first = false;
if (n > DNS_HOSTNAME_MAX)
return -EINVAL;
if (_ret) {
return -ENOMEM;
ret[n] = 0;
assert(p);
label[r] = 0;
int dns_name_compare_func(const void *a, const void *b) {
assert(a);
assert(b);
x = (const char *) a + strlen(a);
y = (const char *) b + strlen(b);
int dns_name_equal(const char *x, const char *y) {
assert(x);
assert(y);
n = name;
s = suffix;
if (!saved_n)
saved_n = n;
if (r == 0 && saved_n == n)
s = suffix;
n = saved_n;
int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
n = name;
s = old_suffix;
if (!saved_before)
saved_before = n;
if (!saved_after)
saved_after = n;
if (r == 0 && saved_after == n) {
s = old_suffix;
n = saved_after;
int dns_name_between(const char *a, const char *b, const char *c) {
n = dns_name_compare_func(a, c);
return -EINVAL;
return dns_name_compare_func(a, b) < 0 &&
dns_name_compare_func(b, c) < 0;
return dns_name_compare_func(b, c) < 0 ||
dns_name_compare_func(a, b) < 0;
const uint8_t *p;
assert(a);
p = (const uint8_t*) a;
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",
return -EAFNOSUPPORT;
return -ENOMEM;
assert(p);
for (i = 0; i < ELEMENTSOF(a); i++) {
return -EINVAL;
return -EINVAL;
(uint32_t) a[0]);
struct in6_addr a;
return -EINVAL;
return -EINVAL;
return -EINVAL;
return -EINVAL;
if (len == 0)
return -ENOBUFS;
len--;
out++;
*label_length = r;
out += r;
len -= r;
size_t k;
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) {