/* * 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 #include #include #include #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; }