dns-domain.c revision 0cf40f5527501f80044c1a2612781dd552d46591
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering/***
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering This file is part of systemd.
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering Copyright 2014 Lennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart 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
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
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 Poettering ***/
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#ifdef HAVE_LIBIDN
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <idna.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <stringprep.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#endif
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <endian.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <netinet/in.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <stdio.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <string.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include <sys/socket.h>
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "alloc-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "dns-domain.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "hashmap.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "hexdecoct.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "in-addr-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "macro.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "parse-util.h"
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering#include "string-util.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "strv.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#include "utf8.h"
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_unescape(const char **name, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *d;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(*name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = *name;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering d = dest;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (;;) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == '.') {
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer n++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r >= DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == '\\') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*n == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Ending NUL */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (*n == '\\' || *n == '.') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped backslash or dot */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (d)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(d++) = *n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (n[0] >= '0' && n[0] <= '9') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Escaped literal ASCII character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!(n[1] >= '0' && n[1] <= '9') ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering !(n[2] >= '0' && n[2] <= '9'))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = ((unsigned) (n[0] - '0') * 100) +
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((unsigned) (n[1] - '0') * 10) +
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((unsigned) (n[2] - '0'));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 * inside. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k > 255)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (d)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(d++) = (char) k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n += 3;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Normal character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (d)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(d++) = *n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Empty label that is not at the end? */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == 0 && *n)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz >= 1 && d)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *d = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *name = n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 Poettering * labels. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *terminal;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(label_terminal);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(dest);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* no more labels */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!*label_terminal) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz >= 1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *dest = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
b92bea5d2a9481de69bb627a7b442a9f58fca43dZbigniew Jędrzejewski-Szmek terminal = *label_terminal;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(*terminal == '.' || *terminal == 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Skip current terminal character (and accept domain names ending it ".") */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*terminal == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering terminal--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (terminal >= name && *terminal == '.')
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering terminal--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (;;) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (terminal < name) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Reached the first label, so indicate that there are no more */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering terminal = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Find the start of the last label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*terminal == '.') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *y;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned slashes = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (y = terminal - 1; y >= name && *y == '\\'; y--)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering slashes ++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (slashes % 2 == 0) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* The '.' was not escaped */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering name = terminal + 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering terminal = y;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering continue;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering terminal --;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&name, dest, sz);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *label_terminal = terminal;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char *q;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 * 11. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz < 1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(dest);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = dest;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering while (l > 0) {
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (*p == '.' || *p == '\\') {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Dot or backslash */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz < 3)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = '\\';
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz -= 2;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else if (*p == '_' ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *p == '-' ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (*p >= '0' && *p <= '9') ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (*p >= 'a' && *p <= 'z') ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering (*p >= 'A' && *p <= 'Z')) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Proper character */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz < 2)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *(q++) = *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz -= 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Everything else */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (sz < 5)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering sz -= 4;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p++;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna l--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *q = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return (int) (q - dest);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_escape_new(const char *p, size_t l, char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *s = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l <= 0 || l > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = new(char, DNS_LABEL_ESCAPED_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!s)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *ret = s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering s = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#ifdef HAVE_LIBIDN
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ uint32_t *input = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t input_size, l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering bool contains_8bit = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char buffer[DNS_LABEL_MAX+1];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(encoded);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(decoded);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Converts an U-label into an A-label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size <= 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -EINVAL;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (p = encoded; p < encoded + encoded_size; p++)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if ((uint8_t) *p > 127)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering contains_8bit = true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!contains_8bit) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!input)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering l = strlen(buffer);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (l > decoded_max)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering memcpy(decoded, buffer, l);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* If there's room, append a trailing NUL byte, but only then */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (decoded_max > l)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering decoded[l] = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return (int) l;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#endif
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar}
2f7a4867babd3fd382e5495f21724358f30fa67dMichal Sekletar
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering#ifdef HAVE_LIBIDN
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t input_size, output_size;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ uint32_t *input = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering _cleanup_free_ char *result = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering uint32_t *output = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t w;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* To be invoked after unescaping. Converts an A-label into an U-label. */
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering assert(encoded);
0affed79d2e30013f07cb94e6f07e3fcb81c02faLennart Poettering assert(decoded);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!input)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna output_size = input_size;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna output = newa(uint32_t, output_size);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna idna_to_unicode_44i(input, input_size, output, &output_size, 0);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (!result)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -ENOMEM;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (w <= 0)
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer return -EINVAL;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (w > decoded_max)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -ENOBUFS;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna memcpy(decoded, result, w);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* Append trailing NUL byte if there's space, but only then. */
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (decoded_max > w)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna decoded[w] = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return w;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna#else
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna#endif
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna}
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagnaint dns_name_concat(const char *a, const char *b, char **_ret) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna _cleanup_free_ char *ret = NULL;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna size_t n = 0, allocated = 0;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna const char *p = a;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna bool first = true;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek int r;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna assert(a);
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek for (;;) {
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek char label[DNS_LABEL_MAX];
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek int k;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = dns_label_unescape(&p, label, sizeof(label));
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return r;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r == 0) {
8333c77edf8fd1654cd96f3f6ee0f078dd64b58bZbigniew Jędrzejewski-Szmek if (*p != 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -EINVAL;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (b) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna /* Now continue with the second string, if there is one */
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek p = b;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna b = NULL;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna continue;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna }
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna break;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna }
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna k = dns_label_undo_idna(label, r, label, sizeof(label));
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (k < 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return k;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (k > 0)
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna r = k;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (_ret) {
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna return -ENOMEM;
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
17d33cecaa762f7e43200307328af5e9135e2091Giovanni Campagna if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek if (!first)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ret[n] = '.';
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } else {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char escaped[DNS_LABEL_ESCAPED_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_escape(label, r, escaped, sizeof(escaped));
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersen if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
bac3c8eefe23a820caac930d41629cebafbfc7b2Zbigniew Jędrzejewski-Szmek }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!first)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen first = false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n += r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (n > DNS_HOSTNAME_MAX)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (_ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (!GREEDY_REALLOC(ret, allocated, n + 1))
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ret[n] = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *_ret = ret;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ret = NULL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringvoid dns_name_hash_func(const void *s, struct siphash *state) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const char *p = s;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (;;) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char label[DNS_LABEL_MAX+1];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(label, r, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering break;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ascii_strlower_n(label, r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering siphash24_compress(label, r, state);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* enforce that all names are terminated by the empty label */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering string_hash_func("", state);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(b);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering x = (const char *) a + strlen(a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y = (const char *) b + strlen(b);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (;;) {
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
ef42202ac8ed27e7ff1fc90ef8bc2590046dff25Zbigniew Jędrzejewski-Szmek
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (x == NULL && y == NULL)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 return r - q;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyer if (r > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(la, r, la, sizeof(la));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (q > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering w = 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k < 0 || w < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return k - w;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (w > 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = w;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = ascii_strcasecmp_nn(la, r, lb, q);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringconst struct hash_ops dns_name_hash_ops = {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering .hash = dns_name_hash_func,
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering .compare = dns_name_compare_func
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering};
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
7c2d80944afb4196f2eff614e8da1450dffcbeaaThomas Hindoe Paaboel Andersenstatic int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Clobbers all arguments on failure... */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(name, dest, sz);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering k = dns_label_undo_idna(dest, r, dest, sz);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (k == 0) /* not an IDNA name */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_equal(const char *x, const char *y) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r, q;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(x);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(y);
6b2b6f30e38d67b032d6bdc6b47ae05e143e96c5Michal Schmidt
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (;;) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape_undo_idna(&x, la, sizeof(la));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering q = dns_label_unescape_undo_idna(&y, lb, sizeof(lb));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (q < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return q;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r != q)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return true;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (ascii_strcasecmp_n(la, lb, r) != 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
7fd1b19bc9e9f5574f2877936b8ac267c7706947Harald Hoyerint dns_name_endswith(const char *name, const char *suffix) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering const char *n, *s, *saved_n = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r, q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(suffix);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = name;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s = suffix;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (;;) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
c62e11ce3966c55d23520b9f0785c7e839cf7f37Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!saved_n)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering saved_n = n;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (q < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && q == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return true;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && saved_n == n)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return false;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Not the same, let's jump back, and try with the next label again */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s = suffix;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = saved_n;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering saved_n = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint dns_name_startswith(const char *name, const char *prefix) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering const char *n, *p;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering int r, q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(prefix);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = name;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering p = prefix;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (;;) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&p, lp, sizeof(lp));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return true;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (q < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r != q)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return false;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (ascii_strcasecmp_n(ln, lp, r) != 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return false;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
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 int r, q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(old_suffix);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(new_suffix);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering assert(ret);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering n = name;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s = old_suffix;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering for (;;) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!saved_before)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering saved_before = n;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (!saved_after)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering saved_after = n;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls));
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (q < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return q;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && q == 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering break;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r == 0 && saved_after == n) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *ret = NULL; /* doesn't match */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
82c1d8f4eb74ddd9be2c9b9b56d9dc564c599effLennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Not the same, let's jump back, and try with the next label again */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering s = old_suffix;
2927b326ccf67236e148444679f582ea1437ef5aJan Janssen n = saved_after;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering saved_after = saved_before = NULL;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering /* Found it! Now generate the new name */
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering prefix = strndupa(name, saved_before - name);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_name_concat(prefix, new_suffix, ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 1;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering}
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poetteringint dns_name_between(const char *a, const char *b, const char *c) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int n;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering n = dns_name_compare_func(a, c);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (n == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (n < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* a<---b--->c */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return dns_name_compare_func(a, b) < 0 &&
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_name_compare_func(b, c) < 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* <--b--c a--b--> */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return dns_name_compare_func(b, c) < 0 ||
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering dns_name_compare_func(a, b) < 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering const uint8_t *p;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(a);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(ret);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering p = (const uint8_t*) a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen if (family == AF_INET)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering else if (family == AF_INET6)
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 Poettering else
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EAFNOSUPPORT;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOMEM;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringint dns_name_address(const char *p, int *family, union in_addr_union *address) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(p);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(family);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(address);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_endswith(p, "in-addr.arpa");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen if (r > 0) {
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen uint8_t a[4];
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen unsigned i;
546158bc6f46f8004cc11e81d19d223e0da56730Jan Janssen
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < ELEMENTSOF(a); i++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char label[DNS_LABEL_MAX+1];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r == 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r > 3)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = safe_atou8(label, &a[i]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_equal(p, "in-addr.arpa");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *family = AF_INET;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((uint32_t) a[2] << 16) |
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ((uint32_t) a[1] << 8) |
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering (uint32_t) a[0]);
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return 1;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering }
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering r = dns_name_endswith(p, "ip6.arpa");
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r < 0)
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering return r;
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering if (r > 0) {
50cfc579280fb42569488079bd2e249e32a27df2Lennart Poettering struct in6_addr a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering unsigned i;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering char label[DNS_LABEL_MAX+1];
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int x, y;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r != 1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering x = unhexchar(label[0]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (x < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_label_unescape(&p, label, sizeof(label));
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r != 1)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering y = unhexchar(label[0]);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (y < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_equal(p, "ip6.arpa");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *family = AF_INET6;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering address->in6 = a;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 1;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering }
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return 0;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool dns_name_is_root(const char *name) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* There are exactly two ways to encode the root domain name:
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering * as empty string, or with a single dot. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return STR_IN_SET(name, "", ".");
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringbool dns_name_is_single_label(const char *name) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering r = dns_name_parent(&name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (r <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return false;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return dns_name_is_root(name);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 uint8_t *label_length, *out;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering int r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(domain);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering assert(buffer);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering out = buffer;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering do {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Reserve a byte for label length */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (len <= 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -ENOBUFS;
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner len--;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering label_length = out;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering out++;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 if (r < 0)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 if (canonical)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering ascii_strlower_n((char*) out, (size_t) r);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering /* Fill label length, move forward */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering *label_length = r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering out += r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering len -= r;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering } while (r != 0);
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
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 Poettering * time. */
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering if (out - buffer > DNS_HOSTNAME_MAX + 2)
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return -EINVAL;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering return out - buffer;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering}
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poetteringstatic bool srv_type_label_is_valid(const char *label, size_t n) {
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering size_t k;
2087a7aff26ea5d1bc2c7c29add3275328f36baaLennart Poettering
assert(label);
if (n < 2) /* Label needs to be at least 2 chars long */
return false;
if (label[0] != '_') /* First label char needs to be underscore */
return false;
/* Second char must be a letter */
if (!(label[1] >= 'A' && label[1] <= 'Z') &&
!(label[1] >= 'a' && label[1] <= 'z'))
return false;
/* Third and further chars must be alphanumeric or a hyphen */
for (k = 2; k < n; k++) {
if (!(label[k] >= 'A' && label[k] <= 'Z') &&
!(label[k] >= 'a' && label[k] <= 'z') &&
!(label[k] >= '0' && label[k] <= '9') &&
label[k] != '-')
return false;
}
return true;
}
bool dns_srv_type_is_valid(const char *name) {
unsigned c = 0;
int r;
if (!name)
return false;
for (;;) {
char label[DNS_LABEL_MAX];
/* This more or less implements RFC 6335, Section 5.1 */
r = dns_label_unescape(&name, label, sizeof(label));
if (r < 0)
return false;
if (r == 0)
break;
if (c >= 2)
return false;
if (!srv_type_label_is_valid(label, r))
return false;
c++;
}
return c == 2; /* exactly two labels */
}
bool dns_service_name_is_valid(const char *name) {
size_t l;
/* This more or less implements RFC 6763, Section 4.1.1 */
if (!name)
return false;
if (!utf8_is_valid(name))
return false;
if (string_has_cc(name, NULL))
return false;
l = strlen(name);
if (l <= 0)
return false;
if (l > 63)
return false;
return true;
}
int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
char escaped[DNS_LABEL_ESCAPED_MAX];
_cleanup_free_ char *n = NULL;
int r;
assert(type);
assert(domain);
assert(ret);
if (!dns_srv_type_is_valid(type))
return -EINVAL;
if (!name)
return dns_name_concat(type, domain, ret);
if (!dns_service_name_is_valid(name))
return -EINVAL;
r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
if (r < 0)
return r;
r = dns_name_concat(type, domain, &n);
if (r < 0)
return r;
return dns_name_concat(escaped, n, ret);
}
static bool dns_service_name_label_is_valid(const char *label, size_t n) {
char *s;
assert(label);
if (memchr(label, 0, n))
return false;
s = strndupa(label, n);
return dns_service_name_is_valid(s);
}
int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
_cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
const char *p = joined, *q = NULL, *d = NULL;
char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
int an, bn, cn, r;
unsigned x = 0;
assert(joined);
/* Get first label from the full name */
an = dns_label_unescape(&p, a, sizeof(a));
if (an < 0)
return an;
if (an > 0) {
x++;
/* If there was a first label, try to get the second one */
bn = dns_label_unescape(&p, b, sizeof(b));
if (bn < 0)
return bn;
if (bn > 0) {
x++;
/* If there was a second label, try to get the third one */
q = p;
cn = dns_label_unescape(&p, c, sizeof(c));
if (cn < 0)
return cn;
if (cn > 0)
x++;
} else
cn = 0;
} else
an = 0;
if (x >= 2 && srv_type_label_is_valid(b, bn)) {
if (x >= 3 && srv_type_label_is_valid(c, cn)) {
if (dns_service_name_label_is_valid(a, an)) {
/* OK, got <name> . <type> . <type2> . <domain> */
name = strndup(a, an);
if (!name)
return -ENOMEM;
type = strjoin(b, ".", c, NULL);
if (!type)
return -ENOMEM;
d = p;
goto finish;
}
} else if (srv_type_label_is_valid(a, an)) {
/* OK, got <type> . <type2> . <domain> */
name = NULL;
type = strjoin(a, ".", b, NULL);
if (!type)
return -ENOMEM;
d = q;
goto finish;
}
}
name = NULL;
type = NULL;
d = joined;
finish:
r = dns_name_normalize(d, &domain);
if (r < 0)
return r;
if (_domain) {
*_domain = domain;
domain = NULL;
}
if (_type) {
*_type = type;
type = NULL;
}
if (_name) {
*_name = name;
name = NULL;
}
return 0;
}
static int dns_name_build_suffix_table(const char *name, const char*table[]) {
const char *p;
unsigned n = 0;
int r;
assert(name);
assert(table);
p = name;
for (;;) {
if (n > DNS_N_LABELS_MAX)
return -EINVAL;
table[n] = p;
r = dns_name_parent(&p);
if (r < 0)
return r;
if (r == 0)
break;
n++;
}
return (int) n;
}
int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) {
const char* labels[DNS_N_LABELS_MAX+1];
int n;
assert(name);
assert(ret);
n = dns_name_build_suffix_table(name, labels);
if (n < 0)
return n;
if ((unsigned) n < n_labels)
return -EINVAL;
*ret = labels[n - n_labels];
return (int) (n - n_labels);
}
int dns_name_skip(const char *a, unsigned n_labels, const char **ret) {
int r;
assert(a);
assert(ret);
for (; n_labels > 0; n_labels --) {
r = dns_name_parent(&a);
if (r < 0)
return r;
if (r == 0) {
*ret = "";
return 0;
}
}
*ret = a;
return 1;
}
int dns_name_count_labels(const char *name) {
unsigned n = 0;
const char *p;
int r;
assert(name);
p = name;
for (;;) {
r = dns_name_parent(&p);
if (r < 0)
return r;
if (r == 0)
break;
if (n >= DNS_N_LABELS_MAX)
return -EINVAL;
n++;
}
return (int) n;
}
int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) {
int r;
assert(a);
assert(b);
r = dns_name_skip(a, n_labels, &a);
if (r <= 0)
return r;
return dns_name_equal(a, b);
}
int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1];
int n = 0, m = 0, k = 0, r, q;
assert(a);
assert(b);
assert(ret);
/* Determines the common suffix of domain names a and b */
n = dns_name_build_suffix_table(a, a_labels);
if (n < 0)
return n;
m = dns_name_build_suffix_table(b, b_labels);
if (m < 0)
return m;
for (;;) {
char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
const char *x, *y;
if (k >= n || k >= m) {
*ret = a_labels[n - k];
return 0;
}
x = a_labels[n - 1 - k];
r = dns_label_unescape_undo_idna(&x, la, sizeof(la));
if (r < 0)
return r;
y = b_labels[m - 1 - k];
q = dns_label_unescape_undo_idna(&y, lb, sizeof(lb));
if (q < 0)
return q;
if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) {
*ret = a_labels[n - k];
return 0;
}
k++;
}
}
int dns_name_apply_idna(const char *name, char **ret) {
_cleanup_free_ char *buf = NULL;
size_t n = 0, allocated = 0;
bool first = true;
int r, q;
assert(name);
assert(ret);
for (;;) {
char label[DNS_LABEL_MAX];
r = dns_label_unescape(&name, label, sizeof(label));
if (r < 0)
return r;
if (r == 0)
break;
q = dns_label_apply_idna(label, r, label, sizeof(label));
if (q < 0)
return q;
if (q > 0)
r = q;
if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
return r;
if (first)
first = false;
else
buf[n++] = '.';
n +=r;
}
if (n > DNS_HOSTNAME_MAX)
return -EINVAL;
if (!GREEDY_REALLOC(buf, allocated, n + 1))
return -ENOMEM;
buf[n] = 0;
*ret = buf;
buf = NULL;
return (int) n;
}