/* * manager.c * This file is part of Network-inador * * Copyright (C) 2011 - 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 #include #include "common.h" #include "interfaces.h" #include "ip-address.h" #include "network-inador-manager.h" #define COMMAND_SOCKET_PATH "/tmp/network-inador.socket" static void _manager_send_error (ManagerClientInfo *manager_client, int error, int orig_cmd) { unsigned char buffer[8]; buffer[0] = NET_INADOR_TYPE_RESPONSE_ERROR; buffer[1] = orig_cmd; buffer[2] = error; send (manager_client->fd, buffer, 3, 0); } static void _manager_send_executed (ManagerClientInfo *manager_client) { unsigned char buffer[8]; buffer[0] = NET_INADOR_TYPE_RESPONSE; buffer[1] = NET_INADOR_RESPONSE_EXECUTED; send (manager_client->fd, buffer, 2, 0); } static void _manager_send_end_command (ManagerClientInfo *manager_client, int orig_cmd) { unsigned char buffer[8]; buffer[0] = NET_INADOR_TYPE_RESPONSE_LISTING_END; buffer[1] = orig_cmd; send (manager_client->fd, buffer, 2, 0); } static Interface * _manager_fetch_interface (ManagerClientInfo *manager_client, unsigned char *buffer, int orig_cmd) { Interface *iface; uint32_t index; memcpy (&index, buffer, 4); /* TODO: Revisar el ntohl */ iface = _interfaces_locate_by_index (manager_client->manager->handle->interfaces, index); if (iface == NULL) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_IFACE_INDEX, orig_cmd); return NULL; } return iface; } void _manager_send_interface (ManagerClientInfo *manager_client, Interface *iface, gboolean is_event) { unsigned char buffer[32 + IFNAMSIZ + IFNAMSIZ]; int name_len = strlen (iface->name); if (is_event) { buffer[0] = NET_INADOR_TYPE_EVENT; buffer[1] = NET_INADOR_EVENT_IFACE_ADDED; } else { buffer[0] = NET_INADOR_TYPE_RESPONSE; buffer[1] = NET_INADOR_RESPONSE_IFACE; } memcpy (&buffer[2], &iface->index, 4); memcpy (&buffer[6], &iface->link_type, 4); memcpy (&buffer[10], &iface->master_index, 4); memcpy (&buffer[14], &iface->mtu, 4); memcpy (&buffer[18], &iface->flags, 2); buffer[20] = iface->is_wireless; buffer[21] = name_len; memcpy (&buffer[22], iface->name, name_len); send (manager_client->fd, buffer, 22 + name_len, 0); } void _manager_send_interface_del (ManagerClientInfo *manager_client, uint32_t index) { unsigned char buffer[8]; buffer[0] = NET_INADOR_TYPE_EVENT; buffer[1] = NET_INADOR_EVENT_IFACE_REMOVED; memcpy (&buffer[2], &index, 4); send (manager_client->fd, buffer, 6, 0); } void _manager_send_ip (ManagerClientInfo *manager_client, IPAddr *ip_addr, gboolean is_event) { unsigned char buffer[80]; int family_size = 0; int pos; if (is_event) { buffer[0] = NET_INADOR_TYPE_EVENT; buffer[1] = NET_INADOR_EVENT_IPADDR_ADDED; } else { buffer[0] = NET_INADOR_TYPE_RESPONSE; buffer[1] = NET_INADOR_RESPONSE_IPADDR; } if (ip_addr->family == AF_INET) { family_size = sizeof (struct in_addr); } else if (ip_addr->family == AF_INET6) { family_size = sizeof (struct in6_addr); } memcpy (&buffer[2], &ip_addr->iface->index, 4); buffer[6] = ip_addr->family; buffer[7] = ip_addr->prefix; buffer[8] = 0; if (ip_addr->has_local) { buffer[8] |= 0x01; } if (ip_addr->has_brd) { buffer[8] |= 0x02; } buffer[9] = ip_addr->scope; memcpy (&buffer[10], &ip_addr->flags, 4); memcpy (&buffer[14], &ip_addr->addr, family_size); pos = 14 + family_size; if (ip_addr->has_local) { memcpy (&buffer[pos], &ip_addr->local_addr, family_size); pos += family_size; } if (ip_addr->has_brd) { memcpy (&buffer[pos], &ip_addr->brd_addr, family_size); pos += family_size; } send (manager_client->fd, buffer, pos, 0); } void _manager_send_ip_del (ManagerClientInfo *manager_client, IPAddr *ip_addr) { unsigned char buffer[80]; int family_size = 0; int pos; buffer[0] = NET_INADOR_TYPE_EVENT; buffer[1] = NET_INADOR_EVENT_IPADDR_REMOVED; if (ip_addr->family == AF_INET) { family_size = sizeof (struct in_addr); } else if (ip_addr->family == AF_INET6) { family_size = sizeof (struct in6_addr); } memcpy (&buffer[2], &ip_addr->iface->index, 4); buffer[6] = ip_addr->family; buffer[7] = ip_addr->prefix; buffer[8] = 0; if (ip_addr->has_local) { buffer[8] |= 0x01; } buffer[9] = 0; memcpy (&buffer[10], &ip_addr->addr, family_size); pos = 10 + family_size; if (ip_addr->has_local) { memcpy (&buffer[pos], &ip_addr->local_addr, family_size); pos += family_size; } send (manager_client->fd, buffer, pos, 0); } void _manager_send_list_interfaces (ManagerClientInfo *manager_client) { GList *g; Interface *iface; g = manager_client->manager->handle->interfaces; while (g != NULL) { iface = (Interface *) g->data; _manager_send_interface (manager_client, iface, FALSE); g = g->next; } _manager_send_end_command (manager_client, NET_INADOR_COMMAND_LIST_IFACES); } void _manager_send_iface (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { Interface *iface; if (buffer_len < 6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_GET_IFACE); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_GET_IFACE); if (iface == NULL) return; _manager_send_interface (manager_client, iface, FALSE); } void _manager_send_list_ips (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { int family; GList *g; IPAddr *ip_addr; Interface *iface; if (buffer_len < 7) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_LIST_IP); return; } family = buffer[6]; if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_LIST_IP); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_LIST_IP); if (iface == NULL) return; for (g = iface->address; g != NULL; g = g->next) { ip_addr = (IPAddr *) g->data; if (family != AF_UNSPEC && family != ip_addr->family) continue; _manager_send_ip (manager_client, ip_addr, FALSE); } _manager_send_end_command (manager_client, NET_INADOR_COMMAND_LIST_IP); } void _manager_execute_iface_down_up (ManagerClientInfo *manager_client, int is_up, unsigned char *buffer, int buffer_len) { Interface *iface; int ret; if (buffer_len < 6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, (is_up ? NET_INADOR_COMMAND_IFACE_UP : NET_INADOR_COMMAND_IFACE_DOWN)); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], (is_up ? NET_INADOR_COMMAND_IFACE_UP : NET_INADOR_COMMAND_IFACE_DOWN)); if (iface == NULL) return; if (is_up) { ret = interfaces_change_set_up (manager_client->manager->handle, iface->index); } else { ret = interfaces_change_set_down (manager_client->manager->handle, iface->index); } if (ret == 0) { /* OK */ _manager_send_executed (manager_client); } else { _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, (is_up ? NET_INADOR_COMMAND_IFACE_UP : NET_INADOR_COMMAND_IFACE_DOWN)); } } void _manager_execute_iface_change_name (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { Interface *iface; int ret; int name_len; unsigned char name[IFNAMSIZ]; if (buffer_len < 7) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_IFACE_CHANGE_NAME); if (iface == NULL) return; name_len = buffer[6]; if (name_len == 0 || name_len >= IFNAMSIZ) { _manager_send_error (manager_client, NET_INADOR_ERROR_BAD_STRING, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); return; } if (name_len + 7 < buffer_len) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); return; } memcpy (name, &buffer[7], name_len); if (name[0] == 0) { _manager_send_error (manager_client, NET_INADOR_ERROR_BAD_STRING, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); return; } ret = interfaces_change_name (manager_client->manager->handle, iface->index, name); if (ret == 0) { /* OK */ _manager_send_executed (manager_client); } else { _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); } } void _manager_execute_clear_ips (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { int family; Interface *iface; IPAddr *ip_addr; GList *g; int ret; if (buffer_len < 7) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_CLEAR_IP); return; } family = buffer[6]; if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_CLEAR_IP); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_CLEAR_IP); if (iface == NULL) return; ret = 0; for (g = iface->address; g != NULL; g = g->next) { ip_addr = (IPAddr *) g->data; if (family != AF_UNSPEC && family != ip_addr->family) continue; ret |= ip_address_del_ip (manager_client->manager->handle, iface->index, ip_addr); } if (ret == 0) { /* OK */ _manager_send_executed (manager_client); } else { _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_CLEAR_IP); } } void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { Interface *iface; IPAddr ip_addr; GList *g; int ret; int family_size, wanted_size, family; int has_local, has_brd; if (buffer_len < 14) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_ADD_IP); return; } family = ip_addr.family = buffer[6]; if (family != AF_INET && family != AF_INET6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_ADD_IP); return; } iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_ADD_IP); if (iface == NULL) return; ip_addr.prefix = buffer[7]; if (ip_addr.family == AF_INET && (ip_addr.prefix > 32 || ip_addr.prefix < 1)) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_ADD_IP); return; } else if (ip_addr.family == AF_INET6 && (ip_addr.prefix > 128 || ip_addr.prefix < 1)) { _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_ADD_IP); return; } has_local = buffer[8] & 0x01; has_brd = (buffer[8] & 0x02) >> 1; if (ip_addr.family == AF_INET) { family_size = sizeof (struct in_addr); } else if (ip_addr.family == AF_INET6) { family_size = sizeof (struct in6_addr); } /* Ya puedo revisar el resto de la longitud */ wanted_size = 14 + family_size + (family_size * has_local) + (family_size * has_brd); if (buffer_len < wanted_size) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_ADD_IP); return; } ip_addr.scope = buffer[9]; memcpy (&ip_addr.flags, &buffer[10], 4); memcpy (&ip_addr.addr, &buffer[14], family_size); wanted_size = 14 + family_size; if (has_local) { memcpy (&ip_addr.local_addr, &buffer[wanted_size], family_size); wanted_size += family_size; } if (has_brd) { memcpy (&ip_addr.brd_addr, &buffer[wanted_size], family_size); wanted_size += family_size; } ret = ip_address_add_ip (manager_client->manager->handle, iface->index, &ip_addr); if (ret == 0) { /* OK */ _manager_send_executed (manager_client); } else { _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_ADD_IP); } } static void _manager_handle_set_event_mask (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { uint32_t events; if (buffer_len < 6) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_SET_EVENT_MASK); return; } memcpy (&events, &buffer[2], 4); printf ("___ MANAGER __ Set events de un cliente (%i), eventos: %u\n", manager_client->fd, events); manager_client->wanted_events = events; } static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) { ManagerClientInfo *manager_client = (ManagerClientInfo *) data; NetworkInadorManager *manager = manager_client->manager; int type, command; Interface *iface; int g; unsigned char buffer[8192]; int bytes; bytes = recv (manager_client->fd, buffer, sizeof (buffer), 0); if (bytes <= 0) { printf ("___ MANAGER ___ Conexión cerrada manager (%i)\n", manager_client->fd); /* Error de lectura o cierre */ close (manager_client->fd); manager->connected_client_list = g_list_remove (manager->connected_client_list, manager_client); free (manager_client); return FALSE; } printf ("___ MANAGER ___ Data arrival (%i):\n", manager_client->fd); for (g = 0; g < bytes; g++) { printf ("%02hhx ", buffer[g]); } printf ("\n"); /* Comando incompleto */ if (bytes < 2) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, 0); return TRUE; } /* Procesar los datos del cliente */ type = buffer[0]; if (type != NET_INADOR_TYPE_COMMAND) { _manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, 0); return TRUE; } command = buffer[1]; switch (command) { case NET_INADOR_COMMAND_LIST_IFACES: _manager_send_list_interfaces (manager_client); break; case NET_INADOR_COMMAND_GET_IFACE: _manager_send_iface (manager_client, buffer, bytes); break; case NET_INADOR_COMMAND_IFACE_UP: case NET_INADOR_COMMAND_IFACE_DOWN: _manager_execute_iface_down_up (manager_client, (command == NET_INADOR_COMMAND_IFACE_UP), buffer, bytes); break; case NET_INADOR_COMMAND_IFACE_CHANGE_NAME: _manager_execute_iface_change_name (manager_client, buffer, bytes); break; case NET_INADOR_COMMAND_LIST_IP: _manager_send_list_ips (manager_client, buffer, bytes); break; case NET_INADOR_COMMAND_CLEAR_IP: _manager_execute_clear_ips (manager_client, buffer, bytes); break; case NET_INADOR_COMMAND_ADD_IP: _manager_execute_add_ip (manager_client, buffer, bytes); break; /*case NET_INADOR_COMMAND_REMOVE_IP: break;*/ case NET_INADOR_COMMAND_SET_EVENT_MASK: _manager_handle_set_event_mask (manager_client, buffer, bytes); break; default: _manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command); } return TRUE; } static gboolean _manager_client_connect (GIOChannel *source, GIOCondition condition, gpointer data) { NetworkInadorManager *manager = (NetworkInadorManager *) data; ManagerClientInfo *manager_client; int fd; GIOChannel *channel; fd = accept (manager->socket, NULL, NULL); printf ("___ MANAGER ___ Nueva conexión (%i)\n", fd); manager_client = malloc (sizeof (ManagerClientInfo)); if (manager_client == NULL) { close (fd); return TRUE; } memset (manager_client, 0, sizeof (*manager_client)); manager_client->fd = fd; /* Generar el vigilador */ channel = g_io_channel_unix_new (fd); manager_client->source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_client_data, manager_client); g_io_channel_unref (channel); manager_client->manager = manager; manager->connected_client_list = g_list_prepend (manager->connected_client_list, manager_client); return TRUE; } void manager_send_event_interface_add (NetworkInadorHandle *handle, Interface *iface) { printf ("___ MANAGER ___ Informando interfaz agregada: %s (%i)\n", iface->name, iface->index); GList *g; ManagerClientInfo *manager_client; if (handle->manager == NULL) return; for (g = handle->manager->connected_client_list; g != NULL; g = g->next) { manager_client = (ManagerClientInfo *) g->data; if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_INTERFACES) { printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd); _manager_send_interface (manager_client, iface, TRUE); } } } void manager_send_event_interface_del (NetworkInadorHandle *handle, uint32_t index) { printf ("___ MANAGER ___ Informando interfaz eliminada: %i\n", index); GList *g; ManagerClientInfo *manager_client; if (handle->manager == NULL) return; for (g = handle->manager->connected_client_list; g != NULL; g = g->next) { manager_client = (ManagerClientInfo *) g->data; if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_INTERFACES) { printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd); _manager_send_interface_del (manager_client, index); } } } void manager_send_event_interface_update (NetworkInadorHandle *handle, Interface *iface) { printf ("___ MANAGER ___ Informando interfaz actualizada: %s (%i)\n", iface->name, iface->index); GList *g; ManagerClientInfo *manager_client; if (handle->manager == NULL) return; for (g = handle->manager->connected_client_list; g != NULL; g = g->next) { manager_client = (ManagerClientInfo *) g->data; if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_INTERFACES) { printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd); _manager_send_interface (manager_client, iface, TRUE); } } } void manager_send_event_ip_add (NetworkInadorHandle *handle, IPAddr *ip_addr) { printf ("___ MANAGER ___ Informando ip agregada: %s (%i)\n", ip_addr->iface->name, ip_addr->iface->index); GList *g; ManagerClientInfo *manager_client; if (handle->manager == NULL) return; for (g = handle->manager->connected_client_list; g != NULL; g = g->next) { manager_client = (ManagerClientInfo *) g->data; if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_IP) { printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd); _manager_send_ip (manager_client, ip_addr, TRUE); } } } void manager_send_event_ip_del (NetworkInadorHandle *handle, IPAddr *ip_addr) { printf ("___ MANAGER ___ Informando ip eliminada: %s (%i)\n", ip_addr->iface->name, ip_addr->iface->index); GList *g; ManagerClientInfo *manager_client; if (handle->manager == NULL) return; for (g = handle->manager->connected_client_list; g != NULL; g = g->next) { manager_client = (ManagerClientInfo *) g->data; if (manager_client->wanted_events & NET_INADOR_EVENT_MASK_IP) { printf ("___ MANAGER ___ Informando a la conexión (%i)\n", manager_client->fd); _manager_send_ip_del (manager_client, ip_addr); } } } int manager_init (NetworkInadorHandle *handle) { NetworkInadorManager *manager; struct sockaddr_un socket_name; GIOChannel *channel; manager = malloc (sizeof (NetworkInadorManager)); if (manager == NULL) { return -1; } memset (manager, 0, sizeof (*manager)); manager->socket = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); if (manager->socket < 0) { perror ("Failed to create AF_UNIX socket"); free (manager); return -1; } memset (&socket_name, 0, sizeof (struct sockaddr_un)); socket_name.sun_family = AF_UNIX; strncpy (socket_name.sun_path, COMMAND_SOCKET_PATH, sizeof (socket_name.sun_path) - 1); unlink (COMMAND_SOCKET_PATH); if (bind (manager->socket, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) { perror ("bind"); close (manager->socket); manager->socket = -1; free (manager); return -1; } if (listen (manager->socket, 10) < 0) { perror ("listen"); close (manager->socket); manager->socket = -1; free (manager); return -1; } /* TODO: Aplicar permisos aquí */ chmod (COMMAND_SOCKET_PATH, 0666); channel = g_io_channel_unix_new (manager->socket); manager->source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_client_connect, manager); g_io_channel_unref (channel); manager->handle = handle; handle->manager = manager; return 0; }