NetworkInador/client-gtk/ni-client.c

1204 lines
31 KiB
C
Raw Normal View History

/*
* ni-client.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 <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "ni-client.h"
#include "ni-interface.h"
#include "ni-marshal.h"
2022-02-06 23:28:26 -06:00
#include "ni-route.h"
#include "../src/network-inador-manager.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
/* Privados desde el ni-interface */
void ni_interface_consume_values (NIInterface *ni_interface, char *name, gint arp_type, guint master_index, guint mtu, guint flags);
/* Privados locales */
static void ni_client_dispose (GObject *obj);
static void ni_client_finalize (GObject *obj);
struct _NIClientPrivate {
int client_socket;
gchar *socket_path;
GHashTable *interfaces;
2022-02-06 23:28:26 -06:00
GList *routes_v4, *routes_v6;
GList *route_tables_names;
guint source;
guint events;
};
enum {
PROP_SOCKET_PATH = 1,
N_PROPERTIES
};
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
enum {
DATA_READ,
NEW_INTERFACE,
DELETE_INTERFACE,
2022-02-06 23:28:26 -06:00
NEW_ROUTE,
DELETE_ROUTE,
NEW_ROUTE_TABLE,
DELETE_ROUTE_TABLE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE_WITH_PRIVATE (NIClient, ni_client, G_TYPE_OBJECT)
static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size);
static void ni_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
NIClient *ni_client = NI_CLIENT (object);
g_return_if_fail (NI_IS_CLIENT (object));
switch (prop_id) {
case PROP_SOCKET_PATH:
if (ni_client->priv->socket_path != NULL) {
g_free (ni_client->priv->socket_path);
}
ni_client->priv->socket_path = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void ni_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
NIClient *ni_client = NI_CLIENT (object);
g_return_if_fail (NI_IS_CLIENT (object));
switch (prop_id) {
case PROP_SOCKET_PATH:
g_value_set_string (value, ni_client->priv->socket_path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void ni_client_class_init (NIClientClass *klass) {
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = ni_client_set_property;
object_class->get_property = ni_client_get_property;
object_class->dispose = ni_client_dispose;
object_class->finalize = ni_client_finalize;
obj_properties[PROP_SOCKET_PATH] = g_param_spec_string (
"socket-path",
"Socket Path",
"The path of the unix socket.",
COMMAND_SOCKET_PATH,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
signals[DATA_READ] = g_signal_new ("packet-read",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, data_response),
g_signal_accumulator_true_handled,
NULL,
_ni_marshal_BOOLEAN__POINTER_UINT,
G_TYPE_BOOLEAN,
2,
G_TYPE_POINTER | G_SIGNAL_TYPE_STATIC_SCOPE,
G_TYPE_UINT);
signals[NEW_INTERFACE] = g_signal_new ("new-interface",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, new_interface),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
NI_TYPE_INTERFACE);
signals[DELETE_INTERFACE] = g_signal_new ("delete-interface",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, delete_interface),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
NI_TYPE_INTERFACE);
2022-02-06 23:28:26 -06:00
signals[NEW_ROUTE] = g_signal_new ("new-route",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, new_route),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
NI_TYPE_ROUTE);
signals[DELETE_ROUTE] = g_signal_new ("delete-route",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, delete_route),
NULL,
NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
NI_TYPE_ROUTE);
signals[NEW_ROUTE_TABLE] = g_signal_new ("new-route-table",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, new_route_table),
NULL,
NULL,
_ni_marshal_VOID__UINT_STRING,
G_TYPE_NONE,
2,
G_TYPE_UINT,
G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE);
signals[NEW_ROUTE_TABLE] = g_signal_new ("delete-route-table",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (NIClientClass, delete_route_table),
NULL,
NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE,
1,
G_TYPE_UINT);
klass->data_response = ni_client_data_read;
klass->new_interface = NULL;
klass->delete_interface = NULL;
2022-02-06 23:28:26 -06:00
klass->new_route = NULL;
klass->delete_route = NULL;
klass->new_route_table = NULL;
klass->delete_route_table = NULL;
}
static void ni_client_process_interface_response (NIClient *ni_client, gpointer data, guint size) {
NIInterface *ni_interface;
unsigned char *buffer = (unsigned char *) data;
uint32_t index, master_index, mtu, type;
uint16_t flags;
uint8_t bits;
guint name_size;
char iface_name[128];
memcpy (&index, &buffer[2], 4);
memcpy (&type, &buffer[6], 4);
memcpy (&master_index, &buffer[10], 4);
memcpy (&mtu, &buffer[14], 4);
memcpy (&flags, &buffer[18], 2);
bits = buffer[20];
name_size = buffer[21];
memcpy (iface_name, &buffer[22], name_size);
iface_name[name_size] = 0;
/* Insertar y crear */
ni_interface = g_object_new (NI_TYPE_INTERFACE, "ni-client", ni_client, "index", index, "wireless", (bits == 0 ? FALSE : TRUE), "type", type, "name", iface_name, "mtu", mtu, "flags", flags, "master-index", master_index, NULL);
g_hash_table_insert (ni_client->priv->interfaces, GINT_TO_POINTER(index), ni_interface);
g_signal_emit (ni_client, signals[NEW_INTERFACE], 0, ni_interface);
}
2022-12-24 18:39:46 -06:00
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) {
2022-02-06 23:28:26 -06:00
GList *g;
NIRoute *ni_route;
int family_size = 0;
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
} else if (family == AF_INET6) {
family_size = sizeof (struct in6_addr);
}
for (g = list_routes; g != NULL; g = g->next) {
ni_route = (NIRoute *) g->data;
2022-12-24 18:39:46 -06:00
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;
2022-02-06 23:28:26 -06:00
if (memcmp (ni_route_get_dest (ni_route), dest, family_size) == 0 && ni_route_get_prefix(ni_route) == prefix) {
return ni_route;
}
}
return NULL;
}
static void ni_client_process_route_response (NIClient *ni_client, gpointer data, guint size) {
unsigned char *buffer = (unsigned char *) data;
uint8_t family, family_size;
uint8_t type, protocol, tos, scope, prefix;
uint32_t tabla, prioridad;
uint8_t num_nexthops;
gboolean has_prefsrc;
int pos, g;
NIRouteNH nexthops[16];
NIRoute *ni_route;
struct_addr dest, prefsrc;
memset (nexthops, 0, sizeof (nexthops));
family = buffer[2];
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
} else if (family == AF_INET6) {
family_size = sizeof (struct in6_addr);
}
type = buffer[3];
memcpy (&tabla, &buffer[4], 4);
prefix = buffer[8];
protocol = buffer[9];
tos = buffer[10];
scope = buffer[11];
has_prefsrc = FALSE;
if (buffer[12] & 0x01) {
has_prefsrc = TRUE;
}
num_nexthops = buffer[13];
memcpy (&prioridad, &buffer[14], 4);
memcpy (&dest, &buffer[18], family_size);
pos = 18 + family_size;
if (has_prefsrc) {
memcpy (&prefsrc, &buffer[pos], family_size);
pos += family_size;
}
if (num_nexthops > 16) {
num_nexthops = 16;
}
for (g = 0; g < num_nexthops; g++) {
nexthops[g].has_gw = FALSE;
if (buffer[pos] & 0x01) {
/* Tiene GW */
nexthops[g].has_gw = TRUE;
}
pos++;
nexthops[g].flags = buffer[pos];
pos++;
nexthops[g].weight = buffer[pos];
pos++;
pos++; /* El byte ignorado */
memcpy (&nexthops[g].out_index, &buffer[pos], 4);
pos +=4;
if (nexthops[g].has_gw) {
memcpy (&nexthops[g].gw, &buffer[pos], family_size);
pos += family_size;
}
}
ni_route = ni_route_new (ni_client, family, type, tabla, &dest, prefix, protocol, tos, scope, (has_prefsrc ? &prefsrc : NULL), prioridad, num_nexthops, nexthops);
if (family == AF_INET) {
ni_client->priv->routes_v4 = g_list_append (ni_client->priv->routes_v4, ni_route);
} else if (family == AF_INET6) {
ni_client->priv->routes_v6 = g_list_append (ni_client->priv->routes_v6, ni_route);
}
g_signal_emit (ni_client, signals[NEW_ROUTE], 0, ni_route);
}
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;
2022-12-24 18:39:46 -06:00
uint8_t tos, prefix;
2022-02-06 23:28:26 -06:00
uint32_t tabla, prioridad;
NIRoute *ni_route;
struct_addr dest;
GList *list_routes;
family = buffer[2];
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
list_routes = ni_client->priv->routes_v4;
} else if (family == AF_INET6) {
family_size = sizeof (struct in6_addr);
list_routes = ni_client->priv->routes_v6;
}
2022-12-24 18:39:46 -06:00
tos = buffer[3];
2022-02-06 23:28:26 -06:00
memcpy (&tabla, &buffer[4], 4);
prefix = buffer[8];
memcpy (&prioridad, &buffer[9], 4);
memcpy (&dest, &buffer[13], family_size);
2022-12-24 18:39:46 -06:00
ni_route = _ni_client_search_route (list_routes, family, tos, tabla, &dest, prefix, prioridad);
2022-02-06 23:28:26 -06:00
if (ni_route == NULL) {
/* ¿No hay ruta? Raro */
return;
}
/* Desligar la ruta */
if (family == AF_INET) {
ni_client->priv->routes_v4 = g_list_remove (ni_client->priv->routes_v4, ni_route);
} else if (family == AF_INET6) {
ni_client->priv->routes_v6 = g_list_remove (ni_client->priv->routes_v6, ni_route);
}
g_signal_emit (ni_client, signals[DELETE_ROUTE], 0, ni_route);
/* Liberar el objeto */
g_object_unref (ni_route);
}
static void ni_client_process_route_table_name_response (NIClient *ni_client, gpointer data, guint size) {
unsigned char *buffer = (unsigned char *) data;
uint8_t name_len;
uint32_t tabla;
struct _NIClientRouteTable *rtable;
name_len = buffer[6];
memcpy (&tabla, &buffer[2], 4);
rtable = g_malloc (sizeof (struct _NIClientRouteTable));
rtable->table = tabla;
memcpy (rtable->name, &buffer[7], name_len);
rtable->name[name_len] = 0;
ni_client->priv->route_tables_names = g_list_append (ni_client->priv->route_tables_names, rtable);
g_signal_emit (ni_client, signals[NEW_ROUTE_TABLE], 0, rtable->table, rtable->name);
}
static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size) {
unsigned char *buffer = (unsigned char *) data;
uint32_t index;
NIInterface *ni_interface;
if (buffer[0] == NET_INADOR_TYPE_EVENT) {
switch (buffer[1]) {
case NET_INADOR_EVENT_IFACE_ADDED:
memcpy (&index, &buffer[2], 4);
/* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
if (ni_interface == NULL) {
ni_client_process_interface_response (ni_client, data, size);
return TRUE;
} else {
return FALSE;
}
break;
case NET_INADOR_EVENT_IFACE_REMOVED:
memcpy (&index, &buffer[2], 4);
/* La interfaz fué eliminada, nosotros procesamos este evento */
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
if (ni_interface == NULL) {
/* ¿Evento de una interfaz eliminada? Ignorar */
} else {
g_hash_table_remove (ni_client->priv->interfaces, GINT_TO_POINTER(index));
g_signal_emit (ni_client, signals[DELETE_INTERFACE], 0, ni_interface);
g_object_unref (ni_interface);
}
return TRUE;
break;
2022-01-02 23:07:39 -06:00
case NET_INADOR_EVENT_DHCP_STATUS:
memcpy (&index, &buffer[2], 4);
/* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
if (ni_interface == NULL) {
/* Esta es una condición de error interesante. No debería ocurrir. Absorber el evento */
return TRUE;
}
/* Dejar pasar el evento para que la propia interfaz lo procese */
return FALSE;
break;
2022-02-06 23:28:26 -06:00
case NET_INADOR_EVENT_ROUTE_REMOVED:
/* Eliminar una ruta es ligeramente mas complejo porque necesitamos que haga match con varios valores para eliminarla */
ni_client_process_route_del_response (ni_client, data, size);
return TRUE;
break;
case NET_INADOR_EVENT_ROUTE_ADDED:
/* TODO: Revisar si la ruta existe, entonces, en teoría, es una actualización */
ni_client_process_route_response (ni_client, data, size);
return FALSE;
break;
case NET_INADOR_EVENT_ROUTE_TABLE_ADDED:
return FALSE;
break;
case NET_INADOR_EVENT_ROUTE_TABLE_REMOVED:
2022-02-06 23:28:26 -06:00
return FALSE;
break;
}
} else if (buffer[0] == NET_INADOR_TYPE_RESPONSE) {
switch (buffer[1]) {
case NET_INADOR_RESPONSE_IFACE:
memcpy (&index, &buffer[2], 4);
/* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
if (ni_interface == NULL) {
ni_client_process_interface_response (ni_client, data, size);
return TRUE;
} else {
return FALSE;
}
break;
2022-01-02 23:07:39 -06:00
case NET_INADOR_RESPONSE_DHCP_STATUS:
memcpy (&index, &buffer[2], 4);
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
if (ni_interface == NULL) {
/* Esta es una condición de error interesante. No debería ocurrir. Absorber el evento */
return TRUE;
}
/* Dejar pasar el evento para que la propia interfaz lo procese */
return FALSE;
break;
2022-02-06 23:28:26 -06:00
case NET_INADOR_RESPONSE_ROUTE:
/* Cuando hacemos listado, no hay problemas de actualización */
ni_client_process_route_response (ni_client, data, size);
return FALSE;
break;
case NET_INADOR_RESPONSE_ROUTE_TABLE:
ni_client_process_route_table_name_response (ni_client, data, size);
return FALSE;
break;
}
}
/* Procesar los datos aquí */
return TRUE;
}
static gboolean ni_client_read_from_socket (GIOChannel *source, GIOCondition condition, gpointer data) {
NIClient *ni_client = NI_CLIENT (data);
unsigned char buffer[8192];
int res;
gboolean stop;
int g;
res = recv (ni_client->priv->client_socket, buffer, sizeof (buffer), 0);
if (res <= 0) {
/* El socket se cerró */
close (ni_client->priv->client_socket);
ni_client->priv->client_socket = -1;
/* Eliminar el source */
if (ni_client->priv->source > 0) {
g_source_remove (ni_client->priv->source);
ni_client->priv->source = 0;
}
/* TODO: Disparar aquí una señal de desconexión al network-inador */
return FALSE;
}
printf ("Data arrival: %i\n", res);
for (g = 0; g < res; g++) {
printf ("%02hhx ", buffer[g]);
}
printf ("\n");
/* Tenemos datos, hacer una validación básica */
if (buffer[0] != NET_INADOR_TYPE_RESPONSE &&
buffer[0] != NET_INADOR_TYPE_RESPONSE_ERROR &&
buffer[0] != NET_INADOR_TYPE_EVENT &&
buffer[0] != NET_INADOR_TYPE_RESPONSE_LISTING_END) {
/* Tipo de paquete inválido */
return TRUE;
}
g_signal_emit (ni_client, signals[DATA_READ], 0, (void *) buffer, res, &stop);
return TRUE;
}
static gboolean ni_client_foreach_remove_every_interface (gpointer key, gpointer value, gpointer user_data) {
NIInterface *ni_interface = NI_INTERFACE (value);
g_object_unref (ni_interface);
return TRUE;
}
static void ni_client_dispose (GObject *obj) {
NIClient *ni_client;
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
ni_client = NI_CLIENT (obj);
/* Recorrer todos los objetos interface para quitarles una referencia y liberarlos */
g_hash_table_foreach_remove (ni_client->priv->interfaces, ni_client_foreach_remove_every_interface, NULL);
if (ni_client->priv->source > 0) {
g_source_remove (ni_client->priv->source);
ni_client->priv->source = 0;
}
parent_class->dispose (obj);
}
static void ni_client_finalize (GObject *obj) {
NIClient *ni_client;
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
ni_client = NI_CLIENT (obj);
g_hash_table_destroy (ni_client->priv->interfaces);
if (ni_client->priv->client_socket >= 0) {
close (ni_client->priv->client_socket);
ni_client->priv->client_socket = 0;
}
if (ni_client->priv->socket_path != NULL) {
g_free (ni_client->priv->socket_path);
ni_client->priv->socket_path = NULL;
}
parent_class->finalize (obj);
}
static void ni_client_init (NIClient *ni_client) {
NIClientPrivate *priv = ni_client_get_instance_private (ni_client);
ni_client->priv = priv;
priv->client_socket = -1;
priv->socket_path = NULL;
2022-02-06 23:28:26 -06:00
priv->routes_v4 = NULL;
priv->routes_v6 = NULL;
priv->route_tables_names = NULL;
priv->source = 0;
2022-02-06 23:28:26 -06:00
priv->events = NET_INADOR_EVENT_MASK_INTERFACES | NET_INADOR_EVENT_MASK_IP | NET_INADOR_EVENT_MASK_DHCP_STATUS | NET_INADOR_EVENT_MASK_ROUTES;
priv->interfaces = g_hash_table_new (g_direct_hash, g_direct_equal);
}
void ni_client_update_event_mask (NIClient *ni_client) {
unsigned char buffer[8];
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_SET_EVENT_MASK;
memcpy (&buffer[2], &ni_client->priv->events, 4);
send (ni_client->priv->client_socket, buffer, 6, 0);
}
void ni_client_ask_interfaces (NIClient *ni_client) {
unsigned char buffer[8];
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_LIST_IFACES;
send (ni_client->priv->client_socket, buffer, 2, 0);
}
2022-02-06 23:28:26 -06:00
void ni_client_ask_routes (NIClient *ni_client) {
unsigned char buffer[8];
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_LIST_ROUTES;
memset (&buffer[2], 0, 4);
buffer[6] = AF_UNSPEC;
send (ni_client->priv->client_socket, buffer, 7, 0);
}
void ni_client_ask_route_tables_names (NIClient *ni_client) {
unsigned char buffer[8];
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_LIST_ROUTE_TABLES;
memset (&buffer[2], 0, 4);
send (ni_client->priv->client_socket, buffer, 6, 0);
}
void ni_client_ask_ip_new (NIClient *ni_client, NIInterface *ni_interface, int family, int prefix, struct_addr *addr, uint32_t flags, unsigned char scope, int has_local, struct_addr *local_addr, int has_brd, struct_addr *brd_addr, uint32_t *cacheinfo) {
unsigned char buffer[80];
uint32_t index;
int family_size;
int pos;
if (ni_client->priv->client_socket < 0) {
return;
}
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
} else if (family == AF_INET6) {
family_size = sizeof (struct in6_addr);
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_ADD_IP;
memcpy (&buffer[2], &index, 4);
buffer[6] = family;
buffer[7] = prefix;
buffer[8] = 0;
if (has_local) {
buffer[8] |= 0x01;
}
if (has_brd) {
buffer[8] |= 0x02;
}
buffer[9] = scope;
memcpy (&buffer[10], &flags, 4);
/* Copiar los timestamp solicitados */
memcpy (&buffer[14], cacheinfo, 8);
memcpy (&buffer[22], addr, family_size);
pos = 22 + family_size;
if (has_local) {
memcpy (&buffer[pos], local_addr, family_size);
pos += family_size;
}
if (has_brd) {
memcpy (&buffer[pos], brd_addr, family_size);
pos += family_size;
}
send (ni_client->priv->client_socket, buffer, pos, 0);
}
void ni_client_ask_ip_delete (NIClient *ni_client, NIInterface *ni_interface, NIIP *ni_ip) {
unsigned char buffer[32];
uint32_t index;
int family_size;
int pos;
const struct_addr *addr, *local_addr;
int family = ni_ip_get_family (ni_ip);
if (ni_client->priv->client_socket < 0) {
return;
}
if (family == AF_INET) {
family_size = sizeof (struct in_addr);
} else if (family == AF_INET6) {
family_size = sizeof (struct in6_addr);
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_REMOVE_IP;
memcpy (&buffer[2], &index, 4);
buffer[6] = family;
buffer[7] = ni_ip_get_prefix (ni_ip);
buffer[8] = 0;
if (ni_ip_has_local (ni_ip)) {
buffer[8] |= 0x01;
}
addr = ni_ip_get_addr (ni_ip);
memcpy (&buffer[9], addr, family_size);
pos = 9 + family_size;
if (ni_ip_has_local (ni_ip)) {
local_addr = ni_ip_get_local_addr (ni_ip);
memcpy (&buffer[9 + family_size], local_addr, family_size);
pos += family_size;
}
send (ni_client->priv->client_socket, buffer, pos, 0);
}
void ni_client_ask_change_iface_name (NIClient *ni_client, NIInterface *ni_interface, const gchar *new_name) {
unsigned char buffer[128];
uint32_t index;
int n_len;
if (ni_client->priv->client_socket < 0) {
return;
}
if (new_name[0] == 0) return;
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_IFACE_CHANGE_NAME;
memcpy (&buffer[2], &index, 4);
n_len = strlen (new_name);
buffer[6] = n_len;
memcpy (&buffer[7], new_name, buffer[6]);
send (ni_client->priv->client_socket, buffer, 7 + n_len, 0);
}
2021-12-10 09:56:18 -06:00
void ni_client_ask_change_iface_mtu (NIClient *ni_client, NIInterface *ni_interface, guint new_mtu) {
unsigned char buffer[128];
uint32_t index, mtu;
if (ni_client->priv->client_socket < 0) {
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_IFACE_CHANGE_MTU;
memcpy (&buffer[2], &index, 4);
//mtu = htonl (new_mtu);
mtu = new_mtu;
memcpy (&buffer[6], &mtu, 4);
send (ni_client->priv->client_socket, buffer, 10, 0);
}
void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, int family) {
unsigned char buffer[8];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_LIST_IP;
memcpy (&buffer[2], &index, 4);
buffer[6] = family;
send (ni_client->priv->client_socket, buffer, 7, 0);
}
void ni_client_ask_up_down_interface (NIClient *ni_client, NIInterface *ni_interface, gboolean is_up) {
unsigned char buffer[8];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = (is_up ? NET_INADOR_COMMAND_IFACE_UP : NET_INADOR_COMMAND_IFACE_DOWN);
memcpy (&buffer[2], &index, 4);
send (ni_client->priv->client_socket, buffer, 6, 0);
}
void ni_client_ask_dhcp_run_interface (NIClient *ni_client, NIInterface *ni_interface, int type, guint flags) {
2022-01-02 23:07:39 -06:00
unsigned char buffer[16];
uint32_t index;
uint32_t flags_to_send = flags;
2022-01-02 23:07:39 -06:00
if (ni_client->priv->client_socket < 0) {
return;
}
if (type < 1 || type > 2) {
/* Solo se permite tipo 1 o tipo 2 */
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_RUN_DHCP;
memcpy (&buffer[2], &index, 4);
buffer[6] = AF_INET;
buffer[7] = type;
memcpy (&buffer[8], &flags_to_send, 4);
2022-01-02 23:07:39 -06:00
send (ni_client->priv->client_socket, buffer, 12, 0);
}
void ni_client_ask_dhcp_stop_interface (NIClient *ni_client, NIInterface *ni_interface) {
unsigned char buffer[8];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_STOP_DHCP;
memcpy (&buffer[2], &index, 4);
buffer[6] = AF_INET;
send (ni_client->priv->client_socket, buffer, 7, 0);
}
void ni_client_ask_create_bridge (NIClient *ni_client, const gchar *name) {
unsigned char buffer[128];
int n_len;
if (ni_client->priv->client_socket < 0) {
return;
}
if (name[0] == 0) return;
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_CREATE_BRIDGE;
n_len = strlen (name);
buffer[2] = n_len;
memcpy (&buffer[3], name, buffer[2]);
send (ni_client->priv->client_socket, buffer, 3 + n_len, 0);
}
void ni_client_ask_interface_clear_master (NIClient *ni_client, NIInterface *ni_interface) {
unsigned char buffer[128];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_CLEAR_MASTER;
index = ni_interface_get_index (ni_interface);
memcpy (&buffer[2], &index, 4);
send (ni_client->priv->client_socket, buffer, 6, 0);
}
void ni_client_ask_interface_set_master (NIClient *ni_client, NIInterface *ni_interface, NIInterface *master) {
unsigned char buffer[128];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_SET_MASTER;
index = ni_interface_get_index (ni_interface);
memcpy (&buffer[2], &index, 4);
index = ni_interface_get_index (master);
memcpy (&buffer[6], &index, 4);
send (ni_client->priv->client_socket, buffer, 10, 0);
}
2022-01-02 23:07:39 -06:00
void ni_client_ask_interface_dhcp_status (NIClient *ni_client, NIInterface *ni_interface) {
unsigned char buffer[8];
uint32_t index;
if (ni_client->priv->client_socket < 0) {
return;
}
index = ni_interface_get_index (ni_interface);
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_GET_DHCP_STATUS;
memcpy (&buffer[2], &index, 4);
buffer[6] = AF_INET;
send (ni_client->priv->client_socket, buffer, 7, 0);
}
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) {
unsigned char buffer[80];
int family_size;
int pos, c;
GList *g;
NIRouteNH *nexthop;
if (ni_client->priv->client_socket < 0) {
return;
}
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_ADD_ROUTE;
buffer[2] = family;
buffer[3] = type;
memcpy (&buffer[4], &tabla, 4);
buffer[8] = prefix;
buffer[9] = protocol;
buffer[10] = tos;
buffer[11] = scope;
buffer[12] = 0;
if (has_prefsrc) {
buffer[12] |= 0x01;
}
/* La cantidad de gateways que voy a enviar con esta ruta */
g = gws;
c = 0;
while (g != NULL) {
c++;
g = g->next;
}
buffer[13] = c;
memcpy (&buffer[14], &priority, 4);
memcpy (&buffer[18], dest, family_size);
pos = 18 + family_size;
if (has_prefsrc) {
memcpy (&buffer[pos], prefsrc, family_size);
pos += family_size;
}
g = gws;
while (g != NULL) {
nexthop = (NIRouteNH *) g->data;
buffer[pos] = 0;
if (nexthop->has_gw) {
buffer[pos] |= 0x01;
}
buffer[pos + 1] = nexthop->flags;
buffer[pos + 2] = nexthop->weight;
buffer[pos + 3] = 0;
memcpy (&buffer[pos + 4], &nexthop->out_index, 4);
if (nexthop->has_gw) {
memcpy (&buffer[pos + 8], &nexthop->gw, family_size);
pos += (8 + family_size);
} else {
pos += 8;
}
g = g->next;
}
send (ni_client->priv->client_socket, buffer, pos, 0);
}
2022-12-24 18:39:46 -06:00
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;
*lista = g_list_append (*lista, value);
}
GList *ni_client_get_list_interfaces (NIClient *ni_client) {
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
GList *all_ifaces = NULL;
g_hash_table_foreach (ni_client->priv->interfaces, ni_client_foreach_has_table, &all_ifaces);
return all_ifaces;
}
NIInterface *ni_client_get_interface_by_index (NIClient *ni_client, guint index) {
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
return g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
}
2022-02-06 23:28:26 -06:00
GList *ni_client_get_routes_v4 (NIClient *ni_client) {
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
return ni_client->priv->routes_v4;
}
GList *ni_client_get_routes_v6 (NIClient *ni_client) {
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
return ni_client->priv->routes_v6;
}
GList *ni_client_get_route_tables_names (NIClient *ni_client) {
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
return ni_client->priv->route_tables_names;
}
gboolean ni_client_connect (NIClient *ni_client) {
int s, ret;
struct sockaddr_un path_dest;
GIOChannel *channel;
if (ni_client->priv->client_socket >= 0) {
return FALSE;
}
s = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
if (s < 0) {
return FALSE;
}
path_dest.sun_family = AF_UNIX;
strncpy (path_dest.sun_path, ni_client->priv->socket_path, sizeof (path_dest.sun_path));
ret = connect (s, (struct sockaddr *) &path_dest, sizeof (path_dest));
if (ret < 0) {
perror ("Connect");
close (s);
return FALSE;
}
/* Tengo socket, instalar vigilante */
ni_client->priv->client_socket = s;
channel = g_io_channel_unix_new (s);
ni_client->priv->source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, ni_client_read_from_socket, ni_client);
g_io_channel_unref (channel);
/* Pedir eventos */
ni_client_update_event_mask (ni_client);
/* Pedir un listado de interfaces */
ni_client_ask_interfaces (ni_client);
2022-02-06 23:28:26 -06:00
/* Pedir un listado de rutas */
ni_client_ask_routes (ni_client);
/* Pedir un listado de los nombres de las tablas */
ni_client_ask_route_tables_names (ni_client);
}
void ni_client_disconnect (NIClient *ni_client) {
/* TODO: Escribir esto */
}
NIClient *ni_client_new (void) {
return g_object_new (NI_TYPE_CLIENT, NULL);
}
NIClient *ni_client_new_with_path (const char *path) {
return g_object_new (NI_TYPE_CLIENT, "socket-path", path, NULL);
}