Mas experimentación del resolv.conf

master
Félix Arreola Rodríguez 2023-07-25 18:34:23 -06:00
parent 95d4826615
commit 009e568920
7 changed files with 311 additions and 95 deletions

View File

@ -46,7 +46,6 @@
#include "bridge.h"
#include "network-inador-manager.h"
#include "dhcp_client.h"
#include "struct_addr_union.h"
#include "resolv_manager.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
@ -824,20 +823,19 @@ static void _manager_execute_resolvconf_feed (ManagerClientInfo *manager_client,
int name_len, wanted;
unsigned char iface_prog[256];
unsigned char iface_name[256], prog[256];
char value[2048];
char *point;
ResolvConfEntry *entry;
GList *pos_entry;
ResolvConfEntry *resolv_entries;
int entries_count;
int ns_count;
int search_count;
int g, h, pos;
int g, h, pos, ns_pos;
int family;
int order = 0;
struct_addr direccion;
int iface_index;
Interface *iface;
int do_write = 0;
if (buffer_len < 3) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
@ -874,7 +872,8 @@ static void _manager_execute_resolvconf_feed (ManagerClientInfo *manager_client,
if (iface != NULL) {
iface_index = iface->index;
} else {
iface_index = 0;
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
pos = 3 + name_len;
@ -887,6 +886,10 @@ static void _manager_execute_resolvconf_feed (ManagerClientInfo *manager_client,
ns_count = buffer[pos];
pos++;
/* TODO: Sumar las otras entradas */
entries_count = ns_count;
ns_pos = pos;
/* Los nameserver vienen con un byte de familia y luego los bytes correspondientes a la IP */
for (g = 0; g < ns_count; g++) {
/* Revisar que en la longitud venga el byte de la familia */
@ -914,58 +917,40 @@ static void _manager_execute_resolvconf_feed (ManagerClientInfo *manager_client,
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
/* Tengo un Nameserver completo, buscar y dependiendo del caso, actualizar o crear */
memcpy (&direccion, &buffer[pos], wanted);
inet_ntop (family, &direccion, value, sizeof (value));
pos_entry = resolv_parser_search_entry (manager_client->manager->handle->resolver_entries, RESOLV_TYPE_NAMESERVER, family, &direccion, value);
if (pos_entry != NULL) {
/* De ser posible, hacer conciliación */
entry = (ResolvConfEntry *) pos_entry->data;
if (entry->origin == RESOLV_ORIGIN_FILE) {
/* Hacer esta entrada nuestra */
entry->origin = RESOLV_ORIGIN_RESOLVCONF;
entry->owner_interface_index = iface_index;
strncpy (entry->owner_prog, prog, sizeof (entry->owner_prog));
printf ("/// Asociando una entrada %s existente del archivo al: %s\n", entry->value, entry->owner_prog);
} else {
/* Existe la entrada, pero no la podemos tomar como nuestra, crear otra */
entry = NULL;
}
} else {
entry = NULL;
}
/* Si no existe, crearla */
if (entry == NULL) {
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
entry->origin = RESOLV_ORIGIN_RESOLVCONF;
entry->resolv_type = RESOLV_TYPE_NAMESERVER;
entry->file_order = 0;
entry->is_on_file = 0;
entry->priority = 0;
entry->ns_family = family;
memcpy (&entry->nameserver, &direccion, wanted);
strncpy (entry->value, value, sizeof (entry->value));
entry->owner_interface_index = iface_index;
strncpy (entry->owner_prog, prog, sizeof (entry->owner_prog));
/* Anexar al final de la lista */
manager_client->manager->handle->resolver_entries = g_list_append (manager_client->manager->handle->resolver_entries, entry);
/* TODO: Como creamos una entrada via el resolvconf, regenerar el archivo */
printf ("/// Nueva entrada %s via resolvconf, programando regeneración.\n", entry->value);
}
pos += wanted;
}
/* Ahora crear y parsear */
/* TODO: Validar otro tipo de entradas */
/* OK */
/* Notificar al cliente */
_manager_send_executed (manager_client);
/* Re-agrupar los datos para enviarlos al resolv_manager */
resolv_entries = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry) * entries_count);
h = 0;
pos = ns_pos;
for (g = 0; g < ns_count; g++) {
family = buffer[pos];
resolv_entries[h].ns_family = family;
pos++; /* El byte de la familia */
wanted = (family == AF_INET) ? 4 : 16;
/* Tengo un Nameserver completo, buscar y dependiendo del caso, actualizar o crear */
memcpy (&resolv_entries[h].nameserver, &buffer[pos], wanted);
inet_ntop (family, &resolv_entries[h].nameserver, resolv_entries[h].value, sizeof (resolv_entries[h].value));
pos += wanted;
resolv_entries[h].resolv_type = RESOLV_TYPE_NAMESERVER;
resolv_entries[h].origin = RESOLV_ORIGIN_RESOLVCONF;
resolv_entries[h].owner_interface_index = iface_index;
strncpy (resolv_entries[h].owner_prog, prog, sizeof (resolv_entries[h].owner_prog));
h++;
}
resolv_manager_process_resolvconf_entries (manager_client->manager->handle, resolv_entries, entries_count);
}
static void _manager_execute_resolvconf_remove (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {

View File

@ -53,7 +53,8 @@ typedef struct _ResolvConfEntry {
int origin;
int file_order;
int is_on_file;
int tagged;
int for_purge;
int priority;
int ns_family;

View File

@ -40,6 +40,7 @@
#include "resolv_conf_defs.h"
#include "struct_addr_union.h"
#include "resolv_conf_parser.h"
#include "utils.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
@ -75,6 +76,50 @@ int wait_for_ack_or_error (int s) {
return -1;
}
GList * helper_parser_parse_input (GList *all_entries, FILE *fd, int origin) {
char buffer[8192], value[2048];
ResolvConfEntry *entry = NULL;
GList *pos, *next;
int g, len;
struct_addr direccion;
int type;
int family;
int order;
order = 0;
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;
}
/* Desde el resolvconf helper, siempre anexar al final de la lista */
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
entry->resolv_type = type;
entry->origin = origin;
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 = g_list_append (all_entries, entry);
entry->tagged = 1;
entry->file_order = order++;
}
return all_entries;
}
void send_entries (int s, GList *entries, const char *iface_prog) {
char buffer[2048];
int pos, len, pos_name_count;
@ -243,7 +288,7 @@ int main (int argc, char *argv[]) {
if (action == 'a') {
/* Parsear el archivo primero */
entries = resolv_parser_parse_file (NULL, stdin, RESOLV_ORIGIN_RESOLVCONF);
entries = helper_parser_parse_input (NULL, stdin, RESOLV_ORIGIN_RESOLVCONF);
/* Preparar un paquete de datos para enviar via el socket */
send_entries (s, entries, iface_prog);

View File

@ -88,7 +88,7 @@ int resolv_conf_parse_line (const char *line, int *ns_family, struct_addr *names
return -1;
}
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value) {
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value, int skip_tagged) {
GList *g;
ResolvConfEntry *entry;
@ -102,6 +102,12 @@ GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, c
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) {
@ -127,7 +133,7 @@ GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, c
return NULL;
}
GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
GList * resolv_parser_parse_local_file (GList *all_entries, FILE *fd, int origin) {
char buffer[8192], value[2048];
ResolvConfEntry *entry = NULL;
GList *pos, *next;
@ -137,7 +143,7 @@ GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
int family;
int order;
order = 0;
order = 1;
while (fgets (buffer, sizeof (buffer), fd), feof (fd) == 0) {
utils_trim (buffer);
utils_trim_comment (buffer);
@ -150,7 +156,7 @@ GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
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);
pos = resolv_parser_search_entry (all_entries, type, family, &direccion, value, 1);
if (pos != NULL) {
/* Ya existe, refrescar que está en el archivo */
@ -161,6 +167,7 @@ GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
entry->resolv_type = type;
entry->origin = origin;
entry->for_purge = 0;
entry->ns_family = family;
memcpy (&entry->nameserver, &direccion, sizeof (direccion));
@ -171,7 +178,7 @@ GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
all_entries = g_list_append (all_entries, entry);
}
entry->is_on_file = 1;
entry->tagged = 1;
entry->file_order = order++;
}

View File

@ -32,8 +32,9 @@
#include "common.h"
#endif
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value);
GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin);
int resolv_conf_parse_line (const char *line, int *ns_family, struct_addr *nameserver, char *value, const size_t value_size);
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value, int skip_on_file);
GList * resolv_parser_parse_local_file (GList *all_entries, FILE *fd, int origin);
#endif /* __RESOLV_CONF_PARSER_H__ */

View File

@ -27,40 +27,154 @@
#include <ctype.h>
#include <sys/inotify.h>
#include "resolv_manager.h"
#include "common.h"
#include "utils.h"
#include "resolv_conf_parser.h"
#include "interfaces.h"
void resolv_manager_write (NetworkInadorHandle *handle);
gint resolv_manager_sort_entries (const void *a, const void *b, gpointer data) {
const ResolvConfEntry *aa = (ResolvConfEntry *) a;
const ResolvConfEntry *bb = (ResolvConfEntry *) b;
/* Primero, las purgadas van al final */
if (aa->for_purge == 1 && bb->for_purge == 0) {
return 1;
} else if (aa->for_purge == 0 && bb->for_purge == 1) {
return -1;
} else if (aa->for_purge == 1) {
return 0;
}
if (aa->tagged == 1 && bb->tagged == 0) {
/* TODO: Revisar este orden por prioridades */
return -1;
} else if (aa->tagged == 0 && bb->tagged == 1) {
return 1;
} else if (aa->tagged == 1) {
/* Como los dos están en el archivo, comparar por el file_order */
return (aa->file_order - bb->file_order);
}
/* TODO: Estas entradas necesitan resolverse por prioridad de configuración */
return 0;
}
void resolv_manager_clear_entries_by_prog (NetworkInadorHandle *handle, const int iface_index, const char *prog) {
GList *g, *next;
GList *g;
ResolvConfEntry *entry;
int do_write = 0;
g = handle->resolver_entries;
while (g != NULL) {
next = g->next;
entry = (ResolvConfEntry *) g->data;
if (entry->origin != RESOLV_ORIGIN_RESOLVCONF) {
/* Solo borramos las entradas creadas via resolvconf */
g = next;
g = g->next;
continue;
}
if (entry->owner_interface_index != iface_index) {
g = next;
g = g->next;
continue;
}
if (prog == NULL || strcmp (entry->owner_prog, prog) == 0) {
/* Hay que eliminar esta entrada, coincide por la interfaz o nombre de programa */
printf ("/// Eliminando entrada %s por via resolvconf. Prog = «%s»\n", entry->value, prog);
free (entry);
/*free (entry);
handle->resolver_entries = g_list_delete_link (handle->resolver_entries, g);
handle->resolver_entries = g_list_delete_link (handle->resolver_entries, g);*/
entry->for_purge = 1;
do_write = 1;
}
g = next;
g = g->next;
}
/* Solicitar una escritura del archivo, via el resolvconf fuimos modificados */
if (do_write == 1) {
resolv_manager_write (handle);
}
}
void resolv_manager_clear_tag_on_all (NetworkInadorHandle *handle) {
GList *pos;
ResolvConfEntry *entry;
/* Borrar el atributo "tagged" */
pos = handle->resolver_entries;
while (pos != NULL) {
entry = (ResolvConfEntry *) pos->data;
entry->tagged = 0;
pos = pos->next;
}
}
void resolv_manager_process_resolvconf_entries (NetworkInadorHandle *handle, ResolvConfEntry *entries, int num_entries) {
int g;
ResolvConfEntry *entry;
GList *pos_entry;
int do_write = 0;
resolv_manager_clear_tag_on_all (handle);
for (g = 0; g < num_entries; g++) {
entry = NULL;
while (entry == NULL) {
pos_entry = resolv_parser_search_entry (handle->resolver_entries, entries[g].resolv_type, entries[g].ns_family, &entries[g].nameserver, entries[g].value, 1);
if (pos_entry == NULL) break;
/* De ser posible, hacer conciliación */
entry = (ResolvConfEntry *) pos_entry->data;
if (entry->origin == RESOLV_ORIGIN_FILE) {
/* Hacer esta entrada nuestra */
entry->origin = RESOLV_ORIGIN_RESOLVCONF;
entry->owner_interface_index = entries[g].owner_interface_index;
entry->tagged = 1;
strncpy (entry->owner_prog, entries[g].owner_prog, sizeof (entry->owner_prog));
printf ("/// Asociando una entrada %s existente del archivo al: %s\n", entry->value, entry->owner_prog);
} else if (entry->origin == RESOLV_ORIGIN_DHCP) {
/* Una entrada que coincide con la actual solo se puede re-asociar al resolvconf si pertenece a la misma interfaz */
if (entry->owner_interface_index != entries[g].owner_interface_index) {
entry->tagged = 1;
entry = NULL;
continue;
}
} else {
/* Existe la entrada, pero no la podemos tomar como nuestra, crear otra */
entry->tagged = 1;
entry = NULL;
continue;
}
}
/* Si no existe, crearla */
if (entry == NULL) {
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
memcpy (entry, &entries[g], sizeof (ResolvConfEntry));
entry->file_order = g; /* TODO: Revisar esto del file order */
entry->tagged = 0;
entry->priority = 0;
entry->for_purge = 0;
/* Anexar al final de la lista */
handle->resolver_entries = g_list_append (handle->resolver_entries, entry);
/* TODO: Como creamos una entrada via el resolvconf, regenerar el archivo */
printf ("/// Nueva entrada %s via resolvconf, programando regeneración.\n", entry->value);
do_write = 1;
}
}
/* Si hubo actualización cambios, disparar ahora */
if (do_write == 1) {
resolv_manager_write (handle);
}
}
@ -74,34 +188,101 @@ void resolv_manager_read_local_etc_resolv (NetworkInadorHandle *handle) {
printf ("/// Ejecutando lectura de resolv.conf\n");
/* Etiquetar las entradas con origen del archivo como "ya no en el archivo", para que cuando se lea el archivo, nos queden las que vamos a eliminar */
/* Borrar cuáles están en el archivo */
pos = handle->resolver_entries;
while (pos != NULL) {
entry = (ResolvConfEntry *) pos->data;
entry->is_on_file = 0;
pos = pos->next;
}
resolv_manager_clear_tag_on_all (handle);
handle->resolver_entries = resolv_parser_parse_file (handle->resolver_entries, fd, RESOLV_ORIGIN_FILE);
handle->resolver_entries = resolv_parser_parse_local_file (handle->resolver_entries, fd, RESOLV_ORIGIN_FILE);
fclose (fd);
/* A la salida, borrar las que ya no siguen en el archivo */
pos = handle->resolver_entries;
while (pos != NULL) {
next = pos->next;
//next = pos->next;
entry = (ResolvConfEntry *) pos->data;
if (entry->origin == RESOLV_ORIGIN_FILE && entry->is_on_file == 0) {
if (entry->origin == RESOLV_ORIGIN_FILE && entry->tagged == 0) {
/* Esta entrada se va, la eliminaron */
printf ("/// La entrada %s del resolv.conf fué eliminada del archivo. Purgando nosotros.\n", entry->value);
entry->for_purge = 1;
/*handle->resolver_entries = g_list_delete_link (handle->resolver_entries, pos);
free (entry);
entry = NULL;*/
} else {
printf ("/// La entrada %s del resolv.conf sigue en el archivo.\n", entry->value);
}
pos = pos->next;
}
/* Reordenar las entradas. TODO: Falta leer los ficheros de configuración del resolv.conf */
handle->resolver_entries = g_list_sort_with_data (handle->resolver_entries, resolv_manager_sort_entries, NULL);
}
void resolv_manager_write (NetworkInadorHandle *handle) {
FILE *fd;
GList *pos, *next;
ResolvConfEntry *entry;
Interface *iface;
/* Antes de hacer la escritura, siempre hacemos una lectura */
resolv_manager_read_local_etc_resolv (handle);
/* Intentar la escritura */
fd = fopen ("/etc/resolv.conf", "w");
if (fd != NULL) {
fprintf (fd, "# Autogenered by NetworkInador, you can change this file, changes are preserved");
fprintf (fd, "\n\n");
pos = handle->resolver_entries;
while (pos != NULL) {
entry = (ResolvConfEntry *) pos->data;
if (entry->for_purge == 1) {
/* Omitir */
pos = pos->next;
continue;
}
iface = _interfaces_locate_by_index (handle->interfaces, entry->owner_interface_index);
/* Escribir esta entrada "buena" al resolv.conf */
if (entry->origin == RESOLV_ORIGIN_FILE) {
fprintf (fd, "# This entry was previously on file, preserving");
} else if (entry->origin == RESOLV_ORIGIN_DHCP) {
fprintf (fd, "# This entry was added via DHCP (on %s) via NetworkInador", (iface != NULL ? iface->name : "unknown"));
} else if (entry->origin == RESOLV_ORIGIN_RESOLVCONF) {
fprintf (fd, "# This entry was added via resolvconf (%s.%s)", (iface != NULL ? iface->name : "unknown"), entry->owner_prog);
} else if (entry->origin == RESOLV_ORIGIN_SLAAC_RDNSS) {
fprintf (fd, "# This entry was added via RDNSS (IPv6)");
}
fprintf (fd, "\n");
if (entry->resolv_type == RESOLV_TYPE_NAMESERVER) {
fprintf (fd, "nameserver %s\n", entry->value);
} else if (entry->resolv_type == RESOLV_TYPE_DOMAIN) {
fprintf (fd, "domain %s\n", entry->value);
} else if (entry->resolv_type == RESOLV_TYPE_SEARCH) {
fprintf (fd, "search %s\n", entry->value);
} else if (entry->resolv_type == RESOLV_TYPE_SORTLIST) {
fprintf (fd, "sortlist %s\n", entry->value);
} else if (entry->resolv_type == RESOLV_TYPE_OPTIONS) {
fprintf (fd, "options %s\n", entry->value);
}
pos = pos->next;
}
fclose (fd);
}
/* Purgar las entradas marcadas para purge */
pos = handle->resolver_entries;
while (pos != NULL) {
next = pos->next;
entry = (ResolvConfEntry *) pos->data;
if (entry->for_purge == 1) {
handle->resolver_entries = g_list_delete_link (handle->resolver_entries, pos);
free (entry);
entry = NULL;
} else {
printf ("/// La entrada %s del resolv.conf sigue en el archivo.\n", entry->value);
}
pos = next;
}
@ -125,13 +306,5 @@ void resolv_manager_init (NetworkInadorHandle *handle) {
handle->resolver_entries = NULL;
/* Luego, leer el resolv.conf */
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
}

View File

@ -23,11 +23,15 @@
#ifndef __RESOLV_MANAGER_H__
#define __RESOLV_MANAGER_H__
#include "common.h"
#include "struct_addr_union.h"
#include "resolv_conf_parser.h"
#include "resolv_conf_defs.h"
void resolv_manager_init (NetworkInadorHandle *handle);
void resolv_manager_clear_entries_by_prog (NetworkInadorHandle *handle, const int iface_index, const char *prog);
void resolv_manager_process_resolvconf_entries (NetworkInadorHandle *handle, ResolvConfEntry *entries, int num_entries);
//void resolv_manager_clear_tag_on_all (NetworkInadorHandle *handle);
//void resolv_manager_write (NetworkInadorHandle *handle);
#endif /* __RESOLV_MANAGER_H__ */