Agrego primeras pruebas para procesar el resolv.conf

master
Félix Arreola Rodríguez 2023-07-21 22:58:05 -06:00
parent 4660add5ad
commit 95d4826615
19 changed files with 2502 additions and 7 deletions

1
.gitignore vendored
View File

@ -49,3 +49,4 @@ client-gtk/ni-marshal.h
client-gtk/core
src/ni-dhcp-helper
src/resolvconf

View File

@ -3,6 +3,7 @@
bin_PROGRAMS = network-inador
network_inador_SOURCES = main.c \
common.h link-types.h \
struct_addr_union.h resolv_conf_defs.h \
netlink-events.c netlink-events.h \
interfaces.c interfaces.h \
ip-address.c ip-address.h \
@ -10,8 +11,19 @@ network_inador_SOURCES = main.c \
manager.c manager.h \
dhcp_client.c dhcp_client.h \
routes.c routes.h \
resolv_manager.c resolv_manager.h \
resolv_conf_parser.c resolv_conf_parser.h \
wireless_if.c wireless_if.h \
wireless_bss.c wireless_bss.h
wireless_bss.c wireless_bss.h \
utils.c utils.h
sbin_PROGRAMS = resolvconf
resolvconf_SOURCES = resolv_conf_helper.c \
struct_addr_union.h resolv_conf_defs.h \
resolv_conf_parser.c resolv_conf_parser.h \
utils.c utils.h \
glist.c glist.h
resolvconf_CFLAGS = -DSTAND_ALONE_RESOLV_CONF_HELPER_BUILD
libexec_PROGRAMS = ni-dhcp-helper

View File

@ -29,10 +29,15 @@
#include <netinet/in.h>
#include <net/ethernet.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <glib.h>
#include <gmodule.h>
#include "struct_addr_union.h"
#include "resolv_conf_defs.h"
#ifndef FALSE
#define FALSE 0
#endif
@ -53,11 +58,6 @@ typedef struct _NetworkInadorHandle NetworkInadorHandle;
typedef struct _NetworkInadorManager NetworkInadorManager;
typedef struct _Interface Interface;
typedef union {
struct in_addr v4;
struct in6_addr v6;
} struct_addr;
typedef struct _IPAddr {
sa_family_t family;
@ -255,12 +255,19 @@ typedef struct _RouteTable {
int for_delete, was_new;
} RouteTable;
/* La definición principal que engloba todo */
struct _NetworkInadorHandle {
GList *interfaces;
GList *route_v4_tables;
GList *route_v6_tables;
GList *route_tables_names;
/* Entradas para el resolv conf */
GList *resolver_entries;
int resolver_inotify_fd;
int resolver_inotify_watch;
/* El manager */
NetworkInadorManager *manager;
/* Estos sockets ejecutan comandos */

View File

@ -257,6 +257,8 @@ void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *hand
Interface *iface;
struct in_addr empty_v4;
int g;
struct_addr old_dns[7];
int old_dns_c;
iface = _interfaces_locate_by_index (handle->interfaces, index);
@ -298,6 +300,13 @@ void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *hand
printf ("----> DHCP status: %i\n", iface->dhcpc.dhcp_state);
if (status == NET_INADOR_DHCP_STATUS_BOUND || status == NET_INADOR_DHCP_STATUS_RENEWED) {
/* Copiar la información de DNS para saber si hubo cambios */
old_dns_c = iface->dhcpc.dns_c;
if (old_dns_c != dns_count) {
/* Copiamos los dns viejos solo si la cantidad es diferente */
memcpy (old_dns, iface->dhcpc.dns, old_dns_c * (sizeof (iface->dhcpc.dns[0])));
}
/* Copiar las variables de estado */
memset (&empty_v4, 0, sizeof (empty_v4));
@ -318,8 +327,15 @@ void interfaces_dhcp_client_internal_feed_from_client (NetworkInadorHandle *hand
memcpy (&iface->dhcpc.dns[g], &dns_list[g], 4);
}
if (iface->dhcpc.dns_c != old_dns_c) {
/* TODO: Tenemos cambio en los DNS, actualizar el resolv.conf */
} else if (memcmp (iface->dhcpc.dns, old_dns, dns_count * (sizeof (iface->dhcpc.dns[0]))) != 0) {
/* TODO: Tenemos cambio en los DNS, actualizar el resolv.conf */
}
strncpy (iface->dhcpc.domain_name, domain_name, sizeof (iface->dhcpc.domain_name));
/* Esto solo es para impresión */
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));

1258
src/glist.c 100644

File diff suppressed because it is too large Load Diff

152
src/glist.h 100644
View File

@ -0,0 +1,152 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __G_LIST_H__
#define __G_LIST_H__
#define G_GNUC_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
typedef void * gpointer;
typedef const void * gconstpointer;
typedef void (*GDestroyNotify) (gpointer data);
typedef void (*GFunc) (gpointer data, gpointer user_data);
typedef int (*GCompareDataFunc) (gconstpointer a, gconstpointer b, gpointer user_data);
typedef int (*GCompareFunc) (gconstpointer a, gconstpointer b);
typedef gpointer (*GCopyFunc) (gconstpointer src, gpointer data);
typedef struct _GList GList;
struct _GList
{
gpointer data;
GList *next;
GList *prev;
};
/* Doubly linked lists
*/
GList* g_list_alloc (void) G_GNUC_WARN_UNUSED_RESULT;
void g_list_free (GList *list);
void g_list_free_1 (GList *list);
#define g_list_free1 g_list_free_1
void g_list_free_full (GList *list,
GDestroyNotify free_func);
GList* g_list_append (GList *list,
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_prepend (GList *list,
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_insert (GList *list,
gpointer data,
int position) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_insert_sorted (GList *list,
gpointer data,
GCompareFunc func) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_insert_sorted_with_data (GList *list,
gpointer data,
GCompareDataFunc func,
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_insert_before (GList *list,
GList *sibling,
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_concat (GList *list1,
GList *list2) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_remove (GList *list,
gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_remove_all (GList *list,
gconstpointer data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_remove_link (GList *list,
GList *llink) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_delete_link (GList *list,
GList *link_) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_reverse (GList *list) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_copy (GList *list) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_copy_deep (GList *list,
GCopyFunc func,
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_nth (GList *list,
unsigned int n);
GList* g_list_nth_prev (GList *list,
unsigned int n);
GList* g_list_find (GList *list,
gconstpointer data);
GList* g_list_find_custom (GList *list,
gconstpointer data,
GCompareFunc func);
int g_list_position (GList *list,
GList *llink);
int g_list_index (GList *list,
gconstpointer data);
GList* g_list_last (GList *list);
GList* g_list_first (GList *list);
unsigned int g_list_length (GList *list);
void g_list_foreach (GList *list,
GFunc func,
gpointer user_data);
GList* g_list_sort (GList *list,
GCompareFunc compare_func) G_GNUC_WARN_UNUSED_RESULT;
GList* g_list_sort_with_data (GList *list,
GCompareDataFunc compare_func,
gpointer user_data) G_GNUC_WARN_UNUSED_RESULT;
gpointer g_list_nth_data (GList *list,
unsigned int n);
#define g_list_previous(list) ((list) ? (((GList *)(list))->prev) : NULL)
#define g_list_next(list) ((list) ? (((GList *)(list))->next) : NULL)
#endif /* __G_LIST_H__ */

View File

@ -46,6 +46,7 @@
#include "bridge.h"
#include "dhcp_client.h"
#include "routes.h"
#include "resolv_manager.h"
/* Usados para salir en caso de una señal */
static int sigterm_pipe_fds[2] = { -1, -1 };
@ -148,6 +149,9 @@ int main (int argc, char *argv[]) {
/* Inicializar las rutas */
routes_init (&handle);
/* Inicializar el resolv.conf */
resolv_manager_init (&handle);
manager_init (&handle);
g_main_loop_run (loop);

View File

@ -46,6 +46,8 @@
#include "bridge.h"
#include "network-inador-manager.h"
#include "dhcp_client.h"
#include "struct_addr_union.h"
#include "resolv_manager.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
@ -818,6 +820,201 @@ static void _manager_execute_dhcp_client_feed (ManagerClientInfo *manager_client
_manager_send_executed (manager_client);
}
static void _manager_execute_resolvconf_feed (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
int name_len, wanted;
unsigned char iface_prog[256];
unsigned char iface_name[256], prog[256];
char value[2048];
char *point;
ResolvConfEntry *entry;
GList *pos_entry;
int ns_count;
int search_count;
int g, h, pos;
int family;
int order = 0;
struct_addr direccion;
int iface_index;
Interface *iface;
if (buffer_len < 3) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
name_len = buffer[2];
if (buffer_len < 3 + name_len || name_len == 0) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
memcpy (iface_prog, &buffer[3], name_len);
iface_prog[name_len] = 0;
if (iface_prog[0] == '.') {
/* No permitimos interfaces vacías */
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
point = strchr (iface_prog, '.');
if (point == NULL) {
prog[0] = 0;
strncpy (iface_name, iface_prog, sizeof (iface_name));
} else {
point[0] = 0;
strncpy (iface_name, iface_prog, sizeof (iface_name));
strncpy (prog, &point[1], sizeof (prog));
}
iface = _interfaces_locate_by_name (manager_client->manager->handle->interfaces, iface_name);
if (iface != NULL) {
iface_index = iface->index;
} else {
iface_index = 0;
}
pos = 3 + name_len;
if (buffer_len < pos) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
/* Revisar la cantidad de nameservers */
ns_count = buffer[pos];
pos++;
/* Los nameserver vienen con un byte de familia y luego los bytes correspondientes a la IP */
for (g = 0; g < ns_count; g++) {
/* Revisar que en la longitud venga el byte de la familia */
if (buffer_len < pos + 1) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
family = buffer[pos];
pos++; /* El byte de la familia */
if (family != AF_INET && family != AF_INET6) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
if (family == AF_INET) {
wanted = 4;
} else if (family == AF_INET6) {
wanted = 16;
}
if (buffer_len < pos + wanted) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_FEED);
return;
}
/* Tengo un Nameserver completo, buscar y dependiendo del caso, actualizar o crear */
memcpy (&direccion, &buffer[pos], wanted);
inet_ntop (family, &direccion, value, sizeof (value));
pos_entry = resolv_parser_search_entry (manager_client->manager->handle->resolver_entries, RESOLV_TYPE_NAMESERVER, family, &direccion, value);
if (pos_entry != NULL) {
/* De ser posible, hacer conciliación */
entry = (ResolvConfEntry *) pos_entry->data;
if (entry->origin == RESOLV_ORIGIN_FILE) {
/* Hacer esta entrada nuestra */
entry->origin = RESOLV_ORIGIN_RESOLVCONF;
entry->owner_interface_index = iface_index;
strncpy (entry->owner_prog, prog, sizeof (entry->owner_prog));
printf ("/// Asociando una entrada %s existente del archivo al: %s\n", entry->value, entry->owner_prog);
} else {
/* Existe la entrada, pero no la podemos tomar como nuestra, crear otra */
entry = NULL;
}
} else {
entry = NULL;
}
/* Si no existe, crearla */
if (entry == NULL) {
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
entry->origin = RESOLV_ORIGIN_RESOLVCONF;
entry->resolv_type = RESOLV_TYPE_NAMESERVER;
entry->file_order = 0;
entry->is_on_file = 0;
entry->priority = 0;
entry->ns_family = family;
memcpy (&entry->nameserver, &direccion, wanted);
strncpy (entry->value, value, sizeof (entry->value));
entry->owner_interface_index = iface_index;
strncpy (entry->owner_prog, prog, sizeof (entry->owner_prog));
/* Anexar al final de la lista */
manager_client->manager->handle->resolver_entries = g_list_append (manager_client->manager->handle->resolver_entries, entry);
/* TODO: Como creamos una entrada via el resolvconf, regenerar el archivo */
printf ("/// Nueva entrada %s via resolvconf, programando regeneración.\n", entry->value);
}
}
/* Ahora crear y parsear */
/* OK */
_manager_send_executed (manager_client);
}
static void _manager_execute_resolvconf_remove (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
int name_len;
unsigned char iface_prog[256];
unsigned char iface_name[256], prog[256];
char *point;
Interface *iface;
int iface_index;
name_len = buffer[2];
if (buffer_len < 3 + name_len || name_len == 0) {
_manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_RESOLVCONF_REMOVE);
return;
}
memcpy (iface_prog, &buffer[3], name_len);
iface_prog[name_len] = 0;
if (iface_prog[0] == '.') {
/* No permitimos interfaces vacías */
_manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_RESOLVCONF_REMOVE);
return;
}
point = strchr (iface_prog, '.');
if (point == NULL) {
prog[0] = 0;
strncpy (iface_name, iface_prog, sizeof (iface_name));
} else {
point[0] = 0;
strncpy (iface_name, iface_prog, sizeof (iface_name));
strncpy (prog, &point[1], sizeof (prog));
}
iface = _interfaces_locate_by_name (manager_client->manager->handle->interfaces, iface_name);
if (iface != NULL) {
iface_index = iface->index;
} else {
iface_index = 0;
}
resolv_manager_clear_entries_by_prog (manager_client->manager->handle, iface_index, prog);
_manager_send_executed (manager_client);
}
static void _manager_execute_dhcp_run (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) {
Interface *iface;
int ret;
@ -1493,6 +1690,12 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition
case NET_INADOR_COMMAND_LIST_ROUTE_TABLES:
_manager_send_list_route_tables (manager_client, buffer, bytes);
break;
case NET_INADOR_COMMAND_RESOLVCONF_FEED:
_manager_execute_resolvconf_feed (manager_client, buffer, bytes);
break;
case NET_INADOR_COMMAND_RESOLVCONF_REMOVE:
_manager_execute_resolvconf_remove (manager_client, buffer, bytes);
break;
default:
_manager_send_error (manager_client, NET_INADOR_ERROR_WRONG_COMMAND, command);
}

View File

@ -51,6 +51,8 @@ enum {
/* Los siguientes comandos son para uso interno */
NET_INADOR_COMMAND_DHCP_CLIENT_FEED = 224,
NET_INADOR_COMMAND_RESOLVCONF_FEED = 225,
NET_INADOR_COMMAND_RESOLVCONF_REMOVE = 226,
};
enum {

View File

@ -1,5 +1,5 @@
/*
* ni-iface-helper.c
* ni-dhcp-iface-helper.c
* This file is part of Network Inador
*
* Copyright (C) 2021 - Félix Arreola Rodríguez

View File

@ -0,0 +1,69 @@
/*
* resolv_conf_defs.h
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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.
*
* NetworkInador 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 NetworkInador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __RESOLV_CONF_DEFS_H__
#define __RESOLV_CONF_DEFS_H__
#include <linux/if.h>
#include "struct_addr_union.h"
/* Cosas del resolv.conf */
enum {
RESOLV_TYPE_NAMESERVER,
RESOLV_TYPE_DOMAIN,
RESOLV_TYPE_SEARCH,
RESOLV_TYPE_SORTLIST,
RESOLV_TYPE_OPTIONS,
NUM_RESOLV_TYPES
};
enum {
RESOLV_ORIGIN_FILE,
RESOLV_ORIGIN_DHCP,
RESOLV_ORIGIN_RESOLVCONF,
RESOLV_ORIGIN_SLAAC_RDNSS,
NUM_RESOLV_ORIGINS
};
typedef struct _ResolvConfEntry {
int resolv_type;
int origin;
int file_order;
int is_on_file;
int priority;
int ns_family;
struct_addr nameserver;
char value[2048];
//char owner_interface[IFNAMSIZ];
int owner_interface_index;
char owner_prog[256];
} ResolvConfEntry;
#endif /* __RESOLV_CONF_DEFS_H__ */

View File

@ -0,0 +1,258 @@
/*
* resolv_conf_helper.c
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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.
*
* NetworkInador 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 NetworkInador; 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 <getopt.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include "glist.h"
#include "network-inador-manager.h"
#include "resolv_conf_defs.h"
#include "struct_addr_union.h"
#include "resolv_conf_parser.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
static const struct option long_options[] = {
{"enable-updates", 0, NULL, 'z' },
{"disable-updates", 0, NULL, 'y' },
{"updates-are-enabled", 0, NULL, 'x' },
{"create-runtime-directories", 0, NULL, 'w' },
{"wipe-runtime-directories", 0, NULL, 'v' },
{NULL, 0, NULL, 0}
};
const char *short_options = "a:d:u";
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_entries (int s, GList *entries, const char *iface_prog) {
char buffer[2048];
int pos, len, pos_name_count;
GList *g;
int n;
ResolvConfEntry *entry;
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_RESOLVCONF_FEED;
/* El segundo byte es el nombre seguido del nombre en sí */
len = strlen (iface_prog);
buffer[2] = len;
memcpy (&buffer[3], iface_prog, len);
pos_name_count = 3 + len;
/* Contar los nameservers que tengo */
g = entries;
n = 0;
pos = pos_name_count + 1;
while (g != NULL) {
entry = (ResolvConfEntry *) g->data;
if (entry->resolv_type == RESOLV_TYPE_NAMESERVER) {
n++;
buffer[pos] = entry->ns_family;
pos++;
if (entry->ns_family == AF_INET) {
memcpy (&buffer[pos], &entry->nameserver, 4);
pos += 4;
} else if (entry->ns_family == AF_INET6) {
memcpy (&buffer[pos], &entry->nameserver, 16);
pos += 16;
}
}
g = g->next;
}
buffer[pos_name_count] = n;
send (s, buffer, pos, 0);
if (wait_for_ack_or_error (s) < 0) {
return;
}
}
void send_remove_entries (int s, const char *iface_prog) {
char buffer[2048];
int pos, len;
buffer[0] = NET_INADOR_TYPE_COMMAND;
buffer[1] = NET_INADOR_COMMAND_RESOLVCONF_REMOVE;
/* El segundo byte es el nombre seguido del nombre en sí */
len = strlen (iface_prog);
buffer[2] = len;
memcpy (&buffer[3], iface_prog, len);
send (s, buffer, 3 + len, 0);
if (wait_for_ack_or_error (s) < 0) {
return;
}
}
int main (int argc, char *argv[]) {
int next_option;
const char *iface_prog = NULL;
int action = 0;
GList *entries;
int s, ret;
struct sockaddr_un path_dest;
do {
next_option = getopt_long (argc, argv, short_options, long_options, NULL);
switch (next_option) {
case 'z':
case 'y':
case 'x':
case 'w':
case 'v':
/* Ignorar */
break;
case 'a':
action = 'a';
iface_prog = optarg;
break;
case 'd':
action = 'd';
iface_prog = optarg;
break;
case 'u':
break;
case '?':
/* Opción incorrecta */
break;
case -1:
/* Fin de opciones */
break;
}
} while (next_option != -1);
if (action == 0) {
return 0;
}
/* Validar el nombre del argumento del -a o del -d */
if (iface_prog == NULL || iface_prog[0] == 0) {
fprintf (stderr, "interface record name empty\n");
return -1;
}
if (strchr (iface_prog, '/') != NULL) {
/* Diagonal no permitida */
fprintf (stderr, "Slash not allowed in interface record name\n");
return -1;
}
if (strchr (iface_prog, ' ') != NULL) {
fprintf (stderr, "Space not allowed in interface record name\n");
return -1;
}
if (iface_prog[0] == '.') {
fprintf (stderr, "Space not allowed in interface record name\n");
return -1;
}
if (iface_prog[0] == '-') {
fprintf (stderr, "Initial hyphen not allowed in interface record name\n");
return -1;
}
if (iface_prog[0] == '~') {
fprintf (stderr, "Initial tilde not allowed in interface record name\n");
return -1;
}
if (strlen (iface_prog) > 255) {
fprintf (stderr, "Interface too long\n");
return -1;
}
/* Intentar abrir el socket al network inador */
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 (action == 'a') {
/* Parsear el archivo primero */
entries = resolv_parser_parse_file (NULL, stdin, RESOLV_ORIGIN_RESOLVCONF);
/* Preparar un paquete de datos para enviar via el socket */
send_entries (s, entries, iface_prog);
} else if (action == 'd') {
send_remove_entries (s, iface_prog);
}
close (s);
return 0;
}

View File

@ -0,0 +1,180 @@
/*
* resolv_conf_parser.c
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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.
*
* NetworkInador 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 NetworkInador; 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 <unistd.h>
#include <arpa/inet.h>
#include "resolv_conf_defs.h"
#include "resolv_conf_parser.h"
#include "utils.h"
#ifdef STAND_ALONE_RESOLV_CONF_HELPER_BUILD
#include "glist.h"
#else
#include "common.h"
#endif
static const char *resolv_conf_keywords[NUM_RESOLV_TYPES] = {
"nameserver",
"domain",
"search",
"sortlist",
"options"
};
int resolv_conf_parse_line (const char *line, int *ns_family, struct_addr *nameserver, char *value, const size_t value_size) {
int g, len;
int af;
struct_addr temp_addr;
int ret;
/* Recorrer cada palabra clave posible de los resolv.conf */
for (g = 0; g < NUM_RESOLV_TYPES; g++) {
len = strlen (resolv_conf_keywords[g]);
if (strncmp (line, resolv_conf_keywords[g], len) == 0 && line[len] == ' ') {
if (g == RESOLV_TYPE_NAMESERVER) {
/* Los nameserver solo pueden ser direcciones IP de IPv4 o IPv6 */
af = AF_INET;
ret = inet_pton (AF_INET, &line[len + 1], &temp_addr);
if (ret == 0) {
af = AF_INET6;
ret = inet_pton (AF_INET6, &line[len + 1], &temp_addr);
}
if (ret == 0) {
/* No es una dirección IP, ignorar */
break;
}
} else {
/* Revisar por posibles restricciones en otros tipos */
}
strncpy (value, &line[len + 1], value_size);
value[value_size - 1] = 0;
if (g == RESOLV_TYPE_NAMESERVER) {
*ns_family = af;
memcpy (nameserver, &temp_addr, sizeof (temp_addr));
} else {
*ns_family = AF_UNSPEC;
memset (nameserver, 0, sizeof (temp_addr));
}
return g;
}
}
/* No es alguna linea válida */
return -1;
}
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value) {
GList *g;
ResolvConfEntry *entry;
g = all_entries;
while (g != NULL) {
entry = (ResolvConfEntry *) g->data;
if (resolv_type != entry->resolv_type) {
/* Pasar a la siguiente entrada, no es del mismo tipo */
g = g->next;
continue;
}
/* Comparar dependiendo del tipo */
if (resolv_type == RESOLV_TYPE_NAMESERVER) {
if (ns_family == AF_INET && entry->ns_family == AF_INET) {
if (memcmp (nameserver, &entry->nameserver, sizeof (struct in_addr)) == 0) {
/* Es la entrada que andamos buscando */
return g;
}
} else if (ns_family == AF_INET6 && entry->ns_family == AF_INET6) {
if (memcmp (nameserver, &entry->nameserver, sizeof (struct in6_addr)) == 0) {
return g;
}
}
} else {
/* TODO: Revisar si las otras entradas requieren otro tipo de comparación */
if (strcmp (value, entry->value) == 0) {
return g;
}
}
g = g->next;
}
return NULL;
}
GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin) {
char buffer[8192], value[2048];
ResolvConfEntry *entry = NULL;
GList *pos, *next;
int g, len;
struct_addr direccion;
int type;
int family;
int order;
order = 0;
while (fgets (buffer, sizeof (buffer), fd), feof (fd) == 0) {
utils_trim (buffer);
utils_trim_comment (buffer);
if (buffer[0] == 0) continue;
type = resolv_conf_parse_line (buffer, &family, &direccion, value, sizeof (value));
if (type == -1) {
/* Linea no válida de acuerdo al parser, ignorar */
continue;
}
/* Tenemos una linea buena, buscar si esta linea ya existe en nuestra lista de entradas */
pos = resolv_parser_search_entry (all_entries, type, family, &direccion, value);
if (pos != NULL) {
/* Ya existe, refrescar que está en el archivo */
entry = (ResolvConfEntry *) pos->data;
} else {
/* Como no existe, crear y anexar al final de la lista */
entry = (ResolvConfEntry *) malloc (sizeof (ResolvConfEntry));
entry->resolv_type = type;
entry->origin = origin;
entry->ns_family = family;
memcpy (&entry->nameserver, &direccion, sizeof (direccion));
strncpy (entry->value, value, sizeof (entry->value));
entry->owner_interface_index = 0;
entry->owner_prog[0] = 0;
all_entries = g_list_append (all_entries, entry);
}
entry->is_on_file = 1;
entry->file_order = order++;
}
return all_entries;
}

View File

@ -0,0 +1,39 @@
/*
* resolv_conf_parser.h
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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.
*
* NetworkInador 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 NetworkInador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __RESOLV_CONF_PARSER_H__
#define __RESOLV_CONF_PARSER_H__
#include <stdio.h>
#include <stdlib.h>
#ifdef STAND_ALONE_RESOLV_CONF_HELPER_BUILD
#include "glist.h"
#else
#include "common.h"
#endif
GList * resolv_parser_search_entry (GList *all_entries, const int resolv_type, const int ns_family, const struct_addr *nameserver, const char *value);
GList * resolv_parser_parse_file (GList *all_entries, FILE *fd, int origin);
#endif /* __RESOLV_CONF_PARSER_H__ */

View File

@ -0,0 +1,137 @@
/*
* resolv_manager.c
* This file is part of Network-inador
*
* Copyright (C) 2022 - 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 <ctype.h>
#include <sys/inotify.h>
#include "common.h"
#include "utils.h"
#include "resolv_conf_parser.h"
void resolv_manager_clear_entries_by_prog (NetworkInadorHandle *handle, const int iface_index, const char *prog) {
GList *g, *next;
ResolvConfEntry *entry;
g = handle->resolver_entries;
while (g != NULL) {
next = g->next;
entry = (ResolvConfEntry *) g->data;
if (entry->origin != RESOLV_ORIGIN_RESOLVCONF) {
/* Solo borramos las entradas creadas via resolvconf */
g = next;
continue;
}
if (entry->owner_interface_index != iface_index) {
g = next;
continue;
}
if (prog == NULL || strcmp (entry->owner_prog, prog) == 0) {
/* Hay que eliminar esta entrada, coincide por la interfaz o nombre de programa */
printf ("/// Eliminando entrada %s por via resolvconf. Prog = «%s»\n", entry->value, prog);
free (entry);
handle->resolver_entries = g_list_delete_link (handle->resolver_entries, g);
}
g = next;
}
}
void resolv_manager_read_local_etc_resolv (NetworkInadorHandle *handle) {
FILE *fd;
GList *pos, *next;
ResolvConfEntry *entry;
fd = fopen ("/etc/resolv.conf", "r");
if (fd == NULL) return;
printf ("/// Ejecutando lectura de resolv.conf\n");
/* Etiquetar las entradas con origen del archivo como "ya no en el archivo", para que cuando se lea el archivo, nos queden las que vamos a eliminar */
/* Borrar cuáles están en el archivo */
pos = handle->resolver_entries;
while (pos != NULL) {
entry = (ResolvConfEntry *) pos->data;
entry->is_on_file = 0;
pos = pos->next;
}
handle->resolver_entries = resolv_parser_parse_file (handle->resolver_entries, fd, RESOLV_ORIGIN_FILE);
fclose (fd);
/* A la salida, borrar las que ya no siguen en el archivo */
pos = handle->resolver_entries;
while (pos != NULL) {
next = pos->next;
entry = (ResolvConfEntry *) pos->data;
if (entry->origin == RESOLV_ORIGIN_FILE && entry->is_on_file == 0) {
/* Esta entrada se va, la eliminaron */
printf ("/// La entrada %s del resolv.conf fué eliminada del archivo. Purgando nosotros.\n", entry->value);
handle->resolver_entries = g_list_delete_link (handle->resolver_entries, pos);
free (entry);
entry = NULL;
} else {
printf ("/// La entrada %s del resolv.conf sigue en el archivo.\n", entry->value);
}
pos = next;
}
}
void resolv_manager_init (NetworkInadorHandle *handle) {
//handle->resolver_inotify_fd = inotify_init1 (IN_NONBLOCK | IN_CLOEXEC);
if (handle->resolver_inotify_fd >= 0) {
/* Debemos primero instalar el manejador de eventos de escritura sobre el resolv.conf */
/*
IN_CLOSE_WRITE Releer archivo.
IN_DELETE_SELF Dejar de hacer watch
IN_MOVE_SELF Dejar de hacer watch
*/
//handle->resolver_inotify_watch = inotify_add_watch (handle->resolver_inotify_fd, "/etc/resolv.conf",
}
handle->resolver_entries = NULL;
/* Luego, leer el resolv.conf */
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
resolv_manager_read_local_etc_resolv (handle);
}

View File

@ -0,0 +1,33 @@
/*
* resolv_manager.h
* This file is part of Network-inador
*
* Copyright (C) 2023 - 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
*/
#ifndef __RESOLV_MANAGER_H__
#define __RESOLV_MANAGER_H__
#include "struct_addr_union.h"
#include "resolv_conf_parser.h"
void resolv_manager_init (NetworkInadorHandle *handle);
void resolv_manager_clear_entries_by_prog (NetworkInadorHandle *handle, const int iface_index, const char *prog);
#endif /* __RESOLV_MANAGER_H__ */

View File

@ -0,0 +1,35 @@
/*
* struct_addr_union.h
* This file is part of NetworkInador
*
* Copyright (C) 2023 - Félix Arreola Rodríguez
*
* NetworkInador 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.
*
* NetworkInador 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 NetworkInador; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#ifndef __STRUCT_ADDR_UNION_H__
#define __STRUCT_ADDR_UNION_H__
#include <sys/socket.h>
#include <netinet/in.h>
typedef union {
struct in_addr v4;
struct in6_addr v6;
} struct_addr;
#endif /* __STRUCT_ADDR_UNION_H__ */

53
src/utils.c 100644
View File

@ -0,0 +1,53 @@
/*
* utils.c
* This file is part of Network-inador
*
* Copyright (C) 2022 - 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 <ctype.h>
#include "utils.h"
void utils_trim (char * s) {
char * p = s;
int l = strlen(p);
while(isspace(p[l - 1])) p[--l] = 0;
while(* p && isspace(* p)) ++p, --l;
memmove(s, p, l + 1);
}
void utils_trim_comment (char *s) {
char *p = s;
int l = strlen (p);
while (*p != 0 && *p != '#') {
++p;
}
if (*p == '#') {
*p = 0;
}
}

36
src/utils.h 100644
View File

@ -0,0 +1,36 @@
/*
* utils.h
* This file is part of Network-inador
*
* Copyright (C) 2022 - 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
*/
#ifndef __UTILS_H__
#define __UTILS_H__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void utils_trim (char * s);
void utils_trim_comment (char *s);
#endif /* __UTILS_H__ */