/* * rtables.c * This file is part of Network-inador * * Copyright (C) 2025 - Félix Arreola Rodríguez * * Network-inador 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. * * Network-inador 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 Network-inador; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include "flist.h" #include "network-inador-private.h" #include "rtables.h" #include "event_notify.h" #include "file_watcher.h" static int _routes_table_find_by_number (const void * left, const void * right) { RouteTable *a, *b; a = (RouteTable *) left; b = (RouteTable *) right; return a->table != b->table; } static void _routes_table_parse_file (NetworkInadorHandle *handle, FILE *fd) { FList *g; int ret; RouteTable *rtable, temp_table; char buffer[2048]; while (fgets (buffer, sizeof (buffer), fd), feof (fd) == 0) { if (buffer[0] == '#') continue; /* Ignorar las lineas con comentarios */ ret = sscanf (buffer, "%d %s", &(temp_table.table), temp_table.name); if (ret < 2) { continue; } if (temp_table.table == 0) continue; /* Omitir la tabla número 0 */ g = f_list_find_custom (handle->route_tables_names, &temp_table, _routes_table_find_by_number); if (g != NULL) { /* El número de tabla ya existe, marcar y actualizar el nombre */ rtable = (RouteTable *) g->data; printf ("Tabla ya existe en la lista ligada: %d\n", temp_table.table); rtable->for_delete = 0; rtable->was_new = 0; } else { printf ("Creando tabla en la lista ligada: %i, %s\n", temp_table.table, temp_table.name); /* No existe, crear nueva */ rtable = (RouteTable *) malloc (sizeof (RouteTable)); rtable->table = temp_table.table; rtable->for_delete = 0; rtable->was_new = 1; handle->route_tables_names = f_list_append (handle->route_tables_names, rtable); handle->rtables_counter++; } /* En cualquier caso actualizar el nombre */ strncpy (rtable->name, temp_table.name, sizeof (rtable->name)); } } static void routes_tables_read_all (NetworkInadorHandle *handle, int do_notify) { FILE *fd; FList *g, *h; RouteTable *rtable; DIR *dir; struct dirent *direntry; int len; char buffer[4096]; g = handle->route_tables_names; while (g != NULL) { rtable = (RouteTable *) g->data; rtable->for_delete = 1; rtable->was_new = 0; g = g->next; } /* Intentar abrir /etc/iproute2/rt_tables */ fd = fopen ("/etc/iproute2/rt_tables", "r"); if (fd != NULL) { printf ("Parsing main rt_tables file\n"); _routes_table_parse_file (handle, fd); fclose (fd); } /* Ahora leer todo el directorio /etc/iproute2/rt_tables.d/ y buscar archivos *.conf */ dir = opendir ("/etc/iproute2/rt_tables.d"); if (dir != NULL) { while (direntry = readdir (dir), direntry != NULL) { len = strlen (direntry->d_name); /* Buscar por archivos que terminen en .conf */ if (len > 5 && strcmp (&(direntry->d_name[len - 5]), ".conf") == 0) { /* Intentar abrir este archivo y parsearlo */ snprintf (buffer, sizeof (buffer), "/etc/iproute2/rt_tables.d/%s", direntry->d_name); printf ("Parsing %s secundary\n", buffer); fd = fopen (buffer, "r"); if (fd != NULL) { _routes_table_parse_file (handle, fd); fclose (fd); } } } closedir (dir); } /* Ahora, todas las tablas que están marcadas para eliminar, eliminarlas */ g = handle->route_tables_names; while (g != NULL) { h = g->next; rtable = (RouteTable *) g->data; if (rtable->for_delete) { handle->route_tables_names = f_list_delete_link (handle->route_tables_names, g); handle->rtables_counter--; if (do_notify) { network_manager_trigger_route_table_deleted_event (handle, rtable->table); } free (rtable); } g = h; } g = handle->route_tables_names; while (g != NULL) { rtable = (RouteTable *) g->data; if (rtable->was_new) { if (do_notify) { network_manager_trigger_route_table_added_event (handle, rtable->table, rtable->name); } rtable->was_new = 0; } g = g->next; } } static void rtables_notify_close_write_cb (NetworkInadorHandle *handle, const char *path, void *data) { /* Cuando se nos notifique acerca de un cambio en el /etc/iproute2/rt_tables re-leer el archivo */ routes_tables_read_all (handle, TRUE); } static void rtables_notify_directory_close_write_cb (NetworkInadorHandle *handle, const char *path, void *data) { int path_len; path_len = strlen (path); if (path_len < 5) { /* Si ni siquiera tiene 5 letras ".conf", este archivo no nos interesa */ return; } if (strcmp (&path[path_len - 5], ".conf") != 0) return; /* Cuando se nos notifique acerca de un cambio en el resolv.conf re-leer el archivo */ routes_tables_read_all (handle, TRUE); } void rtables_init (NetworkInadorHandle *handle) { network_inador_file_watcher_add_file (handle, "/etc/iproute2/rt_tables", rtables_notify_close_write_cb, NULL); /* TODO: La vigilancia de directorios necesita vigilar eliminar archivos y archivos movidos */ network_inador_file_watcher_add_file (handle, "/etc/iproute2/rt_tables.d/", rtables_notify_directory_close_write_cb, NULL); routes_tables_read_all (handle, FALSE); } void rtables_clean_up (NetworkInadorHandle *handle) { f_list_free_full (handle->route_tables_names, free); handle->route_tables_names = NULL; handle->rtables_counter = 0; }