/* * dhcp_client.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 "interfaces.h" #include "common.h" #include "dhcp_client.h" #include "network-inador-manager.h" 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]; 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"; argv[2] = "-q"; argv[3] = "-pf"; argv[4] = pid_file; argv[5] = "-sf"; argv[6] = "/home/gatuno/Proyectos/NetworkInador/src/ni-iface-helper"; argv[7] = iface_name; argv[8] = NULL; } void interfaces_dhcp_client_killed_cb (GPid pid, gint status, gpointer data) { Interface *iface = (Interface *) data; gboolean ret; GError *error = NULL; char *argv[20]; /* Preparar los argumentos */ interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name); if (g_spawn_check_exit_status (status, NULL)) { /* Revisar si necesito algo */ } if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) { if (iface->dhcpc.flags & DHCP_CLIENT_FLAG_AUTO_RESTART) { /* Se cerró o mataron el proceso, reiniciar */ ret = g_spawn_async_with_pipes ( "/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &iface->dhcpc.process_pid, NULL, NULL, NULL, &error); if (ret == FALSE) { printf ("Error dhcp: %s\n", error->message); g_error_free (error); error = NULL; iface->dhcpc.flags = DHCP_CLIENT_KILLED; iface->dhcpc.process_watch = 0; } else { iface->dhcpc.dhcp_state = DHCP_CLIENT_EXTERNAL_RUNNING; iface->dhcpc.process_watch = g_child_watch_add (iface->dhcpc.process_pid, interfaces_dhcp_client_killed_cb, iface); } } else { /* En caso contrario, solo dejar la muerte escrita */ iface->dhcpc.flags = DHCP_CLIENT_KILLED; iface->dhcpc.process_watch = 0; } } } int interfaces_dhcp_client_run (NetworkInadorHandle *handle, int index, int type, uint32_t flags) { /* IFNAMSIZ */ Interface *iface; gboolean ret; GError *error = NULL; char *argv[20]; iface = _interfaces_locate_by_index (handle->interfaces, index); if (iface == NULL) { printf ("Error, solicitaron operación sobre interfaz que no existe\n"); return -1; } /* Preparar los argumentos */ interfaces_dhcp_prepare_args_for_dhclient (argv, 20, iface->name); if (iface->dhcpc.type != IFACE_NO_DHCP) { /* No puedo correr otro tipo de DHCP */ return -1; } if (iface->dhcpc.type == IFACE_ISC_DHCLIENT && iface->dhcpc.dhcp_state != DHCP_CLIENT_KILLED) { /* El cliente de dhcp ya está corriendo, no hacer nada */ return -1; } ret = g_spawn_async_with_pipes ( "/", argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &iface->dhcpc.process_pid, NULL, NULL, NULL, &error); if (ret == FALSE) { printf ("Error dhcp: %s\n", error->message); g_error_free (error); error = NULL; return -1; } iface->dhcpc.dhcp_state = DHCP_CLIENT_EXTERNAL_RUNNING; iface->dhcpc.type = IFACE_ISC_DHCLIENT; iface->dhcpc.flags = flags; iface->dhcpc.process_watch = g_child_watch_add (iface->dhcpc.process_pid, interfaces_dhcp_client_killed_cb, iface); return 0; } void interfaces_dhcp_client_stop (NetworkInadorHandle *handle, int index) { Interface *iface; iface = _interfaces_locate_by_index (handle->interfaces, index); if (iface == NULL) { printf ("Error, solicitaron operación sobre interfaz que no existe\n"); return; } if (iface->dhcpc.type == IFACE_NO_DHCP) { return; } if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) { if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return; /* Proceso, matar y reiniciar estado */ iface->dhcpc.type = IFACE_NO_DHCP; iface->dhcpc.flags &= (~DHCP_CLIENT_FLAG_AUTO_RESTART); g_source_remove (iface->dhcpc.process_watch); iface->dhcpc.process_watch = 0; g_child_watch_add (iface->dhcpc.process_pid, interfaces_dhcp_client_ignore_kill, NULL); kill (iface->dhcpc.process_pid, SIGTERM); } } void interfaces_dhcp_client_internal_set_status (NetworkInadorHandle *handle, int index, int status) { Interface *iface; iface = _interfaces_locate_by_index (handle->interfaces, index); if (iface == NULL) { printf ("Error, solicitaron operación sobre interfaz que no existe\n"); return; } if (iface->dhcpc.type == IFACE_NO_DHCP) { return; } if (iface->dhcpc.type == IFACE_ISC_DHCLIENT) { /* Un proceso muerto no puede informar de cambios de estados */ if (iface->dhcpc.dhcp_state == DHCP_CLIENT_KILLED) return; switch (status) { case NET_INADOR_DHCP_STATUS_INITING: iface->dhcpc.dhcp_state = DHCP_CLIENT_INITING; break; } } }