From 2e0bdb1ae4f311a4a9aad004db729f1fba002b87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Wed, 20 Apr 2022 00:55:55 -0500 Subject: [PATCH] =?UTF-8?q?Agrego=20eliminaci=C3=B3n=20de=20rutas=20indire?= =?UTF-8?q?ctas.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client-gtk/ni-window-route.c | 11 ++- src/common.h | 9 ++ src/interfaces.c | 3 + src/ip-address.c | 4 +- src/main.c | 2 + src/manager.c | 2 + src/netlink-events.c | 38 ++++++++ src/routes.c | 177 +++++++++++++++++++++++++++++++++-- src/routes.h | 3 + 9 files changed, 239 insertions(+), 10 deletions(-) diff --git a/client-gtk/ni-window-route.c b/client-gtk/ni-window-route.c index 65b9567..4b8a734 100644 --- a/client-gtk/ni-window-route.c +++ b/client-gtk/ni-window-route.c @@ -152,6 +152,10 @@ static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute table = ni_route_get_table (ni_route); priority = ni_route_get_priority (ni_route); + if (family != window_route->priv->family) { + return; + } + /* Preparar el dest-gw */ inet_ntop (family, dest, buffer_ip, sizeof (buffer_ip)); if (family == AF_INET && prefix == 32) { @@ -507,7 +511,7 @@ GtkWidget *ni_window_route_create_tree_for_routes (GtkTreeModel *store, GtkWidge gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (*tree), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL); h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); - v = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); + v = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (*tree)); scrolled = gtk_scrolled_window_new (h, v); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); @@ -535,6 +539,11 @@ GtkWidget *ni_window_route_create_tree_for_routes (GtkTreeModel *store, GtkWidge gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column); + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Tabla", renderer, "text", ROUTE_STORE_TABLE, NULL); + gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column); + gtk_container_add (GTK_CONTAINER (scrolled), *tree); return scrolled; diff --git a/src/common.h b/src/common.h index ddc3928..5b6d4ce 100644 --- a/src/common.h +++ b/src/common.h @@ -243,6 +243,9 @@ typedef struct _Route { /* Los brincos */ GList *nexthops; + + /* Variable usada para determinar si debemos eliminar la ruta */ + int for_delete; } Route; struct _NetworkInadorHandle { @@ -252,13 +255,19 @@ struct _NetworkInadorHandle { NetworkInadorManager *manager; + /* Estos sockets ejecutan comandos */ struct nl_sock * nl_sock_route; struct nl_sock * nl_sock_nl80211; + /* Estos sockets son de vigilancia de eventos */ NetlinkEventPair route_events; NetlinkEventPair nl80211_scan; NetlinkEventPair nl80211_scan_results; + + /* El pipe de vigilancia especial de las rutas eliminadas */ + int pipe_routes[2]; + guint source_pipe_routes; }; #endif /* __COMMON_H__ */ diff --git a/src/interfaces.c b/src/interfaces.c index 3ddf28a..ec7472b 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -31,6 +31,7 @@ #include "common.h" #include "interfaces.h" +#include "routes.h" #include "ip-address.h" #include "wireless_if.h" #include "manager.h" @@ -223,6 +224,7 @@ static int _interfaces_receive_message_interface (struct nl_msg *msg, void *arg, if (iface->flags != new_flags) { iface->flags = new_flags; + route_ask_delayed_delroute (handle); was_update = 1; } @@ -340,6 +342,7 @@ int interface_receive_message_dellink (struct nl_msg *msg, void *arg) { return NL_SKIP; } + route_ask_delayed_delroute (handle); printf ("----- Interfaz eliminada: %s\n", iface->name); handle->interfaces = g_list_remove (handle->interfaces, iface); diff --git a/src/ip-address.c b/src/ip-address.c index b11e421..620144b 100644 --- a/src/ip-address.c +++ b/src/ip-address.c @@ -35,7 +35,7 @@ #include "ip-address.h" #include "interfaces.h" #include "manager.h" - +#include "routes.h" IPAddr *_ip_address_search_addr (Interface *iface, sa_family_t family, void *addr, uint32_t prefix, void *local_addr) { GList *g; @@ -274,6 +274,8 @@ int ip_address_receive_message_deladdr (struct nl_msg *msg, void *arg) { } } + route_ask_delayed_delroute (handle); + ip_addr = _ip_address_search_addr (iface, family, &addr, addr_msg->ifa_prefixlen, (has_local ? &local_addr : NULL)); if (ip_addr == NULL) { diff --git a/src/main.c b/src/main.c index e76db6f..a33ad67 100644 --- a/src/main.c +++ b/src/main.c @@ -55,6 +55,8 @@ static void _init_handle (NetworkInadorHandle *handle) { memset (handle, 0, sizeof (NetworkInadorHandle)); handle->interfaces = NULL; + handle->pipe_routes[0] = -1; + handle->pipe_routes[1] = -1; } static void _sigterm_handler (int signum) { diff --git a/src/manager.c b/src/manager.c index df88c47..ab25980 100644 --- a/src/manager.c +++ b/src/manager.c @@ -32,6 +32,8 @@ #include #include +#include + #include #include diff --git a/src/netlink-events.c b/src/netlink-events.c index e173efd..dcafe9e 100644 --- a/src/netlink-events.c +++ b/src/netlink-events.c @@ -20,6 +20,9 @@ * Boston, MA 02110-1301 USA */ +#include +#include + #include #include @@ -70,6 +73,26 @@ static gboolean _netlink_events_handle_read (GIOChannel *source, GIOCondition co return TRUE; } +static gboolean _netlink_events_handle_route_ask (GIOChannel *source, GIOCondition condition, gpointer data) { + NetworkInadorHandle *handle = (NetworkInadorHandle *) data; + char buffer[8192]; + int ret; + + ret = read (handle->pipe_routes[0], buffer, sizeof (buffer)); + + if (ret > 0) { + /* Leimos algo en el aviso de re-procesar rutas */ + routes_ask (handle); + } else if (ret == 0) { + /* Cerrar el pipe */ + close (handle->pipe_routes[0]); + handle->pipe_routes[0] = -1; + return FALSE; + } + + return TRUE; +} + void netlink_events_create_pair (NetlinkEventPair *pair, int family) { struct nl_sock * sock_req; int fd; @@ -109,10 +132,25 @@ void netlink_events_clear_pair (NetlinkEventPair *pair) { } void netlink_events_setup (NetworkInadorHandle *handle) { + int ret; + GIOChannel *channel; netlink_events_create_pair (&handle->route_events, NETLINK_ROUTE); + int flags; nl_socket_add_memberships (handle->route_events.nl_sock, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV6_IFINFO, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0); nl_socket_modify_cb (handle->route_events.nl_sock, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle); + + /* Crear un pipe para vigilar y procesar los cambios de rutas */ + ret = pipe (handle->pipe_routes); + if (ret < 0) { + handle->pipe_routes[0] = handle->pipe_routes[1] = -1; + } else { + flags = fcntl (handle->pipe_routes[0], F_GETFL); + fcntl (handle->pipe_routes[0], F_SETFL, flags | O_NONBLOCK); + channel = g_io_channel_unix_new (handle->pipe_routes[0]); + handle->source_pipe_routes = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_route_ask, handle); + g_io_channel_unref (channel); + } } void netlink_events_clear (NetworkInadorHandle *handle) { diff --git a/src/routes.c b/src/routes.c index 43fa1dc..72b8316 100644 --- a/src/routes.c +++ b/src/routes.c @@ -25,6 +25,7 @@ #include #include +#include #include @@ -35,6 +36,45 @@ #include "routes.h" #include "manager.h" +gint _route_compare_nexthop_v4 (gconstpointer a, gconstpointer b); +gint _route_compare_nexthop_v6 (gconstpointer a, gconstpointer b); + +void route_ask_delayed_delroute (NetworkInadorHandle *handle) { + if (handle->pipe_routes[1] > 0) { + write (handle->pipe_routes[1], "", 1); + } +} + +int _route_same_list_nexthops (int family, GList *nexthops_a, GList *nexthops_b) { + int count_a, count_b; + RouteNH *nha, *nhb; + + GList *p_a, *p_b; + + count_a = g_list_length (nexthops_a); + count_b = g_list_length (nexthops_b); + + if (count_a != count_b) return 1; + + p_a = nexthops_a; + p_b = nexthops_b; + + while (p_a != NULL) { + nha = (RouteNH *) p_a->data; + nhb = (RouteNH *) p_b->data; + + if (family == AF_INET) { + if (_route_compare_nexthop_v4 (nha, nhb) != 0) return 1; + } else if (family == AF_INET6) { + if (_route_compare_nexthop_v6 (nha, nhb) != 0) return 1; + } + p_a = p_a->next; + p_b = p_b->next; + } + + return 0; +} + Route *_route_search_route (GList *list_routes, sa_family_t family, uint8_t type, uint32_t table, void *dest, uint32_t prefix, uint32_t priority) { GList *g; Route *route; @@ -62,6 +102,48 @@ Route *_route_search_route (GList *list_routes, sa_family_t family, uint8_t type return NULL; } +gint _route_compare_nexthop_v4 (gconstpointer a, gconstpointer b) { + int ret; + RouteNH *nha = (RouteNH *) a, *nhb = (RouteNH *) b; + + ret = memcmp (&nha->gw, &nhb->gw, 4); + + if (ret != 0) return ret; + + ret = nha->out_index - nhb->out_index; + if (ret != 0) return ret; + + ret = nha->nh_weight - nhb->nh_weight; + + return ret; +} + +gint _route_compare_nexthop_v6 (gconstpointer a, gconstpointer b) { + int ret; + RouteNH *nha = (RouteNH *) a, *nhb = (RouteNH *) b; + + ret = memcmp (&nha->gw, &nhb->gw, 16); + + if (ret != 0) return ret; + + ret = nha->out_index - nhb->out_index; + if (ret != 0) return ret; + + ret = nha->nh_weight - nhb->nh_weight; + + return ret; +} + +GList * _route_sort_nexthops (int family, GList *nexthops) { + if (family == AF_INET) { + return g_list_sort (nexthops, _route_compare_nexthop_v4); + } else if (family == AF_INET6) { + return g_list_sort (nexthops, _route_compare_nexthop_v6); + } + + return nexthops; +} + int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { NetworkInadorHandle *handle = (NetworkInadorHandle *) arg; struct nlmsghdr *reply; @@ -79,8 +161,9 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { uint8_t route_type; struct_addr dest; uint32_t priority = 0; - int was_new = 0; + int was_new = 0, was_update = 0; GList *route_list = NULL; + GList *old_next_hops = NULL; reply = nlmsg_hdr (msg); @@ -147,6 +230,7 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { route->prefix = prefix; route->priority = priority; + route->for_delete = 0; memcpy (&route->dest, &dest, family_size); if (family == AF_INET) { @@ -157,13 +241,26 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { was_new = 1; } else { /* Liberar los next-hops, puesto que volverán a ser creados */ - g_list_free_full (route->nexthops, free); + //g_list_free_full (route->nexthops, free); + old_next_hops = route->nexthops; route->nexthops = NULL; + route->for_delete = 0; } - route->protocol = rtm_hdr->rtm_protocol; - route->tos = rtm_hdr->rtm_tos; - route->scope = rtm_hdr->rtm_scope; + if (route->protocol != rtm_hdr->rtm_protocol) { + route->protocol = rtm_hdr->rtm_protocol; + was_update = 1; + } + + if (route->tos != rtm_hdr->rtm_tos) { + route->tos = rtm_hdr->rtm_tos; + was_update = 1; + } + + if (route->scope != rtm_hdr->rtm_scope) { + route->scope = rtm_hdr->rtm_scope; + was_update = 1; + } /* Pre-reservar el primer siguiente brinco y ligar */ next_hop = (RouteNH *) malloc (sizeof (RouteNH)); @@ -224,11 +321,20 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { } route->nexthops = g_list_append (route->nexthops, next_hop); + route->nexthops = _route_sort_nexthops (family, route->nexthops); + + if (_route_same_list_nexthops (family, route->nexthops, old_next_hops) == 1) { + /* Son diferentes */ + was_update = 1; + } + + /* Liberar la lista vieja de next_hops */ + g_list_free_full (old_next_hops, free); if (was_new) { /* Enviar aquí evento de ruta agregada */ manager_send_event_route_add (handle, route); - } else { + } else if (was_update) { /* Enviar actualización */ manager_send_event_route_update (handle, route); } @@ -325,14 +431,29 @@ int routes_receive_message_delroute (struct nl_msg *msg, void *arg) { return NL_SKIP; } -void routes_init (NetworkInadorHandle *handle) { - /* Si es la primera vez que nos llaman, descargar una primera lista de interfaces */ +void routes_ask (NetworkInadorHandle *handle) { struct nl_msg * msg; struct rtmsg rtm_hdr = { .rtm_family = AF_UNSPEC, }; int ret; + GList *g, *n; + Route *r; + /* Recorrer todas las rutas en la tabla de ruteo y marcarlas para eliminación */ + for (g = handle->route_v4_tables; g != NULL; g = g->next) { + r = (Route *) g->data; + + r->for_delete = 1; + } + + for (g = handle->route_v6_tables; g != NULL; g = g->next) { + r = (Route *) g->data; + + r->for_delete = 1; + } + + /* Ahora sí, mandar la petición */ msg = nlmsg_alloc_simple (RTM_GETROUTE, NLM_F_REQUEST | NLM_F_DUMP); if (msg == NULL) { return; @@ -353,6 +474,46 @@ void routes_init (NetworkInadorHandle *handle) { nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, routes_receive_message_newroute, handle); nl_recvmsgs_default (handle->nl_sock_route); + + /* Ejecutar las eliminaciones */ + for (g = handle->route_v4_tables; g != NULL; g = n) { + n = g->next; + + r = (Route *) g->data; + if (r->for_delete == 0) continue; + + handle->route_v4_tables = g_list_remove (handle->route_v4_tables, r); + + /* Notificar del evento */ + manager_send_event_route_del (handle, r); + + /* Eliminar todos los next-hops primero */ + g_list_free_full (r->nexthops, free); + + free (r); + } + + for (g = handle->route_v6_tables; g != NULL; g = n) { + n = g->next; + + r = (Route *) g->data; + if (r->for_delete == 0) continue; + + handle->route_v6_tables = g_list_remove (handle->route_v6_tables, r); + + /* Notificar del evento */ + manager_send_event_route_del (handle, r); + + /* Eliminar todos los next-hops primero */ + g_list_free_full (r->nexthops, free); + + free (r); + } +} + +void routes_init (NetworkInadorHandle *handle) { + /* Si es la primera vez que nos llaman, descargar una primera lista de interfaces */ + routes_ask (handle); } void routes_clean_up (NetworkInadorHandle *handle) { diff --git a/src/routes.h b/src/routes.h index 72ba0cd..ce8db15 100644 --- a/src/routes.h +++ b/src/routes.h @@ -29,9 +29,12 @@ #include "common.h" void routes_init (NetworkInadorHandle *handle); +void routes_ask (NetworkInadorHandle *handle); int routes_receive_message_newroute (struct nl_msg *msg, void *arg); int routes_receive_message_delroute (struct nl_msg *msg, void *arg); +void route_ask_delayed_delroute (NetworkInadorHandle *handle); + void routes_clean_up (NetworkInadorHandle *handle); #endif /* __ROUTES_H__ */