221 lines
5.6 KiB
C
221 lines
5.6 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
|
|
#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;
|
|
}
|
|
}
|
|
}
|
|
|