diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 19:05:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 19:05:44 +0000 |
commit | b045529c40c83601909dca7b76a53498e9a70f33 (patch) | |
tree | 88371572105933fd950676c07b3a12163a0c9de0 /src/utils/common/resolv.c | |
parent | Initial commit. (diff) | |
download | knot-b045529c40c83601909dca7b76a53498e9a70f33.tar.xz knot-b045529c40c83601909dca7b76a53498e9a70f33.zip |
Adding upstream version 3.3.4.upstream/3.3.4
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/utils/common/resolv.c')
-rw-r--r-- | src/utils/common/resolv.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/utils/common/resolv.c b/src/utils/common/resolv.c new file mode 100644 index 0000000..674a760 --- /dev/null +++ b/src/utils/common/resolv.c @@ -0,0 +1,211 @@ +/* Copyright (C) 2023 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "utils/common/resolv.h" +#include "utils/common/msg.h" +#include "utils/common/params.h" +#include "libknot/libknot.h" +#include "contrib/ucw/lists.h" + +#define RESOLV_FILE "/etc/resolv.conf" + +srv_info_t* parse_nameserver(const char *str, const char *def_port) +{ + char *host = NULL, *port = NULL; + const char *addr = NULL, *sep = NULL; + size_t addr_len = 0; + char separator = ':'; + + if (str == NULL || def_port == NULL) { + DBG_NULL; + return NULL; + } + + const size_t str_len = strlen(str); + const char *str_end = str + str_len; + + // UNIX socket path. + if (*str == '/') { + return srv_info_create(str, "UNIX"); + // [address]:port notation. + } else if (*str == '[') { + addr = str + 1; + const char *addr_end = strchr(addr, ']'); + // Missing closing bracket -> stop processing. + if (addr_end == NULL) { + return NULL; + } + addr_len = addr_end - addr; + str += 1 + addr_len + 1; + // Address@port notation. + } else if ((sep = strchr(str, '@')) != NULL) { + addr = str; + addr_len = sep - addr; + str += addr_len; + separator = '@'; + // Address#port notation. + } else if ((sep = strchr(str, '#')) != NULL) { + addr = str; + addr_len = sep - addr; + str += addr_len; + separator = '#'; + // IPv4:port notation. + } else if ((sep = strchr(str, ':')) != NULL) { + addr = str; + // Not IPv4 address -> no port. + if (strchr(sep + 1, ':') != NULL) { + addr_len = str_len; + str = str_end; + } else { + addr_len = sep - addr; + str += addr_len; + } + // No port specified. + } else { + addr = str; + addr_len = str_len; + str = str_end; + } + + // Process port. + if (str < str_end) { + // Check port separator. + if (*str != separator) { + return NULL; + } + str++; + + // Check for missing port. + if (str >= str_end) { + return NULL; + } + + port = strdup(str); + } else { + port = strdup(def_port); + } + + host = strndup(addr, addr_len); + + // Create server structure. + srv_info_t *server = srv_info_create(host, port); + + free(host); + free(port); + + return server; +} + +static size_t get_resolv_nameservers(list_t *servers, const char *def_port) +{ + char line[512]; + + // Open config file. + FILE *f = fopen(RESOLV_FILE, "r"); + if (f == NULL) { + return 0; + } + + // Read lines from config file. + while (fgets(line, sizeof(line), f) != NULL) { + size_t len; + char *pos = line; + char *option, *value; + + // Find leading white characters. + len = strspn(pos, SEP_CHARS); + pos += len; + + // Start of the first token. + option = pos; + + // Find length of the token. + len = strcspn(pos, SEP_CHARS); + pos += len; + + // Check if the token is not empty. + if (len == 0) { + continue; + } + + // Find separating white characters. + len = strspn(pos, SEP_CHARS); + pos += len; + + // Check if there is a separation between tokens. + if (len == 0) { + continue; + } + + // Copy of the second token. + value = strndup(pos, strcspn(pos, SEP_CHARS)); + + // Process value with respect to option name. + if (strncmp(option, "nameserver", strlen("nameserver")) == 0) { + srv_info_t *server; + + server = parse_nameserver(value, def_port); + + // If value is correct, add nameserver to the list. + if (server != NULL) { + add_tail(servers, (node_t *)server); + } + } + + // Drop value string. + free(value); + } + + // Close config file. + fclose(f); + + // Return number of servers. + return list_size(servers); +} + +void get_nameservers(list_t *servers, const char *def_port) +{ + if (servers == NULL || def_port == NULL) { + DBG_NULL; + return; + } + + // Initialize list of servers. + init_list(servers); + + // Read nameservers from resolv file or use the default ones. + if (get_resolv_nameservers(servers, def_port) == 0) { + srv_info_t *server; + + // Add default ipv6 nameservers. + server = srv_info_create(DEFAULT_IPV6_NAME, def_port); + + if (server != NULL) { + add_tail(servers, (node_t *)server); + } + + // Add default ipv4 nameservers. + server = srv_info_create(DEFAULT_IPV4_NAME, def_port); + + if (server != NULL) { + add_tail(servers, (node_t *)server); + } + } +} |