From fbef149d4fa1c33bd5050806465f02fe0baedde4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Sat, 24 Dec 2022 18:39:46 -0600 Subject: [PATCH] =?UTF-8?q?Agrego=20eliminaci=C3=B3n=20de=20rutas.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client-gtk/ni-client.c | 55 +++++++-- client-gtk/ni-client.h | 2 + client-gtk/ni-route.c | 8 +- client-gtk/ni-route.h | 1 + client-gtk/ni-window-route.c | 43 ++++++- src/common.h | 10 +- src/manager.c | 103 ++++++++++++++++- src/network-inador-manager.h | 7 ++ src/routes.c | 216 ++++++++++++++++++++++++++++++++--- src/routes.h | 1 + 10 files changed, 416 insertions(+), 30 deletions(-) diff --git a/client-gtk/ni-client.c b/client-gtk/ni-client.c index 16c16f9..f5e8efd 100644 --- a/client-gtk/ni-client.c +++ b/client-gtk/ni-client.c @@ -222,7 +222,7 @@ static void ni_client_process_interface_response (NIClient *ni_client, gpointer g_signal_emit (ni_client, signals[NEW_INTERFACE], 0, ni_interface); } -static NIRoute *_ni_client_search_route (GList *list_routes, sa_family_t family, uint8_t type, uint32_t table, void *dest, uint32_t prefix, uint32_t priority) { +static NIRoute *_ni_client_search_route (GList *list_routes, sa_family_t family, uint8_t tos, uint32_t table, void *dest, uint32_t prefix, uint32_t priority) { GList *g; NIRoute *ni_route; int family_size = 0; @@ -236,10 +236,10 @@ static NIRoute *_ni_client_search_route (GList *list_routes, sa_family_t family, for (g = list_routes; g != NULL; g = g->next) { ni_route = (NIRoute *) g->data; - if (ni_route_get_family(ni_route) != family) continue; - if (ni_route_get_route_type(ni_route) != type) continue; - if (ni_route_get_table(ni_route) != table) continue; - if (ni_route_get_priority(ni_route) != priority) continue; + if (ni_route_get_family (ni_route) != family) continue; + if (ni_route_get_route_tos (ni_route) != tos) continue; + if (ni_route_get_table (ni_route) != table) continue; + if (ni_route_get_priority( ni_route) != priority) continue; if (memcmp (ni_route_get_dest (ni_route), dest, family_size) == 0 && ni_route_get_prefix(ni_route) == prefix) { return ni_route; @@ -335,7 +335,7 @@ static void ni_client_process_route_response (NIClient *ni_client, gpointer data static void ni_client_process_route_del_response (NIClient *ni_client, gpointer data, guint size) { unsigned char *buffer = (unsigned char *) data; uint8_t family, family_size; - uint8_t type, prefix; + uint8_t tos, prefix; uint32_t tabla, prioridad; NIRoute *ni_route; struct_addr dest; @@ -351,7 +351,7 @@ static void ni_client_process_route_del_response (NIClient *ni_client, gpointer list_routes = ni_client->priv->routes_v6; } - type = buffer[3]; + tos = buffer[3]; memcpy (&tabla, &buffer[4], 4); prefix = buffer[8]; @@ -359,7 +359,7 @@ static void ni_client_process_route_del_response (NIClient *ni_client, gpointer memcpy (&dest, &buffer[13], family_size); - ni_route = _ni_client_search_route (list_routes, family, type, tabla, &dest, prefix, prioridad); + ni_route = _ni_client_search_route (list_routes, family, tos, tabla, &dest, prefix, prioridad); if (ni_route == NULL) { /* ¿No hay ruta? Raro */ @@ -991,6 +991,45 @@ void ni_client_ask_route_new (NIClient *ni_client, int family, int prefix, struc send (ni_client->priv->client_socket, buffer, pos, 0); } +void ni_client_ask_route_del (NIClient *ni_client, NIRoute *route) { + unsigned char buffer[80]; + int family_size, family; + int pos, c; + const struct_addr *dest; + uint32_t tabla, priority; + + if (ni_client->priv->client_socket < 0) { + return; + } + + family = ni_route_get_family (route); + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_REMOVE_ROUTE; + buffer[2] = family; + buffer[3] = ni_route_get_route_tos (route); + + tabla = ni_route_get_table (route); + memcpy (&buffer[4], &tabla, 4); + + buffer[8] = ni_route_get_prefix (route); + priority = ni_route_get_priority (route); + memcpy (&buffer[9], &priority, 4); + + dest = ni_route_get_dest (route); + memcpy (&buffer[13], dest, family_size); + + pos = 13 + family_size; + + send (ni_client->priv->client_socket, buffer, pos, 0); +} + static void ni_client_foreach_has_table (gpointer key, gpointer value, gpointer data) { GList **lista = (GList **) data; diff --git a/client-gtk/ni-client.h b/client-gtk/ni-client.h index a492221..cee121e 100644 --- a/client-gtk/ni-client.h +++ b/client-gtk/ni-client.h @@ -71,6 +71,7 @@ struct _NIClient { }; typedef struct _NIInterface NIInterface; +typedef struct _NIRoute NIRoute; /* * Method definitions. @@ -96,6 +97,7 @@ GList *ni_client_get_routes_v4 (NIClient *ni_client); GList *ni_client_get_routes_v6 (NIClient *ni_client); void ni_client_ask_route_new (NIClient *ni_client, int family, int prefix, struct_addr *dest, int type, uint32_t tabla, int protocol, int tos, int scope, int has_prefsrc, struct_addr *prefsrc, uint32_t priority, GList *gws); +void ni_client_ask_route_del (NIClient *ni_client, NIRoute *route); void ni_client_ask_interface_clear_master (NIClient *ni_client, NIInterface *ni_interface); void ni_client_ask_interface_set_master (NIClient *ni_client, NIInterface *ni_interface, NIInterface *master); diff --git a/client-gtk/ni-route.c b/client-gtk/ni-route.c index b485e5d..fa006ef 100644 --- a/client-gtk/ni-route.c +++ b/client-gtk/ni-route.c @@ -241,7 +241,7 @@ static gboolean ni_route_process_route_response (NIClient *ni_client, unsigned c /* Tengo suficientes datos, revisar si es mi ruta */ if (ni_route->priv->family != family) return FALSE; - if (ni_route->priv->type != type) return FALSE; + if (ni_route->priv->tos != tos) return FALSE; if (ni_route->priv->table != tabla) return FALSE; if (ni_route->priv->priority != prioridad) return FALSE; @@ -351,6 +351,12 @@ guint ni_route_get_route_type (NIRoute *ni_route) { return ni_route->priv->type; } +guint ni_route_get_route_tos (NIRoute *ni_route) { + g_return_val_if_fail (NI_IS_ROUTE (ni_route), 0); + + return ni_route->priv->tos; +} + guint ni_route_get_family (NIRoute *ni_route) { g_return_val_if_fail (NI_IS_ROUTE (ni_route), 0); diff --git a/client-gtk/ni-route.h b/client-gtk/ni-route.h index b4bc893..38e10bc 100644 --- a/client-gtk/ni-route.h +++ b/client-gtk/ni-route.h @@ -80,6 +80,7 @@ NIRoute *ni_route_new (NIClient *ni_client, int family, int type, uint32_t table NIClient *ni_route_get_client (NIRoute *ni_route); guint ni_route_get_family (NIRoute *ni_route); guint ni_route_get_route_type (NIRoute *ni_route); +guint ni_route_get_route_tos (NIRoute *ni_route); const struct_addr *ni_route_get_dest (NIRoute *ni_route); guint ni_route_get_prefix (NIRoute *ni_route); uint32_t ni_route_get_table (NIRoute *ni_route); diff --git a/client-gtk/ni-window-route.c b/client-gtk/ni-window-route.c index 37fa84e..3aa258f 100644 --- a/client-gtk/ni-window-route.c +++ b/client-gtk/ni-window-route.c @@ -150,6 +150,8 @@ static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute struct _NIWindowRouteSearchTable for_search; int route_type; char *route_type_desc; + int tos; + char *route_tos_desc; family = ni_route_get_family (ni_route); dest = ni_route_get_dest (ni_route); @@ -157,6 +159,7 @@ static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute prefix = ni_route_get_prefix (ni_route); table = ni_route_get_table (ni_route); priority = ni_route_get_priority (ni_route); + tos = ni_route_get_route_tos (ni_route); if (family != window_route->priv->family) { return; @@ -193,12 +196,20 @@ static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute } else { snprintf (buffer, sizeof (buffer), "%s/%i", buffer_ip, prefix); } + if (route_type_desc != NULL) { snprintf (buffer2, sizeof (buffer2), "%s %s", buffer, route_type_desc); } else { strncpy (buffer2, buffer, sizeof (buffer2)); } + route_tos_desc = NULL; + if (tos != 0) { + snprintf (buffer, sizeof (buffer), "%s [TOS 0x%02x]", buffer2, tos); + } else { + strncpy (buffer, buffer2, sizeof (buffer)); + } + /* Preparar el pref-src, si lo tiene */ buffer_ip[0] = 0; if (ni_route_has_prefsrc (ni_route)) { @@ -218,7 +229,7 @@ static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute gtk_list_store_insert_with_values (window_route->priv->tables_store, NULL, -1, TABLE_STORE_TABLE, table, TABLE_STORE_NAME, NULL, TABLE_STORE_IS_NEW, FALSE, -1); } - gtk_list_store_insert_with_values (window_route->priv->routes_store, NULL, -1, ROUTE_STORE_TABLE, table, ROUTE_STORE_COL_DST_GW, buffer2, ROUTE_STORE_COL_METRIC, priority, ROUTE_STORE_COL_PREFSRC, buffer_ip, ROUTE_STORE_COL_OBJECT, ni_route, -1); + gtk_list_store_insert_with_values (window_route->priv->routes_store, NULL, -1, ROUTE_STORE_TABLE, table, ROUTE_STORE_COL_DST_GW, buffer, ROUTE_STORE_COL_METRIC, priority, ROUTE_STORE_COL_PREFSRC, buffer_ip, ROUTE_STORE_COL_OBJECT, ni_route, -1); g_signal_connect (ni_route, "updated", G_CALLBACK (ni_window_route_updated_route_cb), window_route); } @@ -459,6 +470,32 @@ static void ni_window_interface_delete_route_cb (NIClient *ni_client, NIRoute *n } } +static void has_route_selected_cb (GtkTreeSelection *selection, gpointer data) { + NIWindowRoute *window_route = NI_WINDOW_ROUTE (data); + + if (gtk_tree_selection_count_selected_rows (selection) > 0) { + gtk_widget_set_sensitive (window_route->priv->del_route_button, TRUE); + } else { + gtk_widget_set_sensitive (window_route->priv->del_route_button, FALSE); + } +} + +static void ni_window_route_del_route_button_add_cb (GtkWidget *button, gpointer data) { + NIWindowRoute *window_route = NI_WINDOW_ROUTE (data); + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + NIRoute *ni_route; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window_route->priv->tree_routes)); + + gtk_tree_selection_get_selected (selection, &model, &iter); + + gtk_tree_model_get (model, &iter, ROUTE_STORE_COL_OBJECT, &ni_route, -1); + + ni_client_ask_route_del (window_route->priv->ni_client, ni_route); +} + static void ni_window_route_add_route_button_add_cb (GtkWidget *button, gpointer data) { NIWindowRoute *window_route = NI_WINDOW_ROUTE (data); GtkWidget *dialog; @@ -720,12 +757,12 @@ static void ni_window_route_init (NIWindowRoute *window_route) { priv->del_route_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox2), priv->del_route_button, FALSE, FALSE, 0); - //g_signal_connect (priv->del_route_button, "clicked", G_CALLBACK (ni_window_interface_addr_v6_button_del_cb), window_iface); + g_signal_connect (priv->del_route_button, "clicked", G_CALLBACK (ni_window_route_del_route_button_add_cb), window_route); gtk_widget_set_sensitive (priv->del_route_button, FALSE); /* Conectar la señal de cambio de selección del tree view */ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_routes)); - //g_signal_connect (selection, "changed", G_CALLBACK (has_ip_selected_v6_cb), window_iface); + g_signal_connect (selection, "changed", G_CALLBACK (has_route_selected_cb), window_route); /* La botonera inferior */ hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); diff --git a/src/common.h b/src/common.h index 5b6d4ce..6da7de6 100644 --- a/src/common.h +++ b/src/common.h @@ -233,9 +233,9 @@ typedef struct _Route { uint32_t table; struct_addr dest; uint8_t prefix; + uint8_t tos; uint8_t protocol; - uint8_t tos; uint8_t scope; struct_addr prefsrc; @@ -248,10 +248,18 @@ typedef struct _Route { int for_delete; } Route; +typedef struct _RouteTable { + uint32_t table; + char name[256]; + + int for_delete, was_new; +} RouteTable; + struct _NetworkInadorHandle { GList *interfaces; GList *route_v4_tables; GList *route_v6_tables; + GList *route_tables_names; NetworkInadorManager *manager; diff --git a/src/manager.c b/src/manager.c index 2e93cf8..ec91887 100644 --- a/src/manager.c +++ b/src/manager.c @@ -1106,7 +1106,7 @@ void _manager_send_route_del (ManagerClientInfo *manager_client, Route *route) { family_size = sizeof (struct in6_addr); } buffer[2] = route->family; - buffer[3] = route->type; + buffer[3] = route->tos; memcpy (&buffer[4], &route->table, 4); buffer[8] = route->prefix; memcpy (&buffer[9], &route->priority, 4); @@ -1275,6 +1275,102 @@ void _manager_execute_add_route (ManagerClientInfo *manager_client, unsigned cha } } +void _manager_execute_del_route (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { + Route route; + int ret; + int family_size, wanted_size, family; + int g, rem, pos; + + if (buffer_len < 13) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_REMOVE_ROUTE); + return; + } + + family = buffer[2]; + + if (family != AF_INET && family != AF_INET6) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_REMOVE_ROUTE); + + return; + } + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + /* Ya puedo revisar el resto de la longitud */ + wanted_size = 13 + family_size; + if (buffer_len < wanted_size) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_REMOVE_ROUTE); + return; + } + + memset (&route, 0, sizeof (route)); + + /* Ejecutar el parsing */ + route.family = family; + route.tos = buffer[3]; + memcpy (&route.table, &buffer[4], 4); + route.prefix = buffer[8]; + memcpy (&route.priority, &buffer[9], 4); + + memcpy (&route.dest, &buffer[13], family_size); + ret = routes_del (manager_client->manager->handle, &route); + + if (ret == 0) { + /* OK */ + _manager_send_executed (manager_client); + } else { + _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_REMOVE_ROUTE); + } +} + +void _manager_send_route_table (ManagerClientInfo *manager_client, RouteTable *rtable, gboolean is_event) { + unsigned char buffer[80]; + int name_len; + + if (is_event) { + buffer[0] = NET_INADOR_TYPE_EVENT; + buffer[1] = NET_INADOR_EVENT_ROUTE_TABLE_ADDED; + } else { + buffer[0] = NET_INADOR_TYPE_RESPONSE; + buffer[1] = NET_INADOR_RESPONSE_ROUTE_TABLE; + } + + memcpy (&buffer[2], &rtable->table, 4); + + name_len = strlen (rtable->name); + buffer[6] = name_len; + memcpy (&buffer[7], rtable->name, name_len); + + send (manager_client->fd, buffer, 7 + name_len, 0); +} + +void _manager_send_list_route_tables (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { + GList *g; + RouteTable *rtable; + uint32_t table; + + if (buffer_len < 6) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_LIST_ROUTE_TABLES); + return; + } + + memcpy (&table, &buffer[2], 4); + + for (g = manager_client->manager->handle->route_v4_tables; g != NULL; g = g->next) { + rtable = (RouteTable *) g->data; + + if (table != 0 && rtable->table != table) continue; + + _manager_send_route_table (manager_client, rtable, FALSE); + } + + _manager_send_end_command (manager_client, NET_INADOR_COMMAND_LIST_ROUTE_TABLES); +} + static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) { ManagerClientInfo *manager_client = (ManagerClientInfo *) data; NetworkInadorManager *manager = manager_client->manager; @@ -1380,7 +1476,10 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition _manager_execute_add_route (manager_client, buffer, bytes); break; case NET_INADOR_COMMAND_REMOVE_ROUTE: - + _manager_execute_del_route (manager_client, buffer, bytes); + break; + case NET_INADOR_COMMAND_LIST_ROUTE_TABLES: + _manager_send_list_route_tables (manager_client, buffer, bytes); break; default: _manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command); diff --git a/src/network-inador-manager.h b/src/network-inador-manager.h index 844742a..d59ce0b 100644 --- a/src/network-inador-manager.h +++ b/src/network-inador-manager.h @@ -44,6 +44,8 @@ enum { NET_INADOR_COMMAND_ADD_ROUTE, NET_INADOR_COMMAND_REMOVE_ROUTE, + NET_INADOR_COMMAND_LIST_ROUTE_TABLES = 72, + NET_INADOR_COMMAND_SET_EVENT_MASK = 192, /* Los siguientes comandos son para uso interno */ @@ -72,6 +74,9 @@ enum { NET_INADOR_EVENT_ROUTE_ADDED = 10, NET_INADOR_EVENT_ROUTE_REMOVED, + + NET_INADOR_EVENT_ROUTE_TABLE_ADDED = 14, + NET_INADOR_EVENT_ROUTE_TABLE_REMOVED, }; enum { @@ -83,6 +88,8 @@ enum { NET_INADOR_RESPONSE_DHCP_STATUS = 6, NET_INADOR_RESPONSE_ROUTE = 10, + + NET_INADOR_RESPONSE_ROUTE_TABLE = 14 }; enum { diff --git a/src/routes.c b/src/routes.c index fde6f42..67068d3 100644 --- a/src/routes.c +++ b/src/routes.c @@ -26,6 +26,8 @@ #include #include +#include +#include #include @@ -75,7 +77,7 @@ int _route_same_list_nexthops (int family, GList *nexthops_a, GList *nexthops_b) 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) { +Route *_route_search_route (GList *list_routes, sa_family_t family, uint8_t tos, uint32_t table, void *dest, uint32_t prefix, uint32_t priority) { GList *g; Route *route; int family_size = 0; @@ -90,8 +92,11 @@ Route *_route_search_route (GList *list_routes, sa_family_t family, uint8_t type route = (Route *) g->data; if (route->family != family) continue; - if (route->type != type) continue; + + /* Por tos si genera diferencia */ + if (route->tos != tos) continue; if (route->table != table) continue; + /* Por métrica */ if (route->priority != priority) continue; if (memcmp (&route->dest, dest, family_size) == 0 && route->prefix == prefix) { @@ -158,7 +163,7 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { int rtnhp_len; int multipath_len; unsigned char *p; - uint8_t route_type; + uint8_t route_type, tos; struct_addr dest; uint32_t priority = 0; int was_new = 0, was_update = 0; @@ -183,7 +188,9 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { route_list = handle->route_v6_tables; } - /* Recuperar el tipo de ruta */ + /* Recuperar el tos, porque marca diferencia entre rutas */ + tos = rtm_hdr->rtm_tos; + route_type = rtm_hdr->rtm_type; /* Recuperar el prefijo */ @@ -217,7 +224,7 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { } } /* TODO: Revisar si la ruta que procesamos ya existe */ - route = _route_search_route (route_list, family, route_type, table, &dest, prefix, priority); + route = _route_search_route (route_list, family, tos, table, &dest, prefix, priority); if (route == NULL) { /* Nueva ruta */ @@ -228,6 +235,7 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { route->type = route_type; route->table = table; route->prefix = prefix; + route->tos = tos; route->priority = priority; route->for_delete = 0; @@ -252,11 +260,6 @@ int routes_receive_message_newroute (struct nl_msg *msg, void *arg) { 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; @@ -350,7 +353,7 @@ int routes_receive_message_delroute (struct nl_msg *msg, void *arg) { int family, family_size = 0; struct rtmsg *rtm_hdr; struct nlattr *attr; - uint8_t route_type; + uint8_t route_tos; struct_addr dest; uint32_t priority = 0; GList *route_list = NULL; @@ -372,8 +375,8 @@ int routes_receive_message_delroute (struct nl_msg *msg, void *arg) { route_list = handle->route_v6_tables; } - /* Recuperar el tipo de ruta */ - route_type = rtm_hdr->rtm_type; + /* Recuperar el tos de la ruta*/ + route_tos = rtm_hdr->rtm_tos; /* Recuperar el prefijo */ prefix = rtm_hdr->rtm_dst_len; @@ -406,7 +409,7 @@ int routes_receive_message_delroute (struct nl_msg *msg, void *arg) { } } - route = _route_search_route (route_list, family, route_type, table, &dest, prefix, priority); + route = _route_search_route (route_list, family, route_tos, table, &dest, prefix, priority); if (route == NULL) { /* ¿Notificación de eliminar una ruta que no existe? Super raro */ @@ -591,7 +594,61 @@ int routes_del (NetworkInadorHandle *handle, Route *route) { RouteNH *nh; GList *g; - /* TODO: Pendiente escribir esto */ + memset (&route_hdr, 0, sizeof (route_hdr)); + + route_hdr.rtm_family = route->family; + route_hdr.rtm_dst_len = route->prefix; + route_hdr.rtm_tos = route->tos; + route_hdr.rtm_table = route->table; + + msg = nlmsg_alloc_simple (RTM_DELROUTE, NLM_F_REQUEST); + ret = nlmsg_append (msg, &route_hdr, sizeof (route_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + nlmsg_free (msg); + + return -1; + } + + if (route->family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (route->family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + ret = nla_put (msg, RTA_DST, family_size, &route->dest); + if (route->priority != 0) { + ret |= nla_put (msg, RTA_PRIORITY, 4, &route->priority); + } + + if (ret != 0) { + nlmsg_free (msg); + + return -1; + } + + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + if (ret <= 0) { + return -1; + } + + error = 0; + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _route_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_INVALID, NL_CB_CUSTOM, _route_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_ACK, NL_CB_CUSTOM, _route_wait_ack_or_error, &error); + nl_socket_modify_err_cb (handle->nl_sock_route, NL_CB_CUSTOM, _route_wait_error, &error); + + ret = nl_recvmsgs_default (handle->nl_sock_route); + + if (ret < 0 || error < 0) { + return -1; + } + + return 0; } void routes_ask (NetworkInadorHandle *handle) { @@ -674,9 +731,138 @@ void routes_ask (NetworkInadorHandle *handle) { } } +gint _routes_table_find_by_number (gconstpointer left, gconstpointer right) { + RouteTable *a, *b; + + a = (RouteTable *) left; + b = (RouteTable *) right; + + return a->table != b->table; +} + +void _routes_table_parse_file (NetworkInadorHandle *handle, FILE *fd) { + GList *g; + RouteTable *rtable, temp_table; + char buffer[2048]; + + while (fgets (buffer, sizeof (buffer), fd), feof (fd) != 0) { + sscanf (buffer, "%d %s", &(temp_table.table), temp_table.name); + + g = g_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; + + rtable->for_delete = 0; + rtable->was_new = 0; + } else { + /* No existe, crear nueva */ + rtable = (RouteTable *) g_malloc (sizeof (RouteTable)); + rtable->table = temp_table.table; + rtable->for_delete = 0; + rtable->was_new = 1; + } + /* En cualquier caso actualizar el nombre */ + strncpy (rtable->name, temp_table.name, sizeof (rtable->name)); + } +} + +void routes_tables_read (NetworkInadorHandle *handle, int do_notify) { + FILE *fd; + GList *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; + } + + //g_list_free_full (handle->route_tables_names, g_free); + //handle->route_tables_names = NULL; + + /* Intentar abrir /etc/iproute2/rt_tables */ + fd = fopen ("/etc/iproute2/rt_tables", "r"); + if (fd != NULL) { + _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); + 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 = g_list_delete_link (handle->route_tables_names, g); + + if (do_notify) { + /* TODO: Notificar al manager que esta tabla fué eliminada */ + } + + g_free (rtable); + } + + g = h; + } + + g = handle->route_tables_names; + while (g != NULL) { + rtable = (RouteTable *) g->data; + + if (rtable->was_new) { + if (do_notify) { + /* TODO: Notificar al manager que esta tabla fué agregada */ + } + rtable->was_new = 0; + } + + g = g->next; + } +} + void routes_init (NetworkInadorHandle *handle) { /* Si es la primera vez que nos llaman, descargar una primera lista de interfaces */ routes_ask (handle); + + /* Inicializar los nombres de las tablas de ruteo */ + routes_tables_read (handle, FALSE); } void routes_clean_up (NetworkInadorHandle *handle) { diff --git a/src/routes.h b/src/routes.h index b90aaea..e5263fe 100644 --- a/src/routes.h +++ b/src/routes.h @@ -33,6 +33,7 @@ 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); int routes_add (NetworkInadorHandle *handle, Route *route); +int routes_del (NetworkInadorHandle *handle, Route *route); void route_ask_delayed_delroute (NetworkInadorHandle *handle);