NetworkInador/common/resolv_conf_parser.c

184 lines
5.0 KiB
C

/*
* resolv_conf_parser.c
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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 2 of the License, or
* (at your option) any later version.
*
* NetworkInador 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 NetworkInador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "resolv_conf_defs.h"
#include "resolv_conf_parser.h"
#include "utils.h"
#include "flist.h"
static const char *resolv_conf_keywords[NUM_RESOLV_TYPES] = {
"nameserver",
"domain",
"search",
"sortlist",
"options"
};
int resolv_conf_parse_line (const char *line, int *ns_family, struct_addr *nameserver, char *value, const size_t value_size) {
int g, len;
int af;
struct_addr temp_addr;
int ret;
/* Recorrer cada palabra clave posible de los resolv.conf */
for (g = 0; g < NUM_RESOLV_TYPES; g++) {
len = strlen (resolv_conf_keywords[g]);
if (strncmp (line, resolv_conf_keywords[g], len) == 0 && line[len] == ' ') {
if (g == RESOLV_TYPE_NAMESERVER) {
/* Los nameserver solo pueden ser direcciones IP de IPv4 o IPv6 */
af = AF_INET;
ret = inet_pton (AF_INET, &line[len + 1], &temp_addr);
if (ret == 0) {
af = AF_INET6;
ret = inet_pton (AF_INET6, &line[len + 1], &temp_addr);
}
if (ret == 0) {
/* No es una dirección IP, ignorar */
break;
}
} else {
/* Revisar por posibles restricciones en otros tipos */
}
strncpy (value, &line[len + 1], value_size);
value[value_size - 1] = 0;
if (g == RESOLV_TYPE_NAMESERVER) {
*ns_family = af;
memcpy (nameserver, &temp_addr, sizeof (temp_addr));
} else {
*ns_family = AF_UNSPEC;
memset (nameserver, 0, sizeof (temp_addr));
}
return g;
}
}
/* No es alguna linea válida */
return -1;
}
FList * resolv_parser_search_entry (FList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value, int skip_tagged) {
FList *g;
ResolvConfEntry *entry;
g = all_entries;
while (g != NULL) {
entry = (ResolvConfEntry *) g->data;
if (resolv_type != entry->resolv_type) {
/* Pasar a la siguiente entrada, no es del mismo tipo */
g = g->next;
continue;
}
if (skip_tagged == 1 && entry->tagged == 1) {
/* Pasar a la siguiente entrada, nos pidieron omitir las marcadas en el archivo */
g = g->next;
continue;
}
/* Comparar dependiendo del tipo */
if (resolv_type == RESOLV_TYPE_NAMESERVER) {
if (ns_family == AF_INET && entry->ns_family == AF_INET) {
if (memcmp (nameserver, &entry->nameserver, sizeof (struct in_addr)) == 0) {
/* Es la entrada que andamos buscando */
return g;
}
} else if (ns_family == AF_INET6 && entry->ns_family == AF_INET6) {
if (memcmp (nameserver, &entry->nameserver, sizeof (struct in6_addr)) == 0) {
return g;
}
}
} else {
/* TODO: Revisar si las otras entradas requieren otro tipo de comparación */
if (strcmp (value, entry->value) == 0) {
return g;
}
}
g = g->next;
}
return NULL;
}
FList * resolv_parser_parse_local_file (FList *all_entries, FILE *fd, int origin) {
char buffer[8192], value[2048];
ResolvConfEntry *entry = NULL;
FList *pos, *next;
int g, len;
struct_addr direccion;
int type;
int family;
int order;
order = 1;
while (fgets (buffer, sizeof (buffer), fd), feof (fd) == 0) {
utils_trim (buffer);
utils_trim_comment (buffer);
if (buffer[0] == 0) continue;
type = resolv_conf_parse_line (buffer, &family, &direccion, value, sizeof (value));
if (type == -1) {
/* Linea no válida de acuerdo al parser, ignorar */
continue;
}
/* Tenemos una linea buena, buscar si esta linea ya existe en nuestra lista de entradas */
pos = resolv_parser_search_entry (all_entries, type, family, &direccion, value, 1);
if (pos != NULL) {
/* Ya existe, refrescar que está en el archivo */
entry = (ResolvConfEntry *) pos->data;
} else {
/* Como no existe, crear y anexar al final de la lista */
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
entry->resolv_type = type;
entry->origin = origin;
entry->for_purge = 0;
entry->ns_family = family;
memcpy (&entry->nameserver, &direccion, sizeof (direccion));
strncpy (entry->value, value, sizeof (entry->value));
entry->owner_interface_index = 0;
entry->owner_prog[0] = 0;
all_entries = f_list_append (all_entries, entry);
}
entry->tagged = 1;
entry->file_order = order++;
}
return all_entries;
}