Agrego comandos que alimentan la información del cliente DHCP

master
Félix Arreola Rodríguez 2022-01-01 18:32:59 -06:00
parent bf315b5b03
commit f048dde998
9 changed files with 569 additions and 244 deletions

2
.gitignore vendored
View File

@ -48,4 +48,4 @@ client-gtk/ni-marshal.c
client-gtk/ni-marshal.h client-gtk/ni-marshal.h
client-gtk/core client-gtk/core
src/ni-iface-helper src/ni-dhcp-helper

View File

@ -12,11 +12,11 @@ network_inador_SOURCES = main.c \
wireless_if.c wireless_if.h \ wireless_if.c wireless_if.h \
wireless_bss.c wireless_bss.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_dhcp_helper_SOURCES = ni-dhcp-iface-helper.c
ni_iface_helper_CPPFLAGS = $(AM_CPPFLAGS) ni_dhcp_helper_CPPFLAGS = $(AM_CPPFLAGS)
ni_iface_helper_CFLAGS = $(AM_CFLAGS) ni_dhcp_helper_CFLAGS = $(AM_CFLAGS)
#network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) #network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)

View File

@ -120,13 +120,14 @@ enum {
IFACE_ISC_DHCLIENT IFACE_ISC_DHCLIENT
}; };
/* FIXME: Revisar estos estados */
enum { enum {
DHCP_CLIENT_INITING,
DHCP_CLIENT_SELECTING, DHCP_CLIENT_SELECTING,
DHCP_CLIENT_REQUESTING,
DHCP_CLIENT_BOUND, DHCP_CLIENT_BOUND,
DHCP_CLIENT_RENEWING, DHCP_CLIENT_RENEWED,
DHCP_CLIENT_EXPIRED,
DHCP_CLIENT_FAILED,
DHCP_CLIENT_KILLED, DHCP_CLIENT_KILLED,
DHCP_CLIENT_EXTERNAL_RUNNING DHCP_CLIENT_EXTERNAL_RUNNING
@ -143,6 +144,14 @@ typedef struct _InterfaceDHCPClientInfo {
/* Para vigilar el proceso */ /* Para vigilar el proceso */
GPid process_pid; GPid process_pid;
guint process_watch; 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; } InterfaceDHCPClientInfo;
struct _Interface { struct _Interface {

View File

@ -26,6 +26,9 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h> #include <signal.h>
#include "interfaces.h" #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); g_spawn_check_exit_status (status, NULL);
} }
void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *iface_name) { void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *iface_name, char *pid_file, size_t pid_file_len) {
gchar pid_file[256]; 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 */ /* Preparar los argumentos para el proceso */
argv[0] = "/sbin/dhclient"; argv[0] = "/sbin/dhclient";
argv[1] = "-d"; argv[1] = "-d";
@ -49,7 +51,7 @@ void interfaces_dhcp_prepare_args_for_dhclient (char **argv, int size, char *ifa
argv[3] = "-pf"; argv[3] = "-pf";
argv[4] = pid_file; argv[4] = pid_file;
argv[5] = "-sf"; 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[7] = iface_name;
argv[8] = NULL; argv[8] = NULL;
} }
@ -59,9 +61,10 @@ void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) {
gboolean ret; gboolean ret;
GError *error = NULL; GError *error = NULL;
char *argv[20]; char *argv[20];
gchar pid_file[256];
/* Preparar los argumentos */ /* 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)) { if (g_spawn_check_exit_status (status, NULL)) {
/* Revisar si necesito algo */ /* Revisar si necesito algo */
@ -108,6 +111,7 @@ int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type
gboolean ret; gboolean ret;
GError *error = NULL; GError *error = NULL;
char *argv[20]; char *argv[20];
gchar pid_file[256];
iface = _interfaces_locate_by_index (handle->interfaces, index); 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 */ /* 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) { if (iface->dhcpc.type != IFACE_NO_DHCP) {
/* No puedo correr otro tipo de 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; Interface *iface;
struct in_addr empty_v4;
iface = _interfaces_locate_by_index (handle->interfaces, index); 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; if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return;
switch (status) { switch (status) {
case NET_INADOR_DHCP_STATUS_INITING: case NET_INADOR_DHCP_STATUS_SELECTING:
iface->dhcpc.dhcp_state = DHCP_CLIENT_INITING; 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; 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);
}
} }

View File

@ -27,7 +27,7 @@
int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type, uint32_t flags); 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_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__ */ #endif /* __DHCP_CLIENT_H__ */

View File

@ -659,52 +659,149 @@ static void _manager_handle_set_event_mask (ManagerClientInfo *manager_client, u
manager_client->wanted_events = events; manager_client->wanted_events = events;
} }
static void _manager_execute_dhcp_set_status (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { #define _MANAGER_CHECK_BYTE_OR_OUT(FAMILY,BUF,POS) \
int name_len; 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 name[IFNAMSIZ];
unsigned char domain_name[256];
Interface *iface; 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) { if (buffer_len < 16) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_SET_STATUS); _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_CLIENT_FEED);
return; 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) { 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; return;
} }
if (name_len + 4 < buffer_len) { _MANAGER_CHECK_BYTE_OR_OUT(family, buffer, 5); // Dirección IP
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_SET_STATUS); _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; return;
} }
if (buffer[2] < NET_INADOR_DHCP_STATUS_INITING || buffer[2] > NET_INADOR_DHCP_STATUS_RENEWING) { wanted = 16 + name_len + buffer[5] + buffer[7] + buffer[8] + buffer[9] + buffer[10] + buffer[11];
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_DHCP_SET_STATUS); if (wanted < buffer_len) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_DHCP_CLIENT_FEED);
return; return;
} }
memcpy (name, &buffer[4], name_len); /* Recuperar el nombre de la interfaz */
memcpy (name, &buffer[16], name_len);
name[name_len] = 0; name[name_len] = 0;
iface = _interfaces_locate_by_name (manager_client->manager->handle->interfaces, name); iface = _interfaces_locate_by_name (manager_client->manager->handle->interfaces, name);
if (iface == NULL) { 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; return;
} }
if (iface->dhcpc.type != IFACE_ISC_DHCLIENT) { 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; return;
} }
if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) { 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; 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 */ /* OK */
_manager_send_executed (manager_client); _manager_send_executed (manager_client);
@ -796,8 +893,8 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition
case NET_INADOR_COMMAND_SET_MASTER: case NET_INADOR_COMMAND_SET_MASTER:
_manager_execute_set_or_clear_master (manager_client, buffer, bytes, FALSE); _manager_execute_set_or_clear_master (manager_client, buffer, bytes, FALSE);
break; break;
case NET_INADOR_COMMAND_DHCP_SET_STATUS: case NET_INADOR_COMMAND_DHCP_CLIENT_FEED:
_manager_execute_dhcp_set_status (manager_client, buffer, bytes); _manager_execute_dhcp_client_feed (manager_client, buffer, bytes);
break; break;
default: default:
_manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command); _manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command);

View File

@ -37,7 +37,7 @@ enum {
NET_INADOR_COMMAND_SET_EVENT_MASK = 192, NET_INADOR_COMMAND_SET_EVENT_MASK = 192,
/* Los siguientes comandos son para uso interno */ /* Los siguientes comandos son para uso interno */
NET_INADOR_COMMAND_DHCP_SET_STATUS = 224, NET_INADOR_COMMAND_DHCP_CLIENT_FEED = 224,
}; };
enum { enum {
@ -67,11 +67,13 @@ enum {
}; };
enum { enum {
NET_INADOR_DHCP_STATUS_INITING = 1, NET_INADOR_DHCP_STATUS_SELECTING = 1,
NET_INADOR_DHCP_STATUS_SELECTING,
NET_INADOR_DHCP_STATUS_REQUESTING,
NET_INADOR_DHCP_STATUS_BOUND, 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__ */ #endif /* __NETWOR_INADOR_MANAGER_H__ */

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#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;
}

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#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;
}