From 56e9f4b67d7f9567ec33c5d4997853119587c35f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Fri, 17 Aug 2018 01:16:01 -0500 Subject: [PATCH] Agrego manejo de rutas. --- src/Makefile.am | 3 +- src/events.c | 11 +- src/interfaces.c | 128 ++++++++-- src/manager.c | 45 ++++ src/network-inador.c | 4 + src/network-inador.h | 17 ++ src/routes.c | 579 +++++++++++++++++++++++++++++++++++++++++++ src/routes.h | 35 +++ src/rta_aux.h | 3 + 9 files changed, 799 insertions(+), 26 deletions(-) create mode 100644 src/routes.c create mode 100644 src/routes.h diff --git a/src/Makefile.am b/src/Makefile.am index c1cf8f4..bdee3fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,8 @@ network_inador_SOURCES = network-inador.c network-inador.h \ manager.c manager.h \ utils.c utils.h \ bridge.c bridge.h \ - rta_aux.c rta_aux.h + rta_aux.c rta_aux.h \ + routes.c routes.h #network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) diff --git a/src/events.c b/src/events.c index 0f258a4..4956c8b 100644 --- a/src/events.c +++ b/src/events.c @@ -43,11 +43,12 @@ #include #include +#include + #include "events.h" #include "network-inador.h" #include "interfaces.h" - -#include +#include "routes.h" static gboolean _events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) { NetworkInadorHandle *handle = (NetworkInadorHandle *) data; @@ -102,6 +103,12 @@ static gboolean _events_handle_read (GIOChannel *source, GIOCondition condition, } else if (msg_ptr->nlmsg_type == RTM_DELADDR) { printf ("Mensaje dinámico de eliminar IP\n"); interfaces_del_ipv4 (handle, msg_ptr); + } else if (msg_ptr->nlmsg_type == RTM_NEWROUTE) { + printf ("Mensaje dinámico de nueva ruta\n"); + routes_add_or_update_rtm (handle, msg_ptr); + } else if (msg_ptr->nlmsg_type == RTM_DELROUTE) { + printf ("Mensaje dinámico de eliminar ruta\n"); + routes_del_rtm (handle, msg_ptr); } } diff --git a/src/interfaces.c b/src/interfaces.c index 596d444..cdc8c42 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -115,9 +115,9 @@ static IPv4 * _interfaces_serach_ipv4 (Interface *interface, struct in_addr addr static void _interfaces_list_ipv4_address (NetworkInadorHandle *handle, int sock) { struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ struct iovec io; - nl_req_t req; + struct ifaddrmsg *ifa; struct sockaddr_nl kernel; - char reply[8192]; /* a large buffer */ + char buffer[8192]; /* a large buffer */ int len; /* Para la respuesta */ @@ -130,22 +130,25 @@ static void _interfaces_list_ipv4_address (NetworkInadorHandle *handle, int sock local_size = sizeof (local_nl); getsockname (sock, (struct sockaddr *) &local_nl, &local_size); - memset(&rtnl_msg, 0, sizeof(rtnl_msg)); - memset(&kernel, 0, sizeof(kernel)); - memset(&req, 0, sizeof(req)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ kernel.nl_groups = 0; - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.hdr.nlmsg_type = RTM_GETADDR; - req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.hdr.nlmsg_seq = global_nl_seq++; - req.hdr.nlmsg_pid = local_nl.nl_pid; - req.gen.rtgen_family = AF_INET; + msg_ptr = (struct nlmsghdr *) buffer; + msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); + msg_ptr->nlmsg_type = RTM_GETADDR; + msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + msg_ptr->nlmsg_seq = global_nl_seq++; + msg_ptr->nlmsg_pid = local_nl.nl_pid; + + ifa = (struct ifaddrmsg *) NLMSG_DATA (msg_ptr); + ifa->ifa_family = AF_INET; - io.iov_base = &req; - io.iov_len = req.hdr.nlmsg_len; + io.iov_base = buffer; + io.iov_len = msg_ptr->nlmsg_len; rtnl_msg.msg_iov = &io; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &kernel; @@ -154,21 +157,22 @@ static void _interfaces_list_ipv4_address (NetworkInadorHandle *handle, int sock sendmsg (sock, (struct msghdr *) &rtnl_msg, 0); /* Esperar la respuesta */ - memset(&io, 0, sizeof(io)); - memset(&rtnl_msg, 0, sizeof(rtnl_msg)); + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); - io.iov_base = reply; - io.iov_len = sizeof (reply); + io.iov_base = buffer; + io.iov_len = sizeof (buffer); rtnl_msg.msg_iov = &io; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &kernel; - rtnl_msg.msg_namelen = sizeof(kernel); + rtnl_msg.msg_namelen = sizeof (kernel); - while ((len = recvmsg(sock, &rtnl_msg, 0)) > 0) { /* read lots of data */ - msg_ptr = (struct nlmsghdr *) reply; + while ((len = recvmsg (sock, &rtnl_msg, 0)) > 0) { /* read lots of data */ + msg_ptr = (struct nlmsghdr *) buffer; if (msg_ptr->nlmsg_type == NLMSG_DONE) break; - for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { + for (; NLMSG_OK (msg_ptr, len); msg_ptr = NLMSG_NEXT (msg_ptr, len)) { /* Procesar solo los mensajes de nueva interfaz */ printf ("Msg type: %i\n", msg_ptr->nlmsg_type); if (msg_ptr->nlmsg_type == RTM_NEWADDR) { @@ -264,8 +268,86 @@ void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlm printf ("Interface %d has mtu: %u\n", iface->ifi_index, new->mtu); break; - //default: - //printf ("RTA Attribute \"%hu\" no procesado\n", attribute->rta_type); + case IFLA_OPERSTATE: + { + unsigned int operstate; + memcpy (&operstate, RTA_DATA (attribute), sizeof (operstate)); + } + break; + case IFLA_AF_SPEC: + { + struct rtattr * sub_attr; + int sub_len; + int nla_len; + + sub_len = attribute->rta_len; + + sub_attr = RTA_DATA (attribute); + + while (sub_len > sizeof (sub_attr)) { + nla_len = sub_attr->rta_len; + + if (nla_len > sub_len) { + printf ("Los sub atributos se acabaron prematuramente\n"); + break; + } + printf ("Interface %d, IFLA_AF_SPEC, sub attributo type: %i\n", iface->ifi_index, sub_attr->rta_type); + + sub_len -= RTA_ALIGN (nla_len); + sub_attr = (struct rtattr *) (((char *) sub_attr) + RTA_ALIGN (nla_len)); + } + } + break; + case IFLA_LINKINFO: + { + struct rtattr * nest_attr; + int nest_size; + int sub_len; + + nest_size = attribute->rta_len; + nest_attr = RTA_DATA (attribute); + + while (nest_size > sizeof (nest_attr)) { + sub_len = nest_attr->rta_len; + + if (sub_len > nest_size) { + printf ("Los sub atributos se acabaron prematuramente\n"); + break; + } + printf ("Interface %d, IFLA_LINKINFO, sub attributo type: %i\n", iface->ifi_index, nest_attr->rta_type); + + if (nest_attr->rta_type == IFLA_INFO_KIND) { + printf ("IFLA_INFO_KIND: %s\n", RTA_DATA (nest_attr)); + } else if (nest_attr->rta_type == IFLA_INFO_DATA) { + printf ("Segunda anidación: IFLA_INFO_DATA: size: %d\n", nest_attr->rta_len); + struct rtattr *nest2_attr; + int nest2_size; + int sub2_len; + + nest2_size = nest_attr->rta_len; + nest2_attr = RTA_DATA (nest_attr); + + while (nest2_size > sizeof (nest2_attr)) { + sub2_len = nest2_attr->rta_len; + printf ("------ Nest2_attr->rta_len = %d. El tamaño es: %d\n", sub2_len, nest2_size); + if (sub2_len > nest2_size) { + printf ("Los sub atributos se acabaron prematuramente\n"); + break; + } + printf ("Interface %d, IFLA_INFO_DATA, sub attributo type: %i, size: %d\n", iface->ifi_index, nest2_attr->rta_type, nest2_attr->rta_len); + + //if ( + + nest2_size -= RTA_ALIGN (sub2_len); + nest2_attr = (struct rtattr *) (((char *) nest2_attr) + RTA_ALIGN (sub2_len)); + } + + } + nest_size -= RTA_ALIGN (sub_len); + nest_attr = (struct rtattr *) (((char *) nest_attr) + RTA_ALIGN (sub_len)); + } + } + break; } } } diff --git a/src/manager.c b/src/manager.c index 82ad49a..6167108 100644 --- a/src/manager.c +++ b/src/manager.c @@ -46,11 +46,14 @@ enum { MANAGER_COMMAND_SET_IPV4, + MANAGER_COMMAND_LIST_ROUTES, + MANAGER_RESPONSE = 128, MANAGER_RESPONSE_REQUEST_INVALID = 128, MANAGER_RESPONSE_PROCESING, MANAGER_RESPONSE_LIST_IFACES, + MANAGER_RESPONSE_LIST_ROUTES, }; #define MANAGER_IFACE_TYPE_WIRELESS 2 @@ -166,6 +169,43 @@ static void _manager_handle_interface_set_ipv4 (NetworkInadorHandle *handle, cha _manager_send_processing (sock, client, socklen, seq); } +static void _manager_send_list_routes (NetworkInadorHandle *handle, int sock, struct sockaddr_un *client, socklen_t socklen, int seq) { + unsigned char buffer[8192]; + Routev4 *route_g; + int pos; + int flags; + unsigned int count; + + buffer[0] = MANAGER_RESPONSE_LIST_ROUTES; + buffer[1] = seq; + + route_g = handle->rtable_v4; + + count = 0; + pos = 6; + while (route_g != NULL) { + memcpy (&buffer[pos], &route_g->dest, sizeof (route_g->dest)); + pos = pos + sizeof (route_g->dest); + + buffer[pos] = route_g->prefix; + buffer[pos + 1] = route_g->index; + buffer[pos + 2] = route_g->table; + buffer[pos + 3] = route_g->type; + pos = pos + 4; + + memcpy (&buffer[pos], &route_g->gateway, sizeof (route_g->gateway)); + + pos = pos + 4; + + route_g = route_g->next; + count++; + } + + memcpy (&buffer[2], &count, sizeof (int)); + + sendto (sock, buffer, pos, 0, (struct sockaddr *) client, socklen); +} + static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) { NetworkInadorHandle *handle = (NetworkInadorHandle *) data; int sock; @@ -196,6 +236,11 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition case MANAGER_COMMAND_SET_IPV4: _manager_handle_interface_set_ipv4 (handle, &buffer[2], len - 2, sock, &client_name, socklen, seq); break; + case MANAGER_COMMAND_LIST_ROUTES: + _manager_send_list_routes (handle, sock, &client_name, socklen, seq); + break; + default: + _manager_send_invalid_request (sock, &client_name, socklen, seq); } return TRUE; diff --git a/src/network-inador.c b/src/network-inador.c index 8fef09d..8e17d2d 100644 --- a/src/network-inador.c +++ b/src/network-inador.c @@ -45,6 +45,7 @@ #include "events.h" #include "manager.h" #include "bridge.h" +#include "routes.h" static GMainLoop *loop = NULL; @@ -86,6 +87,7 @@ int main (int argc, char *argv[]) { loop = g_main_loop_new (NULL, FALSE); handle.interfaces = NULL; + handle.rtable_v4 = NULL; Interface *to_up; @@ -95,6 +97,8 @@ int main (int argc, char *argv[]) { interfaces_list_all (&handle, nl_sock); + routes_list (&handle, nl_sock); + events_setup_loop (&handle, nl_watch); manager_setup_socket (&handle); diff --git a/src/network-inador.h b/src/network-inador.h index 54bcf31..151a2e5 100644 --- a/src/network-inador.h +++ b/src/network-inador.h @@ -23,6 +23,8 @@ #ifndef __NETWORK_INADOR_H__ #define __NETWORK_INADOR_H__ +#include + #include #include #include @@ -57,8 +59,23 @@ typedef struct _Interface { struct _Interface *next; } Interface; +typedef struct _Routev4 { + struct in_addr dest; + uint32_t prefix; + + struct in_addr gateway; + unsigned int index; + + unsigned char table; + unsigned char type; + + struct _Routev4 *next; +} Routev4; + typedef struct { Interface *interfaces; + Routev4 *rtable_v4; + int netlink_sock_request; } NetworkInadorHandle; diff --git a/src/routes.c b/src/routes.c new file mode 100644 index 0000000..4bae017 --- /dev/null +++ b/src/routes.c @@ -0,0 +1,579 @@ +/* + * routes.c + * This file is part of Network-inador + * + * Copyright (C) 2018 - 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 "network-inador.h" +#include "interfaces.h" +#include "rta_aux.h" + +static uint32_t _routes_utils_ip4_prefix_to_netmask (uint32_t prefix) { + return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF; +} + +static Routev4 * _routes_append_routev4_to_struct (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix) { + Routev4 *new_route, *last; + + new_route = (Routev4 *) malloc (sizeof (Routev4)); + + memset (new_route, 0, sizeof (Routev4)); + + new_route->dest = dest; + new_route->prefix = prefix; + + new_route->next = NULL; + + if (handle->rtable_v4 == NULL) { + handle->rtable_v4 = new_route; + } else { + last = handle->rtable_v4; + + while (last->next != NULL) { + last = last->next; + } + + last->next = new_route; + } + + return new_route; +} + +static Routev4 * _routes_search_ipv4 (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix, unsigned int index) { + Routev4 *list; + + list = handle->rtable_v4; + + while (list != NULL) { + if (list->dest.s_addr == dest.s_addr && + list->prefix == prefix && + list->index == index) { + return list; + } + list = list->next; + } + + return NULL; +} + +static void _routes_delete_by_chain (NetworkInadorHandle *handle, Routev4 *route) { + Routev4 *list, *next, *before; + struct in_addr mask; + struct in_addr with_mask; + struct in_addr dest_masked; + + /* Si esta es una ruta local sin gateway, lo más seguro es que se eliminó una IP, + * hay que eliminar todas las rutas que contengan un gateway que haga match + * con el destino de la ruta y la interfaz + * Esto asegura que se eliminen rutas como 0.0.0.0/0 + */ + + if (route->gateway.s_addr != 0) { + return; + } + + list = handle->rtable_v4; + + mask.s_addr = _routes_utils_ip4_prefix_to_netmask (route->prefix); + dest_masked.s_addr = route->dest.s_addr & mask.s_addr; + + while (list != NULL) { + next = list->next; + + if (list == route) { + /* Solo por seguridad, la ruta ya debería estar desligada de la lista */ + list = next; + continue; + } + + if (list->index != route->index) { + /* Son de diferentes interfaces, no aplica */ + list = next; + continue; + } + + if (list->gateway.s_addr != 0) { + with_mask.s_addr = list->gateway.s_addr & mask.s_addr; + + if (with_mask.s_addr == dest_masked.s_addr) { + /* Eres una ruta que será eliminada */ + if (list == handle->rtable_v4) { + /* Excelente, primera de la lista */ + handle->rtable_v4 = list->next; + } else { + before = handle->rtable_v4; + + while (before->next != list) { + before = before->next; + } + + before->next = list->next; + } + + printf ("Ruta eliminada en cadena\n"); + free (list); + } + } + list = next; + } +} + +void routes_manual_add_ipv4 (int sock, Interface *interface, IPv4 *dest, struct in_addr gateway) { + struct msghdr rtnl_msg; + struct iovec io; + struct sockaddr_nl kernel; + char buffer[8192]; + int len; + struct nlmsghdr *nl; + struct rtmsg *route_addr; + struct rtattr *rta; + + struct nlmsgerr *l_err; + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (sock, (struct sockaddr *) &local_nl, &local_size); + + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + nl = (struct nlmsghdr *) buffer; + nl->nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + nl->nlmsg_type = RTM_NEWROUTE; + nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE | NLM_F_CREATE; + nl->nlmsg_seq = global_nl_seq++; + nl->nlmsg_pid = local_nl.nl_pid; + + route_addr = (struct rtmsg *) NLMSG_DATA (nl); + + route_addr->rtm_family = AF_INET; + route_addr->rtm_table = RT_TABLE_MAIN; + route_addr->rtm_protocol = RTPROT_STATIC; + route_addr->rtm_scope = RT_SCOPE_UNIVERSE; + route_addr->rtm_type = RTN_UNICAST; + route_addr->rtm_dst_len = dest->prefix; + + rta = (struct rtattr *) RTM_RTA (route_addr); + rta->rta_type = RTA_GATEWAY; + memcpy (RTA_DATA (rta), &gateway, sizeof (gateway)); + rta->rta_len = RTA_LENGTH (sizeof (gateway)); + nl->nlmsg_len = NLMSG_ALIGN (nl->nlmsg_len) + rta->rta_len; + + len = sizeof (buffer) - nl->nlmsg_len; + rta = (struct rtattr*) RTA_NEXT (rta, len); + rta->rta_type = RTA_OIF; + rta->rta_len = RTA_LENGTH (sizeof (int)); + *((int*)RTA_DATA(rta)) = interface->index; + nl->nlmsg_len += rta->rta_len; + + if (dest->prefix != 0) { + /* Agregar el atributo destino */ + len = sizeof (buffer) - nl->nlmsg_len; + rta = (struct rtattr*) RTA_NEXT (rta, len); + rta->rta_type = RTA_DST; + rta->rta_len = RTA_LENGTH (sizeof (struct in_addr)); + memcpy (RTA_DATA(rta), &dest->sin_addr, sizeof (struct in_addr)); + nl->nlmsg_len += rta->rta_len; + } + + io.iov_base = buffer; + io.iov_len = nl->nlmsg_len; + + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + len = recvmsg(sock, &rtnl_msg, 0); + nl = (struct nlmsghdr *) buffer; + for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) { + if (nl->nlmsg_type == NLMSG_DONE) { + printf ("Route ADD Msg type: DONE!\n"); + break; + } + if (nl->nlmsg_type == NLMSG_ERROR) { + l_err = (struct nlmsgerr*) NLMSG_DATA (nl); + if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) { + printf ("Route ADD Error tamaño truncado\n"); + } else if (l_err->error != 0) { + // Error: + printf ("Route ADD Error: %i\n", l_err->error); + } + break; + } + } +} + +void routes_manual_del_v4 (int sock, Routev4 *route) { + struct msghdr rtnl_msg; + struct iovec io; + struct sockaddr_nl kernel; + char buffer[8192]; + int len; + struct nlmsghdr *nl; + struct rtmsg *route_addr; + struct rtattr *rta; + struct nlmsgerr *l_err; + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (sock, (struct sockaddr *) &local_nl, &local_size); + + memset (&kernel, 0, sizeof (kernel)); + memset (buffer, 0, sizeof (buffer)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&io, 0, sizeof (io)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + nl = (struct nlmsghdr *) buffer; + nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + nl->nlmsg_type = RTM_DELROUTE; + nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nl->nlmsg_seq = global_nl_seq++; + nl->nlmsg_pid = local_nl.nl_pid; + + route_addr = (struct rtmsg *) NLMSG_DATA (nl); + + route_addr->rtm_family = AF_INET; + route_addr->rtm_scope = RT_SCOPE_NOWHERE; + route_addr->rtm_type = route->type; + route_addr->rtm_table = route->table; + route_addr->rtm_dst_len = route->prefix; + route_addr->rtm_protocol = 0; + + if (route->prefix != 0) { + rta = (struct rtattr *) RTM_RTA (route_addr); + rta->rta_type = RTA_DST; + rta->rta_len = RTA_LENGTH (sizeof (struct in_addr)); + memcpy (RTA_DATA(rta), &route->dest, sizeof (struct in_addr)); + nl->nlmsg_len += rta->rta_len; + } + + io.iov_base = buffer; + io.iov_len = nl->nlmsg_len; + + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + len = recvmsg(sock, &rtnl_msg, 0); + nl = (struct nlmsghdr *) buffer; + for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) { + if (nl->nlmsg_type == NLMSG_DONE) { + printf ("Route DEL Msg type: DONE!\n"); + break; + } + if (nl->nlmsg_type == NLMSG_ERROR) { + l_err = (struct nlmsgerr*) NLMSG_DATA (nl); + if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) { + printf ("Route DEL Error tamaño truncado\n"); + } else if (l_err->error != 0) { + // Error: + printf ("Route DEL Error: %i\n", l_err->error); + } + break; + } + } +} + +void routes_add_or_update_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) { + struct rtmsg *route_addr; + struct rtattr *attribute; + size_t len; + char ip_as_string[1024]; + Routev4 *new; + struct in_addr dest; + int prefix; + struct in_addr gateway; + unsigned index = 0; + + memset (&dest, 0, sizeof (dest)); + memset (&gateway, 0, sizeof (gateway)); + + route_addr = NLMSG_DATA(h); + + if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) { + printf ("Omitiendo ruta local o broadcast\n"); + return; + } + + if (route_addr->rtm_family != AF_INET) { + /* Por el momento, las direcciones IPv6 no son procesadas */ + return; + } + + printf ("--------\n"); + printf ("Route list, family: %d\n", route_addr->rtm_family); + printf ("Route Dest len: %d\n", route_addr->rtm_dst_len); + printf ("Route Table id: %d\n", route_addr->rtm_table); + printf ("Route type: %d\n", route_addr->rtm_type); + printf ("Route flags: %d\n", route_addr->rtm_flags); + printf ("Route protocol: %d\n", route_addr->rtm_protocol); + + prefix = route_addr->rtm_dst_len; + + len = RTM_PAYLOAD (h); + //len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); + + for_each_rattr (attribute, RTM_RTA (route_addr), len) { + //printf ("Attribute (addr): %d\n", attribute->rta_type); + + if (attribute->rta_type == RTA_GATEWAY) { + memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr)); + + inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); + printf ("Gw Address: %s\n", ip_as_string); + } else if (attribute->rta_type == RTA_DST) { + memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr)); + + inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); + printf ("Destination Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len); + } else if (attribute->rta_type == RTA_OIF) { + index = *((int *) RTA_DATA (attribute)); + printf ("!!!!!!!!! Output interface: %i\n", index); + } else if (attribute->rta_type == RTA_PREFSRC) { + //printf ( + } else if (attribute->rta_type == RTA_TABLE) { + + } else { + printf ("ROUTE Attribute: %d\n", attribute->rta_type); + } + } + + if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) { + printf ("Omitiendo ruta local o broadcast\n"); + return; + } + + new = _routes_search_ipv4 (handle, dest, prefix, index); + + if (new == NULL) { + printf ("Agregando Ruta a la lista de rutas\n"); + new = _routes_append_routev4_to_struct (handle, dest, prefix); + } + + /* Actualizar la gateway si hubo gateway en el mensaje */ + memcpy (&new->gateway, &gateway, sizeof (new->gateway)); + new->index = index; + new->table = route_addr->rtm_table; + new->type = route_addr->rtm_type; +} + +void routes_del_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) { + struct rtmsg *route_addr; + Routev4 *route, *before; + struct rtattr *attribute; + size_t len; + char ip_as_string[1024]; + struct in_addr dest; + int prefix; + int index; + + memset (&dest, 0, sizeof (dest)); + + route_addr = NLMSG_DATA(h); + + if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) { + //printf ("Omitiendo ruta local o broadcast\n"); + //return; + } + + if (route_addr->rtm_family != AF_INET) { + /* Por el momento, las direcciones IPv6 no son procesadas */ + return; + } + + printf ("--------> ROUTE DEL <--------\n"); + printf ("Route list, family: %d\n", route_addr->rtm_family); + printf ("Route Dest len: %d\n", route_addr->rtm_dst_len); + printf ("Route Table id: %d\n", route_addr->rtm_table); + printf ("Route type: %d\n", route_addr->rtm_type); + printf ("Route flags: %d\n", route_addr->rtm_flags); + printf ("Route protocol: %d\n", route_addr->rtm_protocol); + + prefix = route_addr->rtm_dst_len; + + //len = RTM_PAYLOAD (h); + len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); + + for (attribute = RTM_RTA (route_addr); RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { + //printf ("Attribute (addr): %d\n", attribute->rta_type); + + if (attribute->rta_type == RTA_GATEWAY) { + //memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr)); + + inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); + printf ("Gw Address: %s\n", ip_as_string); + } else if (attribute->rta_type == RTA_DST) { + memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr)); + + inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); + printf ("Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len); + } else if (attribute->rta_type == RTA_OIF) { + index = *((int *) RTA_DATA (attribute)); + printf ("Output interface: %i\n", index); + } else { + printf ("ROUTE Attribute: %d\n", attribute->rta_type); + } + } + + route = _routes_search_ipv4 (handle, dest, prefix, index); + + if (route == NULL) { + printf ("Me solicitaron eliminar una ruta y no existe\n"); + } else { + if (route == handle->rtable_v4) { + handle->rtable_v4 = route->next; + } else { + before = handle->rtable_v4; + + while (before->next != route) { + before = before->next; + } + + before->next = route->next; + } + + _routes_delete_by_chain (handle, route); + + free (route); + } +} + +void routes_list (NetworkInadorHandle *handle, int sock) { + struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ + struct iovec io; + struct rtmsg *rt; + struct sockaddr_nl kernel; + char buffer[8192]; /* a large buffer */ + int len; + + /* Para la respuesta */ + struct nlmsghdr *msg_ptr; /* pointer to current part */ + + struct sockaddr_nl local_nl; + socklen_t local_size; + + /* Recuperar el puerto local del netlink */ + local_size = sizeof (local_nl); + getsockname (sock, (struct sockaddr *) &local_nl, &local_size); + + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (&kernel, 0, sizeof (kernel)); + memset (&buffer, 0, sizeof (buffer)); + + kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ + kernel.nl_groups = 0; + + msg_ptr = (struct nlmsghdr *) buffer; + msg_ptr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + msg_ptr->nlmsg_type = RTM_GETROUTE; + msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + msg_ptr->nlmsg_seq = global_nl_seq++; + msg_ptr->nlmsg_pid = local_nl.nl_pid; + + rt = (struct rtmsg*) NLMSG_DATA (msg_ptr); + rt->rtm_family = AF_INET; /* Limitar la primer consulta a solo IPv4, por el momento */ + + io.iov_base = buffer; + io.iov_len = msg_ptr->nlmsg_len; + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof(kernel); + + sendmsg (sock, (struct msghdr *) &rtnl_msg, 0); + + /* Esperar la respuesta */ + memset (&io, 0, sizeof (io)); + memset (&rtnl_msg, 0, sizeof (rtnl_msg)); + memset (buffer, 0, sizeof (buffer)); + + io.iov_base = buffer; + io.iov_len = sizeof (buffer); + rtnl_msg.msg_iov = &io; + rtnl_msg.msg_iovlen = 1; + rtnl_msg.msg_name = &kernel; + rtnl_msg.msg_namelen = sizeof (kernel); + + while ((len = recvmsg(sock, &rtnl_msg, 0)) > 0) { /* read lots of data */ + msg_ptr = (struct nlmsghdr *) buffer; + if (msg_ptr->nlmsg_type == NLMSG_DONE) break; + + for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { + /* Procesar solo los mensajes de nueva interfaz */ + printf ("ROUTE Msg type: %i\n", msg_ptr->nlmsg_type); + if (msg_ptr->nlmsg_type == RTM_NEWROUTE) { + routes_add_or_update_rtm (handle, msg_ptr); + } + } + } +} diff --git a/src/routes.h b/src/routes.h new file mode 100644 index 0000000..ec3f6f9 --- /dev/null +++ b/src/routes.h @@ -0,0 +1,35 @@ +/* + * routes.h + * This file is part of Network-inador + * + * Copyright (C) 2018 - 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 + */ + +#ifndef __ROUTES_H__ +#define __ROUTES_H__ + +#include "network-inador.h" + +void routes_list (NetworkInadorHandle *handle, int sock); +void routes_add_or_update_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h); +void routes_del_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h); +void routes_manual_add_ipv4 (int sock, Interface *interface, IPv4 *dest, struct in_addr gateway); +void routes_manual_del_v4 (int sock, Routev4 *route); + +#endif + diff --git a/src/rta_aux.h b/src/rta_aux.h index d9ba3b7..4069976 100644 --- a/src/rta_aux.h +++ b/src/rta_aux.h @@ -23,6 +23,9 @@ #ifndef __RTA_AUX_H__ #define __RTA_AUX_H__ +#define for_each_rattr(n, buf, len) \ +for (n = (struct rtattr*)buf; RTA_OK(n, len); n = RTA_NEXT(n, len)) + int rta_addattr_l (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen); struct rtattr * rta_addattr_nest (struct nlmsghdr *n, int maxlen, int type); int rta_addattr_nest_end (struct nlmsghdr *n, struct rtattr *nest);