/* * ni-interface.c * This file is part of NetworkInador * * Copyright (C) 2021 - Gatuno * * NetworkInador 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. * * NetworkInador 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 NetworkInador; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ #include #include #include #include "ni-client.h" #include "ni-interface.h" #include "ni-ip.h" #include "../src/network-inador-manager.h" struct _NIInterfacePrivate { NIClient *ni_client; guint index; gchar *name; guint type; guint master_index; guint mtu; guint flags; gboolean is_wireless; GList *ip_list; }; enum { PROP_NI_CLIENT = 1, PROP_INDEX, PROP_NAME, PROP_TYPE, PROP_MASTER_INDEX, PROP_MTU, PROP_FLAGS, PROP_WIRELESS, N_PROPERTIES }; static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; enum { NEW_IP, DELETE_IP, LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; struct _SearchIP { guint family; guint prefix; struct_addr local_addr; struct_addr addr; gboolean has_local_addr; }; G_DEFINE_TYPE_WITH_PRIVATE (NIInterface, ni_interface, G_TYPE_OBJECT) static gboolean ni_interface_process_interface_response (NIClient *ni_client, unsigned char *buffer, guint size, gpointer data); #if 0 static GObject *ni_interface_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { GObject *obj; GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); NIInterface *ni_interface; obj = parent_class->constructor (type, n_construct_properties, construct_properties); ni_interface = NI_INTERFACE (obj); { int g; for (g = 0; g < n_construct_properties; g++) { GParamSpec *pspec = construct_properties[g].pspec; GValue *value = construct_properties[g].value; /* Manejar el valor */ if (strcmp (g_param_spec_get_name (pspec), "index") == 0) { printf ("Estableciendo sobre el constructor, el index\n"); ni_interface->priv->index = g_value_get_uint (value); ni_interface_check_and_connect_signal (ni_interface); } else if (strcmp (g_param_spec_get_name (pspec), "ni-client") == 0) { ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); } } } return obj; } #endif static void ni_interface_constructed (GObject *obj) { NIInterface *ni_interface; GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); parent_class->constructed (obj); ni_interface = NI_INTERFACE (obj); if (ni_interface->priv->ni_client != NULL && ni_interface->priv->index != 0) { /* Conectar la señal de datos */ g_signal_connect (ni_interface->priv->ni_client, "packet-read", G_CALLBACK (ni_interface_process_interface_response), ni_interface); /* Solicitar listado de IP's */ ni_client_ask_ip_interface (ni_interface->priv->ni_client, ni_interface, AF_UNSPEC); } } static void ni_interface_dispose (GObject *obj) { NIInterface *ni_interface; GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); ni_interface = NI_INTERFACE (obj); g_signal_handlers_disconnect_by_func (ni_interface->priv->ni_client, G_CALLBACK (ni_interface_process_interface_response), ni_interface); /* Quitar la referencia hacia el ni_client */ g_object_unref (ni_interface->priv->ni_client); parent_class->dispose (obj); } static void ni_interface_finalize (GObject *obj) { NIInterface *ni_interface; GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); ni_interface = NI_INTERFACE (obj); /* Nada que hacer, por el momento */ parent_class->finalize (obj); } static void ni_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NIInterface *ni_interface = NI_INTERFACE (object); g_return_if_fail (NI_IS_INTERFACE (object)); switch (prop_id) { case PROP_NI_CLIENT: ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); g_object_ref (ni_interface->priv->ni_client); break; case PROP_INDEX: ni_interface->priv->index = g_value_get_uint (value); break; case PROP_NAME: if (ni_interface->priv->name != NULL) { g_free (ni_interface->priv->name); } ni_interface->priv->name = g_value_dup_string (value); break; case PROP_TYPE: ni_interface->priv->type = g_value_get_uint (value); break; case PROP_WIRELESS: ni_interface->priv->is_wireless = g_value_get_boolean (value); break; case PROP_MTU: ni_interface->priv->mtu = g_value_get_uint (value); break; case PROP_MASTER_INDEX: ni_interface->priv->master_index = g_value_get_uint (value); break; case PROP_FLAGS: ni_interface->priv->flags = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_interface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NIInterface *ni_interface = NI_INTERFACE (object); g_return_if_fail (NI_IS_INTERFACE (object)); switch (prop_id) { case PROP_NI_CLIENT: g_value_set_object (value, ni_interface->priv->ni_client); break; case PROP_INDEX: g_value_set_uint (value, ni_interface->priv->index); break; case PROP_NAME: g_value_set_string (value, ni_interface->priv->name); break; case PROP_TYPE: g_value_set_uint (value, ni_interface->priv->type); break; case PROP_WIRELESS: g_value_set_boolean (value, ni_interface->priv->is_wireless); break; case PROP_MTU: g_value_set_uint (value, ni_interface->priv->mtu); break; case PROP_MASTER_INDEX: g_value_set_uint (value, ni_interface->priv->master_index); break; case PROP_FLAGS: g_value_set_uint (value, ni_interface->priv->flags); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void ni_interface_class_init (NIInterfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = ni_interface_set_property; object_class->get_property = ni_interface_get_property; object_class->constructed = ni_interface_constructed; object_class->dispose = ni_interface_dispose; object_class->finalize = ni_interface_finalize; obj_properties[PROP_NI_CLIENT] = g_param_spec_object ( "ni-client", "Network Inador Client", "The client object", NI_TYPE_CLIENT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_INDEX] = g_param_spec_uint ( "index", "Index", "The index of the interface.", 1, G_MAXUINT, 1, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_NAME] = g_param_spec_string ( "name", "Name", "Name of the interface", NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_TYPE] = g_param_spec_uint ( "type", "Interface Type", "Type of the interface.", 0, G_MAXUINT, 1, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_MASTER_INDEX] = g_param_spec_uint ( "master-index", "Master index", "The index of the master interface", 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_MTU] = g_param_spec_uint ( "mtu", "MTU", "The mtu of the interface.", 0, G_MAXUINT, 1500, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_FLAGS] = g_param_spec_uint ( "flags", "Flags", "The flags of the interface.", 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); obj_properties[PROP_WIRELESS] = g_param_spec_boolean ( "wireless", "Wireless", "Indicates if this interface is wireless", FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); signals[NEW_IP] = g_signal_new ("new-ip", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NI_TYPE_IP); signals[DELETE_IP] = g_signal_new ("delete-ip", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, NI_TYPE_IP); } static gint ni_interface_locate_ip (gconstpointer *a, gconstpointer *b) { NIIP *ni_ip = (NIIP *) a; struct _SearchIP *search_ip = (struct _SearchIP *) b; int family_size = 0; if (ni_ip_get_family (ni_ip) != search_ip->family) return -1; if (search_ip->family == AF_INET) { family_size = sizeof (struct in_addr); } else if (search_ip->family == AF_INET6) { family_size = sizeof (struct in6_addr); } if (ni_ip_get_prefix (ni_ip) != search_ip->prefix) return -1; if (memcmp (ni_ip_get_addr (ni_ip), &search_ip->addr, family_size) != 0) { return -1; } if (ni_ip_has_local (ni_ip) != search_ip->has_local_addr) { return -1; } if (search_ip->has_local_addr) { if (memcmp (ni_ip_get_local_addr (ni_ip), &search_ip->local_addr, family_size) != 0) { return -1; } } return 0; } static void ni_interface_process_interface_update (NIInterface *ni_interface, gpointer data, guint size) { unsigned char *buffer = (unsigned char *) data; uint32_t master_index, mtu; uint16_t flags; guint name_size; char iface_name[128]; memcpy (&master_index, &buffer[10], 4); memcpy (&mtu, &buffer[14], 4); memcpy (&flags, &buffer[18], 2); name_size = buffer[21]; memcpy (iface_name, &buffer[22], name_size); iface_name[name_size] = 0; g_object_freeze_notify (G_OBJECT (ni_interface)); if (ni_interface->priv->name == NULL) { ni_interface->priv->name = g_strdup (iface_name); g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); } else if (strcmp (ni_interface->priv->name, iface_name) != 0) { g_free (ni_interface->priv->name); ni_interface->priv->name = g_strdup (iface_name); g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); } if (ni_interface->priv->master_index != master_index) { ni_interface->priv->master_index = master_index; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); } if (ni_interface->priv->mtu != mtu) { ni_interface->priv->master_index = master_index; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); } if (ni_interface->priv->flags != flags) { ni_interface->priv->flags = flags; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_FLAGS]); } g_object_thaw_notify (G_OBJECT (ni_interface)); } static void ni_interface_process_ip_added (NIInterface *ni_interface, gpointer data, guint size) { unsigned char *buffer = (unsigned char *) data; uint32_t index, flags; guint family, prefix, bits, scope, pos; gint family_size = 0; gboolean has_local_addr = FALSE, has_brd_addr = FALSE; NIIP *ni_ip; struct_addr addr, local_addr, brd_addr; GList *g; family = buffer[6]; prefix = buffer[7]; bits = buffer[8]; scope = buffer[9]; if (bits & 0x01) has_local_addr = TRUE; if (bits & 0x02) has_brd_addr = TRUE; memcpy (&flags, &buffer[10], 4); if (family == AF_INET) { family_size = sizeof (struct in_addr); } else if (family == AF_INET6) { family_size = sizeof (struct in6_addr); } memcpy (&addr, &buffer[14], family_size); pos = 14 + family_size; if (has_local_addr) { memcpy (&local_addr, &buffer[pos], family_size); pos += family_size; } if (has_brd_addr) { memcpy (&brd_addr, &buffer[pos], family_size); } ni_ip = ni_ip_new (ni_interface, family, prefix, &addr, flags, scope, has_local_addr, (has_local_addr ? &local_addr : NULL), has_brd_addr, (has_brd_addr ? &brd_addr : NULL)); ni_interface->priv->ip_list = g_list_append (ni_interface->priv->ip_list, ni_ip); printf ("Emitiendo signal de IP-addr\n"); g_signal_emit (ni_interface, signals[NEW_IP], 0, ni_ip); } static void ni_interface_process_ip_removed (NIInterface *ni_interface, gpointer data, guint size) { unsigned char *buffer = (unsigned char *) data; struct _SearchIP search_ip; gint family_size = 0; guint bits, pos; GList *g; NIIP *ni_ip; search_ip.family = buffer[6]; search_ip.prefix = buffer[7]; bits = buffer[8]; if (bits & 0x01) search_ip.has_local_addr = TRUE; if (search_ip.family == AF_INET) { family_size = sizeof (struct in_addr); } else if (search_ip.family == AF_INET6) { family_size = sizeof (struct in6_addr); } memcpy (&search_ip.addr, &buffer[10], family_size); pos = 10 + family_size; if (search_ip.has_local_addr) { memcpy (&search_ip.local_addr, &buffer[pos], family_size); pos += family_size; } /* Localizar la IP y eliminarla */ g = g_list_find_custom (ni_interface->priv->ip_list, &search_ip, (GCompareFunc) ni_interface_locate_ip); if (g == NULL) { /* ¿IP eliminada sin que exista? Super error */ } else { ni_ip = (NIIP *) g->data; ni_interface->priv->ip_list = g_list_remove (ni_interface->priv->ip_list, g->data); /* Ahora, ya desligado, emitir la señal */ g_signal_emit (ni_interface, signals[DELETE_IP], 0, ni_ip); g_object_unref (ni_ip); } } static gboolean ni_interface_process_interface_response (NIClient *ni_client, unsigned char *buffer, guint size, gpointer user_data) { NIInterface *ni_interface = (NIInterface *) user_data; uint32_t index; if (buffer[0] == NET_INADOR_TYPE_EVENT) { switch (buffer[1]) { case NET_INADOR_EVENT_IPADDR_ADDED: memcpy (&index, &buffer[2], 4); if (index != ni_interface->priv->index) { /* Mensaje de IP, pero no para mí, dejar pasar */ return FALSE; } ni_interface_process_ip_added (ni_interface, buffer, size); return TRUE; break; case NET_INADOR_EVENT_IFACE_ADDED: /* Mensaje de actualización de mi estado */ memcpy (&index, &buffer[2], 4); if (index != ni_interface->priv->index) { /* Mensaje de la interfaz, pero no para mí, dejar pasar */ return FALSE; } ni_interface_process_interface_update (ni_interface, buffer, size); return TRUE; break; case NET_INADOR_EVENT_IPADDR_REMOVED: memcpy (&index, &buffer[2], 4); if (index != ni_interface->priv->index) { /* Mensaje de la interfaz, pero no para mí, dejar pasar */ return FALSE; } ni_interface_process_ip_removed (ni_interface, buffer, size); return TRUE; break; } } else if (buffer[0] == NET_INADOR_TYPE_RESPONSE) { switch (buffer[1]) { case NET_INADOR_RESPONSE_IPADDR: memcpy (&index, &buffer[2], 4); if (index != ni_interface->priv->index) { /* Mensaje de IP, pero no para mí, dejar pasar */ return FALSE; } printf ("Response IP addr sobre interfaz\n"); ni_interface_process_ip_added (ni_interface, buffer, size); return TRUE; break; case NET_INADOR_RESPONSE_IFACE: memcpy (&index, &buffer[2], 4); if (index != ni_interface->priv->index) { /* Mensaje de la interfaz, pero no para mí, dejar pasar */ return FALSE; } ni_interface_process_interface_update (ni_interface, buffer, size); return TRUE; break; } } return FALSE; /* Que se siga procesando */ } guint ni_interface_get_index (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), 0); return ni_interface->priv->index; } const gchar *ni_interface_get_name (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); return ni_interface->priv->name; } guint ni_interface_get_iface_type (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), 0); return ni_interface->priv->type; } gboolean ni_interface_is_wireless (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), FALSE); return ni_interface->priv->is_wireless; } NIClient *ni_interface_get_client (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); return ni_interface->priv->ni_client; } const GList *ni_interface_get_ip_list (NIInterface *ni_interface) { g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); return ni_interface->priv->ip_list; } #if 0 void ni_interface_consume_values (NIInterface *ni_interface, char *name, gint arp_type, guint master_index, guint mtu, guint flags) { g_object_freeze_notify (G_OBJECT (ni_interface)); if (ni_interface->priv->name == NULL) { ni_interface->priv->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); } else if (strcmp (ni_interface->priv->name, name) != 0) { g_free (ni_interface->priv->name); ni_interface->priv->name = g_strdup (name); g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); } if (ni_interface->priv->arp_type != arp_type) { ni_interface->priv->arp_type = arp_type; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_ARP_TYPE]); } if (ni_interface->priv->master_index != master_index) { ni_interface->priv->master_index = master_index; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); } if (ni_interface->priv->mtu != mtu) { ni_interface->priv->master_index = master_index; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); } if (ni_interface->priv->flags != flags) { ni_interface->priv->flags = flags; g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_FLAGS]); } g_object_thaw_notify (G_OBJECT (ni_interface)); } #endif static void ni_interface_init (NIInterface *ni_interface) { NIInterfacePrivate *priv = ni_interface_get_instance_private (ni_interface); ni_interface->priv = priv; /* initialize all public and private members to reasonable default values. * They are all automatically initialized to 0 to begin with. */ priv->ni_client = NULL; priv->index = 0; priv->name = NULL; priv->type = 0; priv->is_wireless = FALSE; priv->master_index = 0; priv->mtu = 0; priv->flags = 0; priv->ip_list = NULL; }