Agrego manejo de IP's usando libnl3

master
Félix Arreola Rodríguez 2020-01-02 12:53:53 -06:00
parent 060cc47735
commit 4380abdeb7
7 changed files with 283 additions and 6 deletions

View File

@ -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)

View File

@ -23,6 +23,8 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdint.h>
#include <netinet/in.h>
#include <net/ethernet.h>
#include <linux/if.h>
@ -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;

View File

@ -30,9 +30,10 @@
#include <gmodule.h>
#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);
}

View File

@ -23,12 +23,17 @@
#ifndef __INTERFACES_H__
#define __INTERFACES_H__
#include <netlink/socket.h>
#include <netlink/msg.h>
#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);

View File

@ -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 <string.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <gmodule.h>
#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);
}

View File

@ -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 <netlink/socket.h>
#include <netlink/msg.h>
#include "common.h"
int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg);
void ip_address_init (NetworkInadorHandle *handle);
#endif

View File

@ -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);