From 4380abdeb7e6f2cd90d4b034423ba260c254a8b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Thu, 2 Jan 2020 12:53:53 -0600 Subject: [PATCH] Agrego manejo de IP's usando libnl3 --- src/Makefile.am | 3 +- src/common.h | 16 +++- src/interfaces.c | 8 +- src/interfaces.h | 5 ++ src/ip-address.c | 208 +++++++++++++++++++++++++++++++++++++++++++ src/ip-address.h | 34 +++++++ src/netlink-events.c | 15 +++- 7 files changed, 283 insertions(+), 6 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 6da7387..6fe1925 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,7 +3,8 @@ bin_PROGRAMS = network-inador network_inador_SOURCES = main.c common.h \ netlink-events.c netlink-events.h \ - interfaces.c interfaces.h + interfaces.c interfaces.h \ + ip-address.c ip-address.h #network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) diff --git a/src/common.h b/src/common.h index b3539c4..0d4d689 100644 --- a/src/common.h +++ b/src/common.h @@ -23,6 +23,8 @@ #ifndef __COMMON_H__ #define __COMMON_H__ +#include + #include #include #include @@ -38,6 +40,18 @@ #define TRUE !FALSE #endif +typedef struct _IPAddr { + sa_family_t family; + union { + struct in_addr sin_addr; + struct in6_addr sin6_addr; + }; + uint32_t prefix; + + unsigned char flags; + unsigned char scope; +} IPAddr; + typedef struct _Interface { char name[IFNAMSIZ]; int ifi_type; @@ -65,7 +79,7 @@ typedef struct _Interface { int is_nlmon; int is_dummy; - //IPv4 *v4_address; + GList *address; //DHCPStateInfo dhcp_info; diff --git a/src/interfaces.c b/src/interfaces.c index 5c59a8a..9632c89 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -30,9 +30,10 @@ #include #include "common.h" +#include "interfaces.h" +#include "ip-address.h" static int _interfaces_receive_message_interface (struct nl_msg *msg, void *arg, int first_time); -Interface * _interfaces_locate_by_index (GList *list, int index); static int _interfaces_list_first_time (struct nl_msg *msg, void *arg) { return _interfaces_receive_message_interface (msg, arg, TRUE); @@ -263,6 +264,9 @@ int interface_receive_message_dellink (struct nl_msg *msg, void *arg) { handle->interfaces = g_list_remove (handle->interfaces, iface); + /* Antes de eliminar la interfaz, eliminar la lista ligada de todas las direcciones IP */ + g_list_free_full (iface->address, g_free); + g_free (iface); } @@ -553,5 +557,7 @@ void interfaces_init (NetworkInadorHandle *handle) { nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_list_first_time, handle); nl_recvmsgs_default (handle->nl_sock_route); + + ip_address_init (handle); } diff --git a/src/interfaces.h b/src/interfaces.h index d427e51..084da53 100644 --- a/src/interfaces.h +++ b/src/interfaces.h @@ -23,12 +23,17 @@ #ifndef __INTERFACES_H__ #define __INTERFACES_H__ +#include +#include + #include "common.h" void interfaces_init (NetworkInadorHandle *handle); int interface_receive_message_newlink (struct nl_msg *msg, void *arg); int interface_receive_message_dellink (struct nl_msg *msg, void *arg); +Interface * _interfaces_locate_by_index (GList *list, int index); + int interfaces_change_mac_address (NetworkInadorHandle *handle, int index, void *new_mac); int interfaces_change_mtu (NetworkInadorHandle *handle, int index, uint32_t new_mtu); int interfaces_change_set_up (NetworkInadorHandle *handle, int index); diff --git a/src/ip-address.c b/src/ip-address.c index e69de29..02babef 100644 --- a/src/ip-address.c +++ b/src/ip-address.c @@ -0,0 +1,208 @@ +/* + * ip-address.c + * This file is part of Network-inador + * + * Copyright (C) 2019, 2020 - 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 "common.h" +#include "ip-address.h" +#include "interfaces.h" + +static IPAddr *_ip_address_search_addr (Interface *iface, sa_family_t family, void *addr_data, uint32_t prefix) { + GList *g; + IPAddr *addr; + + for (g = iface->address; g != NULL; g = g->next) { + addr = (IPAddr *) g->data; + + if (addr->family == family) { + if (family == AF_INET && memcmp (&addr->sin_addr, addr_data, sizeof (struct in_addr)) == 0 && addr->prefix == prefix) { + return addr; + } else if (family == AF_INET6 && memcmp (&addr->sin6_addr, addr_data, sizeof (struct in6_addr)) == 0 && addr->prefix == prefix) { + return addr; + } + } + } + + return NULL; +} + +int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { + struct nlmsghdr *reply; + struct ifaddrmsg *addr_msg; + int remaining; + struct nlattr *attr; + NetworkInadorHandle *handle = (NetworkInadorHandle *) arg; + Interface *iface; + int has_addr = 0; + struct in_addr sin_addr; + struct in6_addr sin6_addr; + IPAddr *addr; + + reply = nlmsg_hdr (msg); + + if (reply->nlmsg_type != RTM_NEWADDR) return NL_SKIP; + + addr_msg = nlmsg_data (reply); + + iface = _interfaces_locate_by_index (handle->interfaces, addr_msg->ifa_index); + + if (iface == NULL) { + printf ("IP para una interfaz desconocida\n"); + return NL_SKIP; + } + + nlmsg_for_each_attr(attr, reply, sizeof (struct ifaddrmsg), remaining) { + if (nla_type (attr) != IFA_ADDRESS) continue; + + if (addr_msg->ifa_family == AF_INET && nla_len (attr) == 4) { + /* IP de ipv4 */ + memcpy (&sin_addr, nla_data (attr), nla_len (attr)); + has_addr = 1; + } else if (addr_msg->ifa_family == AF_INET6 && nla_len (attr) == 16) { + /* IP de ipv6 */ + memcpy (&sin6_addr, nla_data (attr), nla_len (attr)); + has_addr = 1; + } + } + + + if (addr_msg->ifa_family == AF_INET) { + addr = _ip_address_search_addr (iface, AF_INET, &sin_addr, addr_msg->ifa_prefixlen); + } else if (addr_msg->ifa_family == AF_INET6) { + addr = _ip_address_search_addr (iface, AF_INET6, &sin6_addr, addr_msg->ifa_prefixlen); + } + + if (addr == NULL) { + addr = g_new0 (IPAddr, 1); + + iface->address = g_list_append (iface->address, addr); + + addr->family = addr_msg->ifa_family; + if (addr->family == AF_INET) { + memcpy (&addr->sin_addr, &sin_addr, sizeof (struct in_addr)); + } else if (addr->family == AF_INET6) { + memcpy (&addr->sin6_addr, &sin6_addr, sizeof (struct in6_addr)); + } + + addr->prefix = addr_msg->ifa_prefixlen; + } + + char buffer[2048]; + inet_ntop (addr->family, &addr->sin_addr, buffer, sizeof (buffer)); + printf ("Dirección IP %s/%d sobre interfaz: %d\n", buffer, addr->prefix, iface->index); + + addr->flags = addr_msg->ifa_flags; + addr->scope = addr_msg->ifa_scope; + + return NL_SKIP; +} + +int ip_address_receive_message_deladdr (struct nl_msg *msg, void *arg) { + struct nlmsghdr *reply; + struct ifaddrmsg *addr_msg; + int remaining; + struct nlattr *attr; + NetworkInadorHandle *handle = (NetworkInadorHandle *) arg; + Interface *iface; + struct in_addr sin_addr; + struct in6_addr sin6_addr; + IPAddr *addr = NULL; + + reply = nlmsg_hdr (msg); + + if (reply->nlmsg_type != RTM_DELADDR) return NL_SKIP; + + addr_msg = nlmsg_data (reply); + + iface = _interfaces_locate_by_index (handle->interfaces, addr_msg->ifa_index); + + if (iface == NULL) { + printf ("IP para una interfaz desconocida\n"); + return NL_SKIP; + } + + nlmsg_for_each_attr(attr, reply, sizeof (struct ifaddrmsg), remaining) { + if (nla_type (attr) != IFA_ADDRESS) continue; + + if (addr_msg->ifa_family == AF_INET && nla_len (attr) == 4) { + /* IP de ipv4 */ + memcpy (&sin_addr, nla_data (attr), nla_len (attr)); + } else if (addr_msg->ifa_family == AF_INET6 && nla_len (attr) == 16) { + /* IP de ipv6 */ + memcpy (&sin6_addr, nla_data (attr), nla_len (attr)); + } + } + + + if (addr_msg->ifa_family == AF_INET) { + addr = _ip_address_search_addr (iface, AF_INET, &sin_addr, addr_msg->ifa_prefixlen); + } else if (addr_msg->ifa_family == AF_INET6) { + addr = _ip_address_search_addr (iface, AF_INET6, &sin6_addr, addr_msg->ifa_prefixlen); + } + + if (addr == NULL) { + printf ("IP no encontrada\n"); + return NL_SKIP; + } + + /* Eliminar de la lista ligada */ + iface->address = g_list_remove (iface->address, addr); + + g_free (addr); + + return NL_SKIP; +} + +void ip_address_init (NetworkInadorHandle *handle) { + /* Si es la primera vez que nos llaman, descargar una primera lista de direcciones en todas las interfaces */ + struct nl_msg * msg; + struct ifaddrmsg addr_hdr = { + .ifa_family = AF_UNSPEC, + }; + int ret; + + msg = nlmsg_alloc_simple (RTM_GETADDR, NLM_F_REQUEST | NLM_F_DUMP); + ret = nlmsg_append (msg, &addr_hdr, sizeof (addr_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + return; + } + + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, ip_address_receive_message_newaddr, handle); + + nl_recvmsgs_default (handle->nl_sock_route); +} + diff --git a/src/ip-address.h b/src/ip-address.h index e69de29..35ddf4a 100644 --- a/src/ip-address.h +++ b/src/ip-address.h @@ -0,0 +1,34 @@ +/* + * ip-address.c + * This file is part of Network-inador + * + * Copyright (C) 2019, 2020 - 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 __IP_ADDRESS_H__ +#define __IP_ADDRESS_H__ + +#include +#include + +#include "common.h" + +int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg); +void ip_address_init (NetworkInadorHandle *handle); + +#endif diff --git a/src/netlink-events.c b/src/netlink-events.c index 7f1e009..b9fb1b1 100644 --- a/src/netlink-events.c +++ b/src/netlink-events.c @@ -27,6 +27,7 @@ #include "common.h" #include "interfaces.h" +#include "ip-address.h" static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) { struct nlmsghdr *reply; @@ -35,12 +36,20 @@ static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) { switch (reply->nlmsg_type) { case RTM_NEWLINK: - interface_receive_message_newlink (msg, arg); + return interface_receive_message_newlink (msg, arg); break; case RTM_DELLINK: - interface_receive_message_dellink (msg, arg); + return interface_receive_message_dellink (msg, arg); + break; + case RTM_NEWADDR: + return ip_address_receive_message_newaddr (msg, arg); + break; + case RTM_DELADDR: + return ip_address_receive_message_deladdr (msg, arg); break; } + + return NL_SKIP; } static gboolean _netlink_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) { @@ -64,7 +73,7 @@ void netlink_events_setup (NetworkInadorHandle *handle) { } nl_socket_set_nonblocking (sock_req); - nl_socket_add_memberships (sock_req, RTNLGRP_LINK, 0); + nl_socket_add_memberships (sock_req, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, 0); nl_socket_disable_seq_check (sock_req); nl_socket_modify_cb (sock_req, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle);