diff --git a/.gitignore b/.gitignore index b2853c2..f117102 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,4 @@ client-gtk/ni-marshal.c client-gtk/ni-marshal.h client-gtk/core -src/ni-iface-helper +src/ni-dhcp-helper diff --git a/src/Makefile.am b/src/Makefile.am index 1dd1cdc..9703ac1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -12,11 +12,11 @@ network_inador_SOURCES = main.c \ wireless_if.c wireless_if.h \ wireless_bss.c wireless_bss.h -libexec_PROGRAMS = ni-iface-helper +libexec_PROGRAMS = ni-dhcp-helper -ni_iface_helper_SOURCES = ni-iface-helper.c -ni_iface_helper_CPPFLAGS = $(AM_CPPFLAGS) -ni_iface_helper_CFLAGS = $(AM_CFLAGS) +ni_dhcp_helper_SOURCES = ni-dhcp-iface-helper.c +ni_dhcp_helper_CPPFLAGS = $(AM_CPPFLAGS) +ni_dhcp_helper_CFLAGS = $(AM_CFLAGS) #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 fcd1ed3..86fb4cb 100644 --- a/src/common.h +++ b/src/common.h @@ -120,13 +120,14 @@ enum { IFACE_ISC_DHCLIENT }; +/* FIXME: Revisar estos estados */ enum { - DHCP_CLIENT_INITING, - DHCP_CLIENT_SELECTING, - DHCP_CLIENT_REQUESTING, DHCP_CLIENT_BOUND, - DHCP_CLIENT_RENEWING, + DHCP_CLIENT_RENEWED, + + DHCP_CLIENT_EXPIRED, + DHCP_CLIENT_FAILED, DHCP_CLIENT_KILLED, DHCP_CLIENT_EXTERNAL_RUNNING @@ -143,6 +144,14 @@ typedef struct _InterfaceDHCPClientInfo { /* Para vigilar el proceso */ GPid process_pid; guint process_watch; + + /* La información obtenida desde el cliente */ + struct_addr ip, gateway, broadcast; + int prefix; + + struct_addr dhcp_server_ip; + + /* TODO: Falta almacenar la información de DNS */ } InterfaceDHCPClientInfo; struct _Interface { diff --git a/src/dhcp_client.c b/src/dhcp_client.c index eba74cf..1587b88 100644 --- a/src/dhcp_client.c +++ b/src/dhcp_client.c @@ -26,6 +26,9 @@ #include #include +#include +#include + #include #include "interfaces.h" @@ -38,10 +41,9 @@ void interfaces_dhcp_client_ignore_kill (GPid pid, gint status, gpointer data) { g_spawn_check_exit_status (status, NULL); } -void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *iface_name) { - gchar pid_file[256]; +void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *iface_name, char *pid_file, size_t pid_file_len) { + snprintf (pid_file, pid_file_len, "/run/dhclient-%s.pid", iface_name); - snprintf (pid_file, sizeof (pid_file), "/run/dhclient-%s.pid", iface_name); /* Preparar los argumentos para el proceso */ argv[0] = "/sbin/dhclient"; argv[1] = "-d"; @@ -49,7 +51,7 @@ void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *ifa argv[3] = "-pf"; argv[4] = pid_file; argv[5] = "-sf"; - argv[6] = "/home/gatuno/Proyectos/NetworkInador/src/ni-iface-helper"; + argv[6] = "/home/gatuno/Proyectos/NetworkInador/src/ni-dhcp-helper"; argv[7] = iface_name; argv[8] = NULL; } @@ -59,9 +61,10 @@ void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) { gboolean ret; GError *error = NULL; char *argv[20]; + gchar pid_file[256]; /* Preparar los argumentos */ - interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name); + interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file)); if (g_spawn_check_exit_status (status, NULL)) { /* Revisar si necesito algo */ @@ -108,6 +111,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type gboolean ret; GError *error = NULL; char *argv[20]; + gchar pid_file[256]; iface = _interfaces_locate_by_index (handle->interfaces, index); @@ -118,7 +122,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type } /* Preparar los argumentos */ - interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name); + interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name, pid_file, sizeof (pid_file)); if (iface->dhcpc.type != IFACE_NO_DHCP) { /* No puedo correr otro tipo de DHCP */ @@ -191,8 +195,9 @@ void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) { } } -void interfaces_dhcp_client_internal_set_status (NetworkInadorHandle *handle, int index, int status) { +void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *handle, int index, int status, struct_addr *ip, int prefix, struct_addr *gateway, struct_addr *broadcast, struct_addr *dhcp_server, uint32_t lease_time, struct_addr *dns_list, int dns_count, char *domain_name) { Interface *iface; + struct in_addr empty_v4; iface = _interfaces_locate_by_index (handle->interfaces, index); @@ -211,10 +216,45 @@ void interfaces_dhcp_client_internal_set_status (NetworkInadorHandle *handle, in if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return; switch (status) { - case NET_INADOR_DHCP_STATUS_INITING: - iface->dhcpc.dhcp_state = DHCP_CLIENT_INITING; + case NET_INADOR_DHCP_STATUS_SELECTING: + iface->dhcpc.dhcp_state = DHCP_CLIENT_SELECTING; + break; + case NET_INADOR_DHCP_STATUS_BOUND: + iface->dhcpc.dhcp_state = DHCP_CLIENT_BOUND; + break; + case NET_INADOR_DHCP_STATUS_RENEWED: + iface->dhcpc.dhcp_state = DHCP_CLIENT_RENEWED; + break; + case NET_INADOR_DHCP_STATUS_EXPIRED: + iface->dhcpc.dhcp_state = DHCP_CLIENT_EXPIRED; + /* Borrar la IP anterior, si es que está puesta */ + break; + case NET_INADOR_DHCP_STATUS_FAILED: + iface->dhcpc.dhcp_state = DHCP_CLIENT_FAILED; break; } } + + printf ("----> DHCP status: %i\n", iface->dhcpc.dhcp_state); + + if (status == NET_INADOR_DHCP_STATUS_BOUND || status == NET_INADOR_DHCP_STATUS_RENEWED) { + /* Copiar las variables de estado */ + memset (&empty_v4, 0, sizeof (empty_v4)); + + memcpy (&iface->dhcpc.ip, ip, sizeof (iface->dhcpc.ip)); + iface->dhcpc.prefix = prefix; + + memcpy (&iface->dhcpc.gateway, gateway, sizeof (iface->dhcpc.gateway)); + + memcpy (&iface->dhcpc.broadcast, broadcast, sizeof (iface->dhcpc.broadcast)); + memcpy (&iface->dhcpc.dhcp_server_ip, dhcp_server, sizeof (iface->dhcpc.dhcp_server_ip)); + char buf_a[256], buf_b[256], buf_c[256], buf_d[256]; + + inet_ntop (AF_INET, &iface->dhcpc.ip, buf_a, sizeof (buf_a)); + inet_ntop (AF_INET, &iface->dhcpc.gateway, buf_b, sizeof (buf_b)); + inet_ntop (AF_INET, &iface->dhcpc.broadcast, buf_c, sizeof (buf_c)); + inet_ntop (AF_INET, &iface->dhcpc.dhcp_server_ip, buf_d, sizeof (buf_d)); + printf ("----> DHCP Server (%s), IP obtenida: %s/%i, GW: %s y bcast: %s, lease: %i\n", buf_d, buf_a, prefix, buf_b, buf_c, lease_time); + } } diff --git a/src/dhcp_client.h b/src/dhcp_client.h index fee0318..388570b 100644 --- a/src/dhcp_client.h +++ b/src/dhcp_client.h @@ -27,7 +27,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type, uint32_t flags); void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index); -void interfaces_dhcp_client_internal_set_status (NetworkInadorHandle *handle, int index, int status); +void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *handle, int index, int status, struct_addr *ip, int prefix, struct_addr *gateway, struct_addr *broadcast, struct_addr *dhcp_server, uint32_t lease_time, struct_addr *dns_list, int dns_count, char *domain_name); #endif /* __DHCP_CLIENT_H__ */ diff --git a/src/manager.c b/src/manager.c index aa19436..cf8d162 100644 --- a/src/manager.c +++ b/src/manager.c @@ -659,52 +659,149 @@ static void _manager_handle_set_event_mask (ManagerClientInfo *manager_client, u manager_client->wanted_events = events; } -static void _manager_execute_dhcp_set_status (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { - int name_len; +#define _MANAGER_CHECK_BYTE_OR_OUT(FAMILY,BUF,POS) \ + if (BUF[POS] != 0) { \ + if (FAMILY == AF_INET && BUF[POS] != 4) { \ + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); \ + return; \ + } \ + } + +static void _manager_execute_dhcp_client_feed (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { + int name_len, wanted; unsigned char name[IFNAMSIZ]; + unsigned char domain_name[256]; Interface *iface; + int family; + int pos, prefix, g; + uint32_t lease_time; + struct_addr ip, gateway, broadcast, dhcp_server; + struct_addr dns[8]; - if (buffer_len < 4) { - _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_SET_STATUS); + if (buffer_len < 16) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } - name_len = buffer[3]; + /* Revisar la familia */ + family = buffer[2]; + + if (family != AF_INET && family != AF_INET6) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); + + return; + } + + /* Revisar el estado */ + if (buffer[3] < DHCP_CLIENT_SELECTING || buffer[3] > DHCP_CLIENT_EXPIRED) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); + return; + } + + /* Revisar la longitud del nombre de la interfaz */ + name_len = buffer[4]; if (name_len == 0 || name_len >= IFNAMSIZ) { - _manager_send_error (manager_client, NET_INADOR_ERROR_BAD_STRING, NET_INADOR_COMMAND_DHCP_SET_STATUS); + _manager_send_error (manager_client, NET_INADOR_ERROR_BAD_STRING, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } - if (name_len + 4 < buffer_len) { - _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_SET_STATUS); + _MANAGER_CHECK_BYTE_OR_OUT(family, buffer, 5); // Dirección IP + _MANAGER_CHECK_BYTE_OR_OUT(family, buffer, 7); // Ruta por defecto + _MANAGER_CHECK_BYTE_OR_OUT(family, buffer, 8); // Dirección Broadcast + _MANAGER_CHECK_BYTE_OR_OUT(family, buffer, 9); // Dirección del servidor + + /* La lista de servidores DNS */ + if (family == AF_INET && buffer[10] % 4 != 0) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } - if (buffer[2] < NET_INADOR_DHCP_STATUS_INITING || buffer[2] > NET_INADOR_DHCP_STATUS_RENEWING) { - _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_SET_STATUS); + wanted = 16 + name_len + buffer[5] + buffer[7] + buffer[8] + buffer[9] + buffer[10] + buffer[11]; + if (wanted < buffer_len) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } - memcpy (name, &buffer[4], name_len); + /* Recuperar el nombre de la interfaz */ + memcpy (name, &buffer[16], name_len); name[name_len] = 0; iface = _interfaces_locate_by_name (manager_client->manager->handle->interfaces, name); if (iface == NULL) { - _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_IFACE_INDEX, NET_INADOR_COMMAND_DHCP_SET_STATUS); + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_IFACE_INDEX, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } if (iface->dhcpc.type != IFACE_ISC_DHCLIENT) { - _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_DHCP_SET_STATUS); + _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) { - _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_DHCP_SET_STATUS); + _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); return; } - interfaces_dhcp_client_internal_set_status (manager_client->manager->handle, iface->index, buffer[2]); + /* Recuperar el resto de valores, empezando por la IP */ + if (buffer[5] != 0) { + pos = 16 + name_len; + memcpy (&ip, &buffer[pos], buffer[5]); + } else { + memset (&ip, 0, sizeof (ip)); + } + + /* Recuperar la ruta por defecto */ + if (buffer[7] != 0) { + pos = 16 + name_len + buffer[5]; + memcpy (&gateway, &buffer[pos], buffer[7]); + } else { + memset (&gateway, 0, sizeof (gateway)); + } + + /* Recuperar el broadcast */ + if (buffer[8] != 0) { + pos = 16 + name_len + buffer[5] + buffer[7]; + memcpy (&broadcast, &buffer[pos], buffer[8]); + } else { + memset (&broadcast, 0, sizeof (broadcast)); + } + + /* Recuperar el servidor DHCP */ + if (buffer[9] != 0) { + pos = 16 + name_len + buffer[5] + buffer[7] + buffer[8]; + memcpy (&dhcp_server, &buffer[pos], buffer[9]); + } else { + memset (&dhcp_server, 0, sizeof (dhcp_server)); + } + + /* Recuperar todos los servidores DNS */ + g = 0; + while (g < 8 && g < (buffer[10] / 4)) { + memcpy (&dns[g].v4, &buffer[pos], 4); + pos += 4; + g++; + } + + /* Recuperar el domain name */ + domain_name[0] = 0; + if (buffer[11] != 0) { + pos = 16 + name_len + buffer[5] + buffer[7] + buffer[8] + buffer[9] + buffer[10]; + memcpy (domain_name, &buffer[pos], buffer[11]); + domain_name[buffer[11]] = 0; + } + + /* Copiar el lease_time */ + memcpy (&lease_time, &buffer[12], 4); + + /* TODO: Ejecutar aquí validaciones de estado, revisar que la IP existe, que el prefix sea válido, bla, bla, bla */ + if (family == AF_INET) { + prefix = buffer[6]; + if (prefix > 32) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_CLIENT_FEED); + return; + } + } + interfaces_dhcp_client_internal_feed_from_client (manager_client->manager->handle, iface->index, buffer[3], &ip, buffer[6], &gateway, &broadcast, &dhcp_server, lease_time, dns, (buffer[10] / 4), domain_name); /* OK */ _manager_send_executed (manager_client); @@ -796,8 +893,8 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition case NET_INADOR_COMMAND_SET_MASTER: _manager_execute_set_or_clear_master (manager_client, buffer, bytes, FALSE); break; - case NET_INADOR_COMMAND_DHCP_SET_STATUS: - _manager_execute_dhcp_set_status (manager_client, buffer, bytes); + case NET_INADOR_COMMAND_DHCP_CLIENT_FEED: + _manager_execute_dhcp_client_feed (manager_client, buffer, bytes); break; default: _manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command); diff --git a/src/network-inador-manager.h b/src/network-inador-manager.h index d2fa8c2..ec89a12 100644 --- a/src/network-inador-manager.h +++ b/src/network-inador-manager.h @@ -37,7 +37,7 @@ enum { NET_INADOR_COMMAND_SET_EVENT_MASK = 192, /* Los siguientes comandos son para uso interno */ - NET_INADOR_COMMAND_DHCP_SET_STATUS = 224, + NET_INADOR_COMMAND_DHCP_CLIENT_FEED = 224, }; enum { @@ -67,11 +67,13 @@ enum { }; enum { - NET_INADOR_DHCP_STATUS_INITING = 1, - NET_INADOR_DHCP_STATUS_SELECTING, - NET_INADOR_DHCP_STATUS_REQUESTING, + NET_INADOR_DHCP_STATUS_SELECTING = 1, NET_INADOR_DHCP_STATUS_BOUND, - NET_INADOR_DHCP_STATUS_RENEWING + NET_INADOR_DHCP_STATUS_RENEWED, + + NET_INADOR_DHCP_STATUS_EXPIRED, + NET_INADOR_DHCP_STATUS_FAILED, + }; #endif /* __NETWOR_INADOR_MANAGER_H__ */ diff --git a/src/ni-dhcp-iface-helper.c b/src/ni-dhcp-iface-helper.c new file mode 100644 index 0000000..d57d566 --- /dev/null +++ b/src/ni-dhcp-iface-helper.c @@ -0,0 +1,380 @@ +/* + * ni-iface-helper.c + * This file is part of Network Inador + * + * Copyright (C) 2021 - 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 "network-inador-manager.h" + +#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket" + +extern char** environ; + +int debug (int argc, char *argv[]) { + char **item; + int fd; + + fd = open ("/tmp/var_dhcp.env", O_CREAT | O_WRONLY | O_TRUNC, 0644); + + if (fd < 0) { + return -1; + } + + for (item = environ; *item; item++) { + char *name, *val, **p; + + /* Split on the = */ + name = strdup (*item); + val = strchr (name, '='); + if (!val || val == name) { + free (name); + continue; + } + *val++ = '\0'; + + /* Ignore non-DCHP-related environment variables + for (p = (char **) ignore; *p; p++) { + if (strncmp (name, *p, strlen (*p)) == 0) + goto next; + }*/ + + write (fd, "Name: <", 7); + write (fd, name, strlen (name)); + write (fd, ">, Value: <", 11); + write (fd, val, strlen (val)); + write (fd, ">\n", 2); + } + + close (fd); + + return 0; +} + +uint32_t utils_ip4_netmask_to_prefix (uint32_t netmask) { + uint32_t prefix; + uint8_t v; + const uint8_t *p = (uint8_t *) &netmask; + + if (p[3]) { + prefix = 24; + v = p[3]; + } else if (p[2]) { + prefix = 16; + v = p[2]; + } else if (p[1]) { + prefix = 8; + v = p[1]; + } else { + prefix = 0; + v = p[0]; + } + + while (v) { + prefix++; + v <<= 1; + } + + return prefix; +} + +char *retrieve_env (const char *name) { + char *bus, *dup, *get; + + get = getenv (name); + + if (get == NULL) { + return NULL; + } + + bus = strchr (get, '='); + + if (!bus || bus == get) { + return NULL; + } + + dup = strdup (&get[1]); + + if (dup == NULL) { + return NULL; + } + + return dup; +} + +int wait_for_ack_or_error (int s) { + unsigned char buffer[128]; + int ret; + + ret = recv (s, buffer, sizeof (buffer), 0); + + if (ret < 3) { + return -1; + } + + if (buffer[0] == NET_INADOR_TYPE_RESPONSE_ERROR) { + return -1; + } + + if (buffer[0] == NET_INADOR_TYPE_RESPONSE && buffer[1] == NET_INADOR_RESPONSE_EXECUTED) { + return 0; + } + + return -1; +} + +void send_preinit (int s, char *interface) { + unsigned char buffer[128]; + + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_DHCP_CLIENT_FEED; + + buffer[2] = AF_INET; + buffer[3] = NET_INADOR_DHCP_STATUS_SELECTING; + buffer[4] = strlen (interface); + memset (&buffer[5], 0, 11); + + strncpy (&buffer[16], interface, buffer[4]); + + send (s, buffer, 16 + buffer[4], 0); + + if (wait_for_ack_or_error (s) < 0) { + return; + } +} + +void send_bound_renew (int s, int is_bound, char *interface, struct in_addr *ip, int prefix, struct in_addr *gateway, struct in_addr *broadcast, struct in_addr *dhcp_server, uint32_t lease_time) { + unsigned char buffer[128]; + struct in_addr empty; + int pos; + + memset (&empty, 0, sizeof (empty)); + + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_DHCP_CLIENT_FEED; + + buffer[2] = AF_INET; + if (is_bound) { + buffer[3] = NET_INADOR_DHCP_STATUS_BOUND; + } else { + buffer[3] = NET_INADOR_DHCP_STATUS_RENEWED; + } + buffer[4] = strlen (interface); + memset (&buffer[5], 0, 11); + + buffer[6] = prefix; + + pos = 16; + + /* Copiar el nombre de la interfaz */ + strncpy (&buffer[16], interface, buffer[4]); + pos = 16 + buffer[4]; + + if (memcmp (&empty, ip, sizeof (empty)) != 0) { + /* Tenemos una IP */ + buffer[5] = 4; + memcpy (&buffer[pos], ip, 4); + pos += 4; + } + + if (memcmp (&empty, gateway, sizeof (empty)) != 0) { + /* Tenemos una ruta */ + buffer[7] = 4; + memcpy (&buffer[pos], gateway, 4); + pos += 4; + } + + if (memcmp (&empty, broadcast, sizeof (empty)) != 0) { + /* Tenemos broadcast */ + buffer[8] = 4; + memcpy (&buffer[pos], broadcast, 4); + pos += 4; + } + + if (memcmp (&empty, dhcp_server, sizeof (empty)) != 0) { + /* Tenemos IP del servidor DHCP */ + buffer[9] = 4; + memcpy (&buffer[pos], dhcp_server, 4); + pos += 4; + } + + if (lease_time != 0) { + memcpy (&buffer[12], &lease_time, 4); + } + + /* TODO: Faltan los DNS */ + send (s, buffer, pos, 0); + + if (wait_for_ack_or_error (s) < 0) { + return; + } +} + +int parse_ip (char *var, struct in_addr *addr) { + int res; + + if (var == NULL) { + return -1; + } + + res = inet_pton (AF_INET, var, addr); + + if (res <= 0) { + memset (addr, 0, sizeof (*addr)); + + return -1; + } + + return 0; +} + +int parse_int (char *var, int *entero) { + int res; + + if (var == NULL) { + return -1; + } + + res = sscanf (var, "%i", entero); + + if (res <= 0) { + *entero = 0; + + return -1; + } + + return 0; +} + +int main (int argc, char *argv[]) { + char *reason, *interface; + int s, ret; + struct sockaddr_un path_dest; + struct in_addr ip, netmask, gateway, broadcast, dhcp_server; + int prefix, lease_time; + + debug (argc, argv); + + reason = getenv ("reason"); + + interface = getenv ("interface"); + + if (reason == NULL || interface == NULL) { + return 1; + } + + /* Intentar abrir el socket a la escucha */ + s = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + + if (s < 0) { + return 1; + } + + path_dest.sun_family = AF_UNIX; + strncpy (path_dest.sun_path, COMMAND_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 1; + } + + if (strcmp (reason, "PREINIT") == 0) { + send_preinit (s, interface); + } if (strcmp (reason, "FAIL") == 0) { + + } else if (strcmp (reason, "BOUND") == 0 || strcmp (reason, "REBOOT") == 0 || + strcmp (reason, "RENEW") == 0 || strcmp (reason, "REBIND") == 0 + ) { + /* + * Los valores más importantes recibidos: + * new_domain_name_servers -> los DNS + * new_expiry -> el timestamp de la hora + * new_domain_name -> DNS search name + * new_routers -> Lista de routers + * new_subnet_mask -> Máscara de red en formato largo + * new_broadcast_address -> Dirección broadcast + * new_ip_address -> Dirección IP + * new_dhcp_lease_time -> Tiempo en segundos + */ + /* Parsear y revisar las direcciones IP recibidas */ + char *s_ip, *s_mask, *s_gateway, *s_broadcast, *s_lease_time, *s_dhcp_server; + s_ip = getenv ("new_ip_address"); + s_mask = getenv ("new_subnet_mask"); + s_gateway = getenv ("new_routers"); + s_broadcast = getenv ("new_broadcast_address"); + s_lease_time = getenv ("new_dhcp_lease_time"); + s_dhcp_server = getenv ("new_dhcp_server_identifier"); + /* TODO: Faltan los DNS */ + + if (parse_ip (s_ip, &ip) < 0) { + close (s); + return -1; + } + + if (parse_ip (s_mask, &netmask) < 0) { + close (s); + return -1; + } + + prefix = utils_ip4_netmask_to_prefix (netmask.s_addr); + if (parse_ip (s_gateway, &gateway) < 0) { + memset (&gateway, 0, sizeof (gateway)); + } + + if (parse_ip (s_broadcast, &broadcast) < 0) { + memset (&broadcast, 0, sizeof (broadcast)); + } + + if (parse_ip (s_dhcp_server, &dhcp_server) < 0) { + memset (&dhcp_server, 0, sizeof (dhcp_server)); + } + + if (parse_int (s_lease_time, &lease_time) < 0) { + lease_time = 0; + } + + int is_bound = 0; + if (strcmp (reason, "BOUND") == 0 || strcmp (reason, "REBOOT") == 0) { + is_bound = 1; + } + send_bound_renew (s, is_bound, interface, &ip, prefix, &gateway, &broadcast, &dhcp_server, lease_time); + } else if (strcmp (reason, "EXPIRE") == 0 || strcmp (reason, "STOP") == 0 || strcmp (reason, "RELEASE") == 0) { + /* Los mismos valores, pero con old_ */ + } else { + + + } + close (s); + + return 0; +} diff --git a/src/ni-iface-helper.c b/src/ni-iface-helper.c deleted file mode 100644 index 5d824a9..0000000 --- a/src/ni-iface-helper.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * ni-iface-helper.c - * This file is part of Network Inador - * - * Copyright (C) 2021 - 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 "network-inador-manager.h" - -#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket" - -extern char** environ; - -int debug (int argc, char *argv[]) { - char **item; - int fd; - - fd = open ("/tmp/var_dhcp.env", O_CREAT | O_WRONLY | O_TRUNC, 0644); - - if (fd < 0) { - return -1; - } - - for (item = environ; *item; item++) { - char *name, *val, **p; - - /* Split on the = */ - name = strdup (*item); - val = strchr (name, '='); - if (!val || val == name) { - free (name); - continue; - } - *val++ = '\0'; - - /* Ignore non-DCHP-related environment variables - for (p = (char **) ignore; *p; p++) { - if (strncmp (name, *p, strlen (*p)) == 0) - goto next; - }*/ - - write (fd, "Name: <", 7); - write (fd, name, strlen (name)); - write (fd, ">, Value: <", 11); - write (fd, val, strlen (val)); - write (fd, ">\n", 2); - } - - close (fd); - - return 0; -} - -char *retrieve_env (const char *name) { - char *bus, *dup, *get; - - get = getenv (name); - - if (get == NULL) { - return NULL; - } - - bus = strchr (get, '='); - - if (!bus || bus == get) { - return NULL; - } - - dup = strdup (&get[1]); - - if (dup == NULL) { - return NULL; - } - - return dup; -} - -int wait_for_ack_or_error (int s) { - unsigned char buffer[128]; - int ret; - - ret = recv (s, buffer, sizeof (buffer), 0); - - if (ret < 3) { - return -1; - } - - if (buffer[0] == NET_INADOR_TYPE_RESPONSE_ERROR) { - return -1; - } - - if (buffer[0] == NET_INADOR_TYPE_RESPONSE && buffer[1] == NET_INADOR_RESPONSE_EXECUTED) { - return 0; - } - - return -1; -} - -void send_preinit (int s, char *interface) { - unsigned char buffer[128]; - - buffer[0] = NET_INADOR_TYPE_COMMAND; - buffer[1] = NET_INADOR_COMMAND_DHCP_SET_STATUS; - - buffer[2] = NET_INADOR_DHCP_STATUS_INITING; - buffer[3] = strlen (interface); - strncpy (&buffer[4], interface, buffer[3]); - - send (s, buffer, 3 + buffer[3], 0); - - if (wait_for_ack_or_error (s) < 0) { - close (s); - return; - } - - close (s); -} - -int main (int argc, char *argv[]) { - char *reason, *interface; - int s, ret; - struct sockaddr_un path_dest; - - debug (argc, argv); - - reason = retrieve_env ("reason"); - - interface = retrieve_env ("interface"); - - if (reason == NULL || interface == NULL) { - return 1; - } - - /* Intentar abrir el socket a la escucha */ - s = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); - - if (s < 0) { - return 1; - } - - path_dest.sun_family = AF_UNIX; - strncpy (path_dest.sun_path, COMMAND_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 1; - } - - if (strcmp (reason, "PREINIT") == 0 || strcmp (reason, "FAIL") == 0) { - send_preinit (s, interface); - - return 0; - } else if (strcmp (reason, "REBOOT") == 0 || strcmp (reason, "RENEW") == 0) { - /* - * Los valores más importantes recibidos: - * new_domain_name_servers -> los DNS - * new_expiry -> el timestamp de la hora - * new_domain_name -> DNS search name - * new_routers -> Lista de routers - * new_subnet_mask -> Máscara de red en formato largo - * new_broadcast_address -> Dirección broadcast - * new_ip_address -> Dirección IP - * new_dhcp_lease_time -> Tiempo en segundos - */ - } else if (strcmp (reason, "EXPIRE") == 0) { - /* Los mismos valores, pero con old_ */ - } else { - - - close (s); - } - - return 0; -}