184 lines
5.0 KiB
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;
|
||
|
}
|
||
|
|