Reescritura para usar libnl3.

master
Félix Arreola Rodríguez 2019-12-31 11:05:50 -06:00
parent 3aedf1869e
commit 060cc47735
40 changed files with 567 additions and 7853 deletions

View File

@ -4,15 +4,14 @@ AC_REVISION([Revision 1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR([src/network-inador.c])
AC_CONFIG_SRCDIR([src/main.c])
# For debian systems, /usr as default
AC_PREFIX_DEFAULT([/usr])
# We need Gcc
AC_PROG_CC
# We need OBJC, for MAC
AC_PROG_OBJC
# and automake
AM_INIT_AUTOMAKE([-Wall -Werror])
@ -36,11 +35,15 @@ case $host_os in
esac
GLIB_VERSION=2.50
LIBNL_VERSION=0.29
AC_MSG_CHECKING([if you have Glib installed on your system])
PKG_CHECK_EXISTS([glib-2.0 >= $GLIB_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([Glib not found in your system])])
PKG_CHECK_MODULES(GLIB, [glib-2.0 >= $GLIB_VERSION], [], [])
AC_MSG_CHECKING([if you have libnl-3 installed on your system])
PKG_CHECK_EXISTS([libnl-3.0 >= LIBNL_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([libnl-3 not found in your system])])
PKG_CHECK_MODULES(LIBNL3, [libnl-3.0 >= $LIBNL_VERSION], [], [])
AC_CONFIG_HEADERS([config.h])
@ -48,8 +51,9 @@ AC_CONFIG_FILES([
Makefile
src/Makefile
po/Makefile.in
src/dhcpc/Makefile
])
# src/dhcpc/Makefile
# src/client_test/Makefile
# data/Makefile
AC_OUTPUT

View File

@ -1,2 +1,2 @@
# List of source files which contain translatable strings.
src/network-inador.c
src/main.c

View File

@ -1,22 +1,14 @@
# Automake file for NetworkInador
bin_PROGRAMS = network-inador
network_inador_SOURCES = network-inador.c network-inador.h \
network_inador_SOURCES = main.c common.h \
netlink-events.c netlink-events.h \
interfaces.c interfaces.h \
manager.c manager.h \
utils.c utils.h \
bridge.c bridge.h \
rta_aux.c rta_aux.h \
routes.c routes.h \
manager-events.c manager-events.h \
dhcp.c dhcp.h \
wireless.c
interfaces.c interfaces.h
#network_inador_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
network_inador_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
network_inador_CFLAGS = $(GLIB_CFLAGS) $(AM_CFLAGS)
network_inador_LDADD = $(GLIB_LIBS)
network_inador_CFLAGS = $(GLIB_CFLAGS) $(LIBNL3_CFLAGS) $(AM_CFLAGS)
network_inador_LDADD = $(GLIB_LIBS) $(LIBNL3_LIBS)
LDADD = $(LIBINTL)
SUBDIRS = dhcpc
#SUBDIRS = client_test dhcpc

View File

@ -1,300 +0,0 @@
/*
* bridge.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "interfaces.h"
#include "rta_aux.h"
void bridge_create (int sock, const char *name) {
struct msghdr rtnl_msg;
struct iovec io;
struct sockaddr_nl kernel;
char buffer[8192];
int len;
struct nlmsghdr *nl;
struct ifinfomsg *ifi;
struct rtattr *linkinfo;
struct nlmsgerr *l_err;
struct sockaddr_nl local_nl;
socklen_t local_size;
if (name != NULL) {
/* Validar la longitud del nombre, por seguridad */
len = strlen (name) + 1;
if (len == 1) {
/* Nombre muy corto */
return;
}
if (len > IFNAMSIZ) {
/* Nombre muy largo */
return;
}
}
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
nl = (struct nlmsghdr *) buffer;
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
nl->nlmsg_type = RTM_NEWLINK;
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
nl->nlmsg_seq = global_nl_seq++;
nl->nlmsg_pid = local_nl.nl_pid;
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
ifi->ifi_family = AF_UNSPEC;
ifi->ifi_index = 0;
/* Si existe un nombre, anexar como atributo */
if (name != NULL) {
rta_addattr_l (nl, sizeof (buffer), IFLA_IFNAME, name, strlen (name));
}
linkinfo = rta_addattr_nest (nl, sizeof (buffer), IFLA_LINKINFO);
rta_addattr_l (nl, sizeof (buffer), IFLA_INFO_KIND, "bridge", strlen ("bridge"));
rta_addattr_nest_end (nl, linkinfo);
io.iov_base = buffer;
io.iov_len = nl->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_msg, 0);
nl = (struct nlmsghdr *) buffer;
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
if (nl->nlmsg_type == NLMSG_DONE) {
printf ("Bridge ADD Msg type: DONE!\n");
break;
}
if (nl->nlmsg_type == NLMSG_ERROR) {
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
printf ("Bridge ADD Error tamaño truncado\n");
} else if (l_err->error != 0) {
// Error:
printf ("Bridge ADD Error: %i\n", l_err->error);
}
break;
}
}
}
void bridge_add_interface (int sock, Interface *bridge, Interface *slave) {
struct msghdr rtnl_msg;
struct iovec io;
struct sockaddr_nl kernel;
char buffer[8192];
int len;
struct nlmsghdr *nl;
struct ifinfomsg *ifi;
struct nlmsgerr *l_err;
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
nl = (struct nlmsghdr *) buffer;
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
nl->nlmsg_type = RTM_NEWLINK;
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nl->nlmsg_seq = global_nl_seq++;
nl->nlmsg_pid = local_nl.nl_pid;
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
ifi->ifi_family = AF_UNSPEC;
ifi->ifi_index = slave->index;
rta_addattr_l (nl, sizeof (buffer), IFLA_MASTER, &bridge->index, 4);
io.iov_base = buffer;
io.iov_len = nl->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_msg, 0);
nl = (struct nlmsghdr *) buffer;
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
if (nl->nlmsg_type == NLMSG_DONE) {
printf ("Bridge ADD Slave Msg type: DONE!\n");
break;
}
if (nl->nlmsg_type == NLMSG_ERROR) {
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
printf ("Bridge ADD Slave Error tamaño truncado\n");
} else if (l_err->error != 0) {
// Error:
printf ("Bridge ADD Slave Error: %i\n", l_err->error);
}
break;
}
}
}
void bridge_remove_slave_from_bridge (int sock, Interface *slave) {
struct msghdr rtnl_msg;
struct iovec io;
struct sockaddr_nl kernel;
char buffer[8192];
int len;
struct nlmsghdr *nl;
struct ifinfomsg *ifi;
struct nlmsgerr *l_err;
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
nl = (struct nlmsghdr *) buffer;
nl->nlmsg_len = NLMSG_LENGTH (sizeof(struct ifinfomsg));
nl->nlmsg_type = RTM_NEWLINK;
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nl->nlmsg_seq = global_nl_seq++;
nl->nlmsg_pid = local_nl.nl_pid;
ifi = (struct ifinfomsg*) NLMSG_DATA (nl);
ifi->ifi_family = AF_UNSPEC;
ifi->ifi_index = slave->index;
int ifindex = 0;
rta_addattr_l (nl, sizeof (buffer), IFLA_MASTER, &ifindex, 4);
io.iov_base = buffer;
io.iov_len = nl->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_msg, 0);
nl = (struct nlmsghdr *) buffer;
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
if (nl->nlmsg_type == NLMSG_DONE) {
printf ("Bridge NOMaster Msg type: DONE!\n");
break;
}
if (nl->nlmsg_type == NLMSG_ERROR) {
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
printf ("Bridge NOMaster Error tamaño truncado\n");
} else if (l_err->error != 0) {
// Error:
printf ("Bridge NOMaster Error: %i\n", l_err->error);
}
break;
}
}
}

View File

@ -1,33 +0,0 @@
/*
* bridge.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 __BRIDGE_H__
#define __BRIDGE_H__
#include "network-inador.h"
void bridge_create (int sock, const char *name);
void bridge_add_interface (int sock, Interface *bridge, Interface *slave);
void bridge_remove_slave_from_bridge (int sock, Interface *slave);
#endif

View File

@ -1,8 +1,8 @@
/*
* network-inador.h
* common.h
* This file is part of Network-inador
*
* Copyright (C) 2011 - Félix Arreola Rodríguez
* Copyright (C) 2019, 2020 - 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
@ -20,64 +20,23 @@
* Boston, MA 02110-1301 USA
*/
#ifndef __NETWORK_INADOR_H__
#define __NETWORK_INADOR_H__
#include <stdint.h>
#ifndef __COMMON_H__
#define __COMMON_H__
#include <netinet/in.h>
#include <linux/if.h>
#include <net/ethernet.h>
#include <unistd.h>
#include <linux/if.h>
#include <glib.h>
#include <gmodule.h>
/* Para almacenar la información de DHCP */
enum {
IFACE_NO_DHCP_RUNNING = 0,
IFACE_DHCP_CLIENT,
};
#ifndef FALSE
#define FALSE 0
#endif
enum {
DHCP_CLIENT_DECONFIG = 1,
DHCP_CLIENT_LEASEFAIL,
DHCP_CLIENT_BOUND,
DHCP_CLIENT_RENEW,
DHCP_CLIENT_NAK
};
typedef struct _DHCPStateInfo {
int type;
int read_pipe;
GPid process_pid;
int client_state;
} DHCPStateInfo;
typedef struct _IPv4 {
struct in_addr sin_addr;
uint32_t prefix;
unsigned char flags;
struct _IPv4 *next;
} IPv4;
typedef struct _WirelessAccessPoint {
int freq;
int essid;
char bssid[10];
struct _WirelessAccessPoint *next;
} WirelessAccessPoint;
typedef struct {
int wiphy;
WirelessAccessPoint *scaned_aps;
} WirelessInfo;
#ifndef TRUE
#define TRUE !FALSE
#endif
typedef struct _Interface {
char name[IFNAMSIZ];
@ -90,6 +49,9 @@ typedef struct _Interface {
unsigned int mtu;
/* Para las interfaces vlan */
unsigned int vlan_parent;
/* Banderas estilo ioctl */
short flags;
@ -101,37 +63,24 @@ typedef struct _Interface {
int is_bridge;
int is_vlan;
int is_nlmon;
int is_dummy;
IPv4 *v4_address;
//IPv4 *v4_address;
DHCPStateInfo dhcp_info;
//DHCPStateInfo dhcp_info;
/* Información wireless */
WirelessInfo *wireless;
struct _Interface *next;
//WirelessInfo *wireless;
} Interface;
typedef struct _Routev4 {
struct in_addr dest;
uint32_t prefix;
struct in_addr gateway;
unsigned int index;
unsigned char table;
unsigned char type;
struct _Routev4 *next;
} Routev4;
typedef struct {
Interface *interfaces;
Routev4 *rtable_v4;
GList *interfaces;
//Routev4 *rtable_v4;
int netlink_sock_request;
int netlink_sock_request_generic;
struct nl_sock * nl_sock_route;
struct nl_sock * nl_sock_route_events;
guint route_events_source;
} NetworkInadorHandle;
#endif
#endif /* __COMMON_H__ */

View File

@ -1,286 +0,0 @@
/*
* dhcp.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <signal.h>
#include <glib.h>
#include "network-inador.h"
#include "dhcp.h"
#include "interfaces.h"
#include "utils.h"
#include "routes.h"
#define DHCPC_PIPEOUT_HAS_IP 0x01
#define DHCPC_PIPEOUT_HAS_SERVER_IP 0x02
#define DHCPC_PIPEOUT_HAS_OPTS 0x04
static void _dhcp_parse_client_packet (NetworkInadorHandle *handle, Interface *iface, unsigned char *buffer, int len) {
int type, flags, current_opt, count_opt;
IPv4 address;
struct in_addr mask, siaddr_nip, route;
type = buffer[0];
int pos;
int has_gateway = 0;
memset (&address, 0, sizeof (address));
/* Máscara por default */
inet_pton (AF_INET, "255.255.255.0", &mask);
iface->dhcp_info.client_state = type;
switch (type) {
case DHCP_CLIENT_DECONFIG:
/* Desconfigurar la interfaz, borrar las IPs */
interfaces_clear_all_ipv4_address (handle, iface);
interfaces_bring_up (handle->netlink_sock_request, iface);
break;
case DHCP_CLIENT_LEASEFAIL:
case DHCP_CLIENT_NAK:
/* leasefail, nak */
break;
case DHCP_CLIENT_BOUND:
case DHCP_CLIENT_RENEW:
/* Bound, renew */
flags = buffer[1];
pos = 2;
if (flags & DHCPC_PIPEOUT_HAS_IP) {
memcpy (&address.sin_addr, &buffer[pos], 4);
pos += 4;
}
if (flags & DHCPC_PIPEOUT_HAS_SERVER_IP) {
memcpy (&siaddr_nip, &buffer[pos], 4);
pos += 4;
}
if (flags & DHCPC_PIPEOUT_HAS_OPTS) {
current_opt = buffer[pos];
while (current_opt != 255) {
pos++;
if (current_opt == 0x01) {
memcpy (&mask, &buffer[pos], 4);
pos += 4;
} else if (current_opt == 0x03) {
count_opt = buffer[pos];
pos++;
/* TODO: Solo tomamos la ultima ruta, arreglar */
while (count_opt) {
memcpy (&route, &buffer[pos], 4);
pos += 4;
has_gateway = 1;
count_opt--;
}
} else if (current_opt == 0x06) {
/* TODO: Procesar la lista de DNS */
count_opt = buffer[pos];
pos++;
while (count_opt) {
count_opt--;
pos += 4;
}
} else if (current_opt == 0x0c || current_opt == 0x0f) {
/* TODO: Procesar el hostname o domain name */
while (buffer[pos] != 0) {
pos++;
}
} else if (current_opt == 0x2a) {
/* TODO: Procesar la lista de NTP */
count_opt = buffer[pos];
pos++;
while (count_opt) {
count_opt--;
pos += 4;
}
}
current_opt = buffer[pos];
}
/* Ejecutar la configuración de la IP */
address.prefix = utils_ip4_netmask_to_prefix (mask.s_addr);
interfaces_manual_add_ipv4 (handle->netlink_sock_request, iface, &address);
/* Y esperar a que se active la IP para luego configurar la ruta */
if (has_gateway) {
IPv4 default_dest;
inet_pton (AF_INET, "0.0.0.0", &default_dest.sin_addr);
default_dest.prefix = 0;
routes_manual_add_ipv4 (handle->netlink_sock_request, iface, &default_dest, route);
}
}
break;
}
}
gboolean _dhcp_read_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock;
char buffer[256];
int len;
Interface *iface;
int exit_estatus;
int ret;
sock = g_io_channel_unix_get_fd (source);
len = read (sock, buffer, sizeof (buffer));
printf ("\n-------------> Read DHCP client from PIPE (%i) = %i\n", sock, len);
iface = handle->interfaces;
while (iface != NULL) {
if (sock == iface->dhcp_info.read_pipe) {
/* Esta es la interfaz activa */
break;
}
iface = iface->next;
}
if (iface == NULL) {
/* Que raro... no debería ocurrir */
return FALSE;
}
if (len == 0) {
close (sock);
/* El proceso del cliente de dhcp murió, si lo reiniciamos se maneja en g_child_wait */
iface->dhcp_info.read_pipe = 0;
return FALSE;
} else if (len < 0) {
printf ("_--------------_____________ Soy el error que buscas\n");
return FALSE;
} else {
/* Parsear lo leido por el dhcp client */
_dhcp_parse_client_packet (handle, iface, buffer, len);
}
return TRUE;
}
static void _dhcp_client_exited (GPid pid, gint status, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
Interface *iface;
iface = handle->interfaces;
while (iface != NULL) {
if (pid == iface->dhcp_info.process_pid) {
/* Esta es la interfaz activa */
break;
}
iface = iface->next;
}
if (iface == NULL) {
/* El dhcp para una interfaz eliminada murió */
g_spawn_close_pid (pid);
return;
}
iface->dhcp_info.process_pid = 0;
/* Si el estado quedó en "running", reiniciar el proceso de dhcp */
if (iface->dhcp_info.type == IFACE_DHCP_CLIENT) {
iface->dhcp_info.type = IFACE_NO_DHCP_RUNNING;
dhcp_run_client (handle, iface);
}
g_spawn_close_pid (pid);
}
void dhcp_run_client (NetworkInadorHandle *handle, Interface *iface) {
GIOChannel *channel;
gboolean result;
gint read_from_child;
GPid child_pid;
/* FIXME: Arreglar el path */
char *argv[] = {"/tmp/abc/sbin/nidhcpc", iface->name, NULL};
if (iface->dhcp_info.type != IFACE_NO_DHCP_RUNNING) {
printf ("DHCP (client or server) already running\n");
return;
}
interfaces_bring_up (handle->netlink_sock_request, iface);
result = g_spawn_async_with_pipes (
NULL, /* working directory */
argv, /* Argumentos */
NULL, /* envp */
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_CLOEXEC_PIPES, /* Banderas */
NULL, NULL, /* Child setup func and data */
&child_pid,
NULL, /* Entrada estándar */
&read_from_child, /* Salida estándar */
NULL, /* Salida de errores */
NULL); /* Gerror */
if (result == FALSE) {
printf ("Falló al lanzar proceso de cliente de dhcp\n");
return;
}
iface->dhcp_info.type = IFACE_DHCP_CLIENT;
iface->dhcp_info.read_pipe = read_from_child;
iface->dhcp_info.process_pid = child_pid;
iface->dhcp_info.client_state = DHCP_CLIENT_DECONFIG;
/* Instalar un GIOChannel */
channel = g_io_channel_unix_new (read_from_child);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _dhcp_read_client_data, handle);
/* Para manejar la muerte del proceso */
g_child_watch_add (child_pid, _dhcp_client_exited, handle);
}
void dhcp_stop_client (NetworkInadorHandle *handle, Interface *iface) {
if (iface->dhcp_info.type == IFACE_DHCP_CLIENT) {
iface->dhcp_info.type = IFACE_NO_DHCP_RUNNING;
kill (iface->dhcp_info.process_pid, SIGTERM);
}
}

View File

@ -1,29 +0,0 @@
/*
* dhcp.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 __DHCP_H__
#define __DHCP_H__
void dhcp_run_client (NetworkInadorHandle *handle, Interface *iface);
void dhcp_stop_client (NetworkInadorHandle *handle, Interface *iface);
#endif

View File

@ -1,17 +0,0 @@
# Automake file for NetworkInador DHCP Client
sbin_PROGRAMS = nidhcpc
nidhcpc_SOURCES = nidhcpc.c \
common.c common.h \
dhcpc.c dhcpc.h dhcpd.h \
extra.c extra.h \
packet.c \
signalpipe.c \
socket.c
#client_network_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
nidhcpc_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS)
nidhcpc_CFLAGS = $(AM_CFLAGS)
nidhcpc_LDADD =
LDADD = $(LIBINTL)

View File

@ -1,441 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "common.h"
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
unsigned dhcp_verbose;
#endif
const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
/* Supported options are easily added here.
* See RFC2132 for more options.
* OPTION_REQ: these options are requested by udhcpc (unless -o).
*/
const struct dhcp_optflag dhcp_optflags[] = {
/* flags code */
{ OPTION_IP | OPTION_REQ, 0x01 }, /* DHCP_SUBNET */
{ OPTION_S32 , 0x02 }, /* DHCP_TIME_OFFSET */
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03 }, /* DHCP_ROUTER */
// { OPTION_IP | OPTION_LIST , 0x04 }, /* DHCP_TIME_SERVER */
// { OPTION_IP | OPTION_LIST , 0x05 }, /* DHCP_NAME_SERVER */
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER */
// { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */
// { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */
{ OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */
{ OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */
{ OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */
{ OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */
{ OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */
{ OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */
{ OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */
{ OPTION_U16 , 0x1a }, /* DHCP_MTU */
//TODO: why do we request DHCP_BROADCAST? Can't we assume that
//in the unlikely case it is different from typical N.N.255.255,
//server would let us know anyway?
{ OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */
{ OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */
{ OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */
{ OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */
{ OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */
{ OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */
{ OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */
{ OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */
{ OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */
//TODO: must be combined with 'sname' and 'file' handling:
{ OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
{ OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */
//TODO: not a string, but a set of LASCII strings:
// { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */
#if ENABLE_FEATURE_UDHCP_RFC3397
{ OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */
{ OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */
#endif
{ OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */
#if ENABLE_FEATURE_UDHCP_8021Q
{ OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */
{ OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */
#endif
{ OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */
{ OPTION_6RD , 0xd4 }, /* DHCP_6RD */
{ OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
{ OPTION_STRING , 0xfc }, /* DHCP_WPAD */
/* Options below have no match in dhcp_option_strings[],
* are not passed to dhcpc scripts, and cannot be specified
* with "option XXX YYY" syntax in dhcpd config file.
* These entries are only used internally by udhcp[cd]
* to correctly encode options into packets.
*/
{ OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */
{ OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */
{ OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */
//looks like these opts will work just fine even without these defs:
// { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */
// /* not really a string: */
// { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */
{ 0, 0 } /* zeroed terminating entry */
};
/* Used for converting options from incoming packets to env variables
* for udhcpc stript, and for setting options for udhcpd via
* "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file.
*/
/* Must match dhcp_optflags[] order */
const char dhcp_option_strings[] ALIGN1 =
"subnet" "\0" /* DHCP_SUBNET */
"timezone" "\0" /* DHCP_TIME_OFFSET */
"router" "\0" /* DHCP_ROUTER */
// "timesrv" "\0" /* DHCP_TIME_SERVER */
// "namesrv" "\0" /* DHCP_NAME_SERVER */
"dns" "\0" /* DHCP_DNS_SERVER */
// "logsrv" "\0" /* DHCP_LOG_SERVER */
// "cookiesrv" "\0" /* DHCP_COOKIE_SERVER */
"lprsrv" "\0" /* DHCP_LPR_SERVER */
"hostname" "\0" /* DHCP_HOST_NAME */
"bootsize" "\0" /* DHCP_BOOT_SIZE */
"domain" "\0" /* DHCP_DOMAIN_NAME */
"swapsrv" "\0" /* DHCP_SWAP_SERVER */
"rootpath" "\0" /* DHCP_ROOT_PATH */
"ipttl" "\0" /* DHCP_IP_TTL */
"mtu" "\0" /* DHCP_MTU */
"broadcast" "\0" /* DHCP_BROADCAST */
"routes" "\0" /* DHCP_ROUTES */
"nisdomain" "\0" /* DHCP_NIS_DOMAIN */
"nissrv" "\0" /* DHCP_NIS_SERVER */
"ntpsrv" "\0" /* DHCP_NTP_SERVER */
"wins" "\0" /* DHCP_WINS_SERVER */
"lease" "\0" /* DHCP_LEASE_TIME */
"serverid" "\0" /* DHCP_SERVER_ID */
"message" "\0" /* DHCP_ERR_MESSAGE */
"tftp" "\0" /* DHCP_TFTP_SERVER_NAME */
"bootfile" "\0" /* DHCP_BOOT_FILE */
// "userclass" "\0" /* DHCP_USER_CLASS */
#if ENABLE_FEATURE_UDHCP_RFC3397
"search" "\0" /* DHCP_DOMAIN_SEARCH */
// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
// is not handled yet by "string->option" conversion code:
"sipsrv" "\0" /* DHCP_SIP_SERVERS */
#endif
"staticroutes" "\0"/* DHCP_STATIC_ROUTES */
#if ENABLE_FEATURE_UDHCP_8021Q
"vlanid" "\0" /* DHCP_VLAN_ID */
"vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */
#endif
"pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */
"ip6rd" "\0" /* DHCP_6RD */
"msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
"wpad" "\0" /* DHCP_WPAD */
;
/* Lengths of the option types in binary form.
* Used by:
* udhcp_str2optset: to determine how many bytes to allocate.
* xmalloc_optname_optval: to estimate string length
* from binary option length: (option[LEN] / dhcp_option_lengths[opt_type])
* is the number of elements, multiply in by one element's string width
* (len_of_option_as_string[opt_type]) and you know how wide string you need.
*/
const uint8_t dhcp_option_lengths[] ALIGN1 = {
[OPTION_IP] = 4,
[OPTION_IP_PAIR] = 8,
// [OPTION_BOOLEAN] = 1,
[OPTION_STRING] = 1, /* ignored by udhcp_str2optset */
[OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */
#if ENABLE_FEATURE_UDHCP_RFC3397
[OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
[OPTION_SIP_SERVERS] = 1,
#endif
[OPTION_U8] = 1,
[OPTION_U16] = 2,
// [OPTION_S16] = 2,
[OPTION_U32] = 4,
[OPTION_S32] = 4,
/* Just like OPTION_STRING, we use minimum length here */
[OPTION_STATIC_ROUTES] = 5,
[OPTION_6RD] = 22, /* ignored by udhcp_str2optset */
};
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
static void log_option(const char *pfx, const uint8_t *opt)
{
if (dhcp_verbose >= 2) {
char buf[256 * 2 + 2];
*bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
}
}
#else
# define log_option(pfx, opt) ((void)0)
#endif
/* Get an option with bounds checking (warning, result is not aligned) */
uint8_t* udhcp_get_option(struct dhcp_packet *packet, int code)
{
uint8_t *optionptr;
int len;
int rem;
int overload = 0;
enum {
FILE_FIELD101 = FILE_FIELD * 0x101,
SNAME_FIELD101 = SNAME_FIELD * 0x101,
};
/* option bytes: [code][len][data1][data2]..[dataLEN] */
optionptr = packet->options;
rem = sizeof(packet->options);
while (1) {
if (rem <= 0) {
fprintf (stderr, "bad packet, malformed option field");
return NULL;
}
if (optionptr[OPT_CODE] == DHCP_PADDING) {
rem--;
optionptr++;
continue;
}
if (optionptr[OPT_CODE] == DHCP_END) {
if ((overload & FILE_FIELD101) == FILE_FIELD) {
/* can use packet->file, and didn't look at it yet */
overload |= FILE_FIELD101; /* "we looked at it" */
optionptr = packet->file;
rem = sizeof(packet->file);
continue;
}
if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
/* can use packet->sname, and didn't look at it yet */
overload |= SNAME_FIELD101; /* "we looked at it" */
optionptr = packet->sname;
rem = sizeof(packet->sname);
continue;
}
break;
}
len = 2 + optionptr[OPT_LEN];
rem -= len;
if (rem < 0)
continue; /* complain and return NULL */
if (optionptr[OPT_CODE] == code) {
log_option("Option found", optionptr);
return optionptr + OPT_DATA;
}
if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
overload |= optionptr[OPT_DATA];
/* fall through */
}
optionptr += len;
}
/* log3 because udhcpc uses it a lot - very noisy */
log3("Option 0x%02x not found", code);
return NULL;
}
/* Return the position of the 'end' option (no bounds checking) */
int udhcp_end_option(uint8_t *optionptr)
{
int i = 0;
while (optionptr[i] != DHCP_END) {
if (optionptr[i] != DHCP_PADDING)
i += optionptr[i + OPT_LEN] + OPT_DATA-1;
i++;
}
return i;
}
/* Add an option (supplied in binary form) to the options.
* Option format: [code][len][data1][data2]..[dataLEN]
*/
void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
{
unsigned len;
uint8_t *optionptr = packet->options;
unsigned end = udhcp_end_option(optionptr);
len = OPT_DATA + addopt[OPT_LEN];
/* end position + (option code/length + addopt length) + end option */
if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) {
//TODO: learn how to use overflow option if we exhaust packet->options[]
fprintf (stderr, "option 0x%02x did not fit into the packet",
addopt[OPT_CODE]);
return;
}
log_option("Adding option", addopt);
memcpy(optionptr + end, addopt, len);
optionptr[end + len] = DHCP_END;
}
/* Add an one to four byte option to a packet */
void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data)
{
const struct dhcp_optflag *dh;
for (dh = dhcp_optflags; dh->code; dh++) {
if (dh->code == code) {
uint8_t option[6], len;
option[OPT_CODE] = code;
len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK];
option[OPT_LEN] = len;
if (BB_BIG_ENDIAN)
data <<= 8 * (4 - len);
/* Assignment is unaligned! */
move_to_unaligned32(&option[OPT_DATA], data);
udhcp_add_binary_option(packet, option);
return;
}
}
fprintf (stderr, "can't add option 0x%02x", code);
}
/* Find option 'code' in opt_list */
struct option_set* udhcp_find_option(struct option_set *opt_list, uint8_t code)
{
while (opt_list && opt_list->data[OPT_CODE] < code)
opt_list = opt_list->next;
if (opt_list && opt_list->data[OPT_CODE] == code)
return opt_list;
return NULL;
}
/* Parse string to IP in network order */
int udhcp_str2nip(const char *str, void *arg)
{
len_and_sockaddr *lsa;
lsa = host_and_af2sockaddr(str, 0, AF_INET);
if (!lsa)
return 0;
/* arg maybe unaligned */
move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr);
free(lsa);
return 1;
}
/* udhcp_str2optset:
* Parse string option representation to binary form and add it to opt_list.
* Called to parse "udhcpc -x OPTNAME:OPTVAL"
* and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
*/
/* helper for the helper */
static char *allocate_tempopt_if_needed(
const struct dhcp_optflag *optflag,
char *buffer,
int *length_p)
{
char *allocated = NULL;
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
const char *end;
allocated = xstrdup(buffer); /* more than enough */
end = hex2bin(allocated, buffer, 255);
if (errno) {
fprintf (stderr, "malformed hex string '%s'", buffer);
exit (EXIT_FAILURE);
}
*length_p = end - allocated;
}
return allocated;
}
/* helper: add an option to the opt_list */
static NOINLINE void attach_option(
struct option_set **opt_list,
const struct dhcp_optflag *optflag,
char *buffer,
int length)
{
struct option_set *existing;
char *allocated;
allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
#if ENABLE_FEATURE_UDHCP_RFC3397
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
/* reuse buffer and length for RFC1035-formatted string */
allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
}
#endif
existing = udhcp_find_option(*opt_list, optflag->code);
if (!existing) {
struct option_set *new, **curr;
/* make a new option */
log2("Attaching option %02x to list", optflag->code);
new = xmalloc(sizeof(*new));
new->data = xmalloc(length + OPT_DATA);
new->data[OPT_CODE] = optflag->code;
new->data[OPT_LEN] = length;
memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length);
curr = opt_list;
while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
curr = &(*curr)->next;
new->next = *curr;
*curr = new;
goto ret;
}
if (optflag->flags & OPTION_LIST) {
unsigned old_len;
/* add it to an existing option */
log2("Attaching option %02x to existing member of list", optflag->code);
old_len = existing->data[OPT_LEN];
if (old_len + length < 255) {
/* actually 255 is ok too, but adding a space can overlow it */
existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING
|| (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST
) {
/* add space separator between STRING options in a list */
existing->data[OPT_DATA + old_len] = ' ';
old_len++;
}
memcpy(existing->data + OPT_DATA + old_len, (allocated ? allocated : buffer), length);
existing->data[OPT_LEN] = old_len + length;
} /* else, ignore the data, we could put this in a second option in the future */
} /* else, ignore the new data */
ret:
free(allocated);
}
/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip)
{
char hexstrbuf[16 * 2];
bin2hex(hexstrbuf, (void*)ip, 16);
return sprintf(dest, /* "%s" */
"%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
/* pre, */
hexstrbuf + 0 * 4,
hexstrbuf + 1 * 4,
hexstrbuf + 2 * 4,
hexstrbuf + 3 * 4,
hexstrbuf + 4 * 4,
hexstrbuf + 5 * 4,
hexstrbuf + 6 * 4,
hexstrbuf + 7 * 4
);
}

View File

@ -1,317 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Russ Dill <Russ.Dill@asu.edu> September 2001
* Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
#ifndef UDHCP_COMMON_H
#define UDHCP_COMMON_H 1
#include <netinet/udp.h>
#include <netinet/ip.h>
#include "extra.h"
extern const uint8_t MAC_BCAST_ADDR[6] ALIGN2; /* six all-ones */
/*** DHCP packet ***/
/* DHCP protocol. See RFC 2131 */
#define DHCP_MAGIC 0x63825363
#define DHCP_OPTIONS_BUFSIZE 308
#define BOOTREQUEST 1
#define BOOTREPLY 2
//TODO: rename ciaddr/yiaddr/chaddr
struct dhcp_packet {
uint8_t op; /* BOOTREQUEST or BOOTREPLY */
uint8_t htype; /* hardware address type. 1 = 10mb ethernet */
uint8_t hlen; /* hardware address length */
uint8_t hops; /* used by relay agents only */
uint32_t xid; /* unique id */
uint16_t secs; /* elapsed since client began acquisition/renewal */
uint16_t flags; /* only one flag so far: */
#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
uint32_t yiaddr; /* 'your' (client) IP address */
/* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
uint32_t siaddr_nip;
uint32_t gateway_nip; /* relay agent IP address */
uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */
uint8_t sname[64]; /* server host name (ASCIZ) */
uint8_t file[128]; /* boot file name (ASCIZ) */
uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */
uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
} PACKED;
#define DHCP_PKT_SNAME_LEN 64
#define DHCP_PKT_FILE_LEN 128
#define DHCP_PKT_SNAME_LEN_STR "64"
#define DHCP_PKT_FILE_LEN_STR "128"
struct ip_udp_dhcp_packet {
struct iphdr ip;
struct udphdr udp;
struct dhcp_packet data;
} PACKED;
struct udp_dhcp_packet {
struct udphdr udp;
struct dhcp_packet data;
} PACKED;
enum {
IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
UDP_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
};
/* Let's see whether compiler understood us right */
struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet {
char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1];
};
/*** Options ***/
enum {
OPTION_IP = 1,
OPTION_IP_PAIR,
OPTION_STRING,
/* Opts of STRING_HOST type will be sanitized before they are passed
* to udhcpc script's environment: */
OPTION_STRING_HOST,
// OPTION_BOOLEAN,
OPTION_U8,
OPTION_U16,
// OPTION_S16,
OPTION_U32,
OPTION_S32,
OPTION_BIN,
OPTION_STATIC_ROUTES,
OPTION_6RD,
#if ENABLE_FEATURE_UDHCP_RFC3397
OPTION_DNS_STRING, /* RFC1035 compressed domain name list */
OPTION_SIP_SERVERS,
#endif
OPTION_TYPE_MASK = 0x0f,
/* Client requests this option by default */
OPTION_REQ = 0x10,
/* There can be a list of 1 or more of these */
OPTION_LIST = 0x20,
};
/* DHCP option codes (partial list). See RFC 2132 and
* http://www.iana.org/assignments/bootp-dhcp-parameters/
* Commented out options are handled by common option machinery,
* uncommented ones have special cases (grep for them to see).
*/
#define DHCP_PADDING 0x00
#define DHCP_SUBNET 0x01
//#define DHCP_TIME_OFFSET 0x02 /* (localtime - UTC_time) in seconds. signed */
//#define DHCP_ROUTER 0x03
//#define DHCP_TIME_SERVER 0x04 /* RFC 868 time server (32-bit, 0 = 1.1.1900) */
//#define DHCP_NAME_SERVER 0x05 /* IEN 116 _really_ ancient kind of NS */
//#define DHCP_DNS_SERVER 0x06
//#define DHCP_LOG_SERVER 0x07 /* port 704 UDP log (not syslog)
//#define DHCP_COOKIE_SERVER 0x08 /* "quote of the day" server */
//#define DHCP_LPR_SERVER 0x09
#define DHCP_HOST_NAME 0x0c /* either client informs server or server gives name to client */
//#define DHCP_BOOT_SIZE 0x0d
//#define DHCP_DOMAIN_NAME 0x0f /* server gives domain suffix */
//#define DHCP_SWAP_SERVER 0x10
//#define DHCP_ROOT_PATH 0x11
//#define DHCP_IP_TTL 0x17
//#define DHCP_MTU 0x1a
//#define DHCP_BROADCAST 0x1c
//#define DHCP_ROUTES 0x21
//#define DHCP_NIS_DOMAIN 0x28
//#define DHCP_NIS_SERVER 0x29
//#define DHCP_NTP_SERVER 0x2a
//#define DHCP_WINS_SERVER 0x2c
#define DHCP_REQUESTED_IP 0x32 /* sent by client if specific IP is wanted */
#define DHCP_LEASE_TIME 0x33
#define DHCP_OPTION_OVERLOAD 0x34
#define DHCP_MESSAGE_TYPE 0x35
#define DHCP_SERVER_ID 0x36 /* by default server's IP */
#define DHCP_PARAM_REQ 0x37 /* list of options client wants */
//#define DHCP_ERR_MESSAGE 0x38 /* error message when sending NAK etc */
#define DHCP_MAX_SIZE 0x39
#define DHCP_VENDOR 0x3c /* client's vendor (a string) */
#define DHCP_CLIENT_ID 0x3d /* by default client's MAC addr, but may be arbitrarily long */
//#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */
//#define DHCP_BOOT_FILE 0x43 /* same as 'file' field */
//#define DHCP_USER_CLASS 0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */
#define DHCP_FQDN 0x51 /* client asks to update DNS to map its FQDN to its new IP */
//#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
//#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
//#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */
//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */
//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */
//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */
//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
//#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
#define DHCP_END 0xff
/* Offsets in option byte sequence */
#define OPT_CODE 0
#define OPT_LEN 1
#define OPT_DATA 2
/* Bits in "overload" option */
#define OPTION_FIELD 0
#define FILE_FIELD 1
#define SNAME_FIELD 2
/* DHCP_MESSAGE_TYPE values */
#define DHCPDISCOVER 1 /* client -> server */
#define DHCPOFFER 2 /* client <- server */
#define DHCPREQUEST 3 /* client -> server */
#define DHCPDECLINE 4 /* client -> server */
#define DHCPACK 5 /* client <- server */
#define DHCPNAK 6 /* client <- server */
#define DHCPRELEASE 7 /* client -> server */
#define DHCPINFORM 8 /* client -> server */
#define DHCP_MINTYPE DHCPDISCOVER
#define DHCP_MAXTYPE DHCPINFORM
struct dhcp_optflag {
uint8_t flags;
uint8_t code;
};
struct option_set {
uint8_t *data;
struct option_set *next;
};
extern const struct dhcp_optflag dhcp_optflags[];
extern const char dhcp_option_strings[] ALIGN1;
extern const uint8_t dhcp_option_lengths[] ALIGN1;
unsigned udhcp_option_idx(const char *name);
uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code);
int udhcp_end_option(uint8_t *optionptr);
void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt);
void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data);
#if ENABLE_FEATURE_UDHCP_RFC3397
char *dname_dec(const uint8_t *cstr, int clen, const char *pre);
uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen);
#endif
struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code);
// RFC 2131 Table 5: Fields and options used by DHCP clients
//
// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero
//
// Field DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
// ----- ------------ ------------ ----------- ----------- -----------
// 'xid' selected by client selected by client 'xid' from server selected by client selected by client
// DHCPOFFER message
// 'secs' 0 or seconds since 0 or seconds since 0 or seconds since 0 0
// DHCP process started DHCP process started DHCP process started
// 'flags' Set 'BROADCAST' Set 'BROADCAST' Set 'BROADCAST' 0 0
// flag if client flag if client flag if client
// requires broadcast requires broadcast requires broadcast
// reply reply reply
// 'ciaddr' 0 client's IP 0 or client's IP 0 client's IP
// (BOUND/RENEW/REBIND)
// 'chaddr' client's MAC client's MAC client's MAC client's MAC client's MAC
// 'sname' options or sname options or sname options or sname (unused) (unused)
// 'file' options or file options or file options or file (unused) (unused)
// 'options' options options options message type opt message type opt
//
// Option DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
// ------ ------------ ---------- ----------- ----------- -----------
// Requested IP address MAY MUST NOT MUST (in MUST MUST NOT
// SELECTING or
// INIT-REBOOT)
// MUST NOT (in
// BOUND or
// RENEWING)
// IP address lease time MAY MUST NOT MAY MUST NOT MUST NOT
// Use 'file'/'sname' fields MAY MAY MAY MAY MAY
// Client identifier MAY MAY MAY MAY MAY
// Vendor class identifier MAY MAY MAY MUST NOT MUST NOT
// Server identifier MUST NOT MUST NOT MUST (after MUST MUST
// SELECTING)
// MUST NOT (after
// INIT-REBOOT,
// BOUND, RENEWING
// or REBINDING)
// Parameter request list MAY MAY MAY MUST NOT MUST NOT
// Maximum message size MAY MAY MAY MUST NOT MUST NOT
// Message SHOULD NOT SHOULD NOT SHOULD NOT SHOULD SHOULD
// Site-specific MAY MAY MAY MUST NOT MUST NOT
// All others MAY MAY MAY MUST NOT MUST NOT
/*** Logging ***/
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
extern unsigned dhcp_verbose;
# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
# if CONFIG_UDHCP_DEBUG >= 2
void udhcp_dump_packet(struct dhcp_packet *packet);
# define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0)
# else
# define udhcp_dump_packet(...) ((void)0)
# define log2(...) ((void)0)
# endif
# if CONFIG_UDHCP_DEBUG >= 3
# define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0)
# else
# define log3(...) ((void)0)
# endif
#else
# define IF_UDHCP_VERBOSE(...)
# define udhcp_dump_packet(...) ((void)0)
# define log1(...) ((void)0)
# define log2(...) ((void)0)
# define log3(...) ((void)0)
#endif
/*** Other shared functions ***/
/* 2nd param is "uint32_t*" */
int udhcp_str2nip(const char *str, void *arg);
/* 2nd param is "struct option_set**" */
int udhcp_str2optset(const char *str, void *arg);
void udhcp_init_header(struct dhcp_packet *packet, char type);
int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd);
int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_nip, int source_port,
uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
int ifindex);
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_nip, int source_port,
uint32_t dest_nip, int dest_port);
void udhcp_sp_setup(void);
int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
int udhcp_sp_read(const fd_set *rfds);
int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac);
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf);
/* Returns 1 if no reply received */
int arpping(uint32_t test_nip,
const uint8_t *safe_mac,
uint32_t from_ip,
uint8_t *from_mac,
const char *interface);
/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */
int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,39 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
#include <stdint.h>
#ifndef UDHCP_DHCPC_H
#define UDHCP_DHCPC_H 1
int udhcpc_main(int pipefd, char *interface);
struct client_config_t {
uint8_t client_mac[6]; /* Our mac address */
int ifindex; /* Index number of the interface to use */
uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */
const char *interface; /* The name of the interface to use */
char *pidfile; /* Optionally store the process ID */
const char *script; /* User script to run at dhcp events */
struct option_set *options; /* list of DHCP options to send to server */
uint8_t *clientid; /* Optional client id to use */
uint8_t *vendorclass; /* Optional vendor class-id to use */
uint8_t *hostname; /* Optional hostname to use */
uint8_t *fqdn; /* Optional fully qualified domain name to use */
uint16_t first_secs;
uint16_t last_secs;
} FIX_ALIASING;
/* server_config sits in 1st half of bb_common_bufsiz1 */
//#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
extern struct client_config_t client_config;
#define CLIENT_PORT 68
#define CLIENT_PORT6 546
#define SERVER_PORT 67
#define SERVER_PORT6 547
#endif

View File

@ -1,128 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
#ifndef UDHCP_DHCPD_H
#define UDHCP_DHCPD_H 1
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
/* Defaults you may want to tweak */
/* Default max_lease_sec */
#define DEFAULT_LEASE_TIME (60*60*24 * 10)
#define LEASES_FILE CONFIG_DHCPD_LEASES_FILE
/* Where to find the DHCP server configuration file */
#define DHCPD_CONF_FILE "/etc/udhcpd.conf"
struct static_lease {
struct static_lease *next;
uint32_t nip;
uint8_t mac[6];
};
struct server_config_t {
char *interface; /* interface to use */
//TODO: ifindex, server_nip, server_mac
// are obtained from interface name.
// Instead of querying them *once*, create update_server_network_data_cache()
// and call it before any usage of these fields.
// update_server_network_data_cache() must re-query data
// if more than N seconds have passed after last use.
int ifindex;
uint32_t server_nip;
#if ENABLE_FEATURE_UDHCP_PORT
uint16_t port;
#endif
uint8_t server_mac[6]; /* our MAC address (used only for ARP probing) */
struct option_set *options; /* list of DHCP options loaded from the config file */
/* start,end are in host order: we need to compare start <= ip <= end */
uint32_t start_ip; /* start address of leases, in host order */
uint32_t end_ip; /* end of leases, in host order */
uint32_t max_lease_sec; /* maximum lease time (host order) */
uint32_t min_lease_sec; /* minimum lease time a client can request */
uint32_t max_leases; /* maximum number of leases (including reserved addresses) */
uint32_t auto_time; /* how long should udhcpd wait before writing a config file.
* if this is zero, it will only write one on SIGUSR1 */
uint32_t decline_time; /* how long an address is reserved if a client returns a
* decline message */
uint32_t conflict_time; /* how long an arp conflict offender is leased for */
uint32_t offer_time; /* how long an offered address is reserved */
uint32_t siaddr_nip; /* "next server" bootp option */
char *lease_file;
char *pidfile;
char *notify_file; /* what to run whenever leases are written */
char *sname; /* bootp server name */
char *boot_file; /* bootp boot file option */
struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
} FIX_ALIASING;
#define server_config (*(struct server_config_t*)&bb_common_bufsiz1)
/* client_config sits in 2nd half of bb_common_bufsiz1 */
#if ENABLE_FEATURE_UDHCP_PORT
#define SERVER_PORT (server_config.port)
#define SERVER_PORT6 (server_config.port)
#else
#define SERVER_PORT 67
#define SERVER_PORT6 547
#endif
typedef uint32_t leasetime_t;
typedef int32_t signed_leasetime_t;
struct dyn_lease {
/* Unix time when lease expires. Kept in memory in host order.
* When written to file, converted to network order
* and adjusted (current time subtracted) */
leasetime_t expires;
/* "nip": IP in network order */
uint32_t lease_nip;
/* We use lease_mac[6], since e.g. ARP probing uses
* only 6 first bytes anyway. We check received dhcp packets
* that their hlen == 6 and thus chaddr has only 6 significant bytes
* (dhcp packet has chaddr[16], not [6])
*/
uint8_t lease_mac[6];
char hostname[20];
uint8_t pad[2];
/* total size is a multiply of 4 */
} PACKED;
extern struct dyn_lease *g_leases;
struct dyn_lease *add_lease(
const uint8_t *chaddr, uint32_t yiaddr,
leasetime_t leasetime,
const char *hostname, int hostname_len
);
int is_expired_lease(struct dyn_lease *lease) FAST_FUNC;
struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC;
struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC;
uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC;
/* Config file parser will pass static lease info to this function
* which will add it to a data structure that can be searched later */
void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, uint32_t nip) FAST_FUNC;
/* Find static lease IP by mac */
uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *arg) FAST_FUNC;
/* Check to see if an IP is reserved as a static IP */
int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC;
/* Print out static leases just to check what's going on (debug code) */
#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
void log_static_leases(struct static_lease **st_lease_pp) FAST_FUNC;
#else
# define log_static_leases(st_lease_pp) ((void)0)
#endif
void read_config(const char *file) FAST_FUNC;
void write_leases(void) FAST_FUNC;
void read_leases(const char *file) FAST_FUNC;
POP_SAVED_FUNCTION_VISIBILITY
#endif

View File

@ -1,499 +0,0 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <time.h>
#include "extra.h"
const int const_int_1 = 1;
const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF";
void xpipe(int filedes[2]) {
if (pipe(filedes)) {
fprintf (stderr, "can't create pipe");
exit (EXIT_FAILURE);
}
}
void bb_signals(int sigs, void (*f)(int)) {
int sig_no = 0;
int bit = 1;
while (sigs) {
if (sigs & bit) {
sigs -= bit;
signal(sig_no, f);
}
sig_no++;
bit <<= 1;
}
}
void close_on_exec_on(int fd) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
/* Turn on nonblocking I/O on a fd */
void ndelay_on(int fd) {
int flags = fcntl(fd, F_GETFL);
if (flags & O_NONBLOCK)
return;
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
void ndelay_off(int fd) {
int flags = fcntl(fd, F_GETFL);
if (!(flags & O_NONBLOCK))
return;
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}
// Die if we can't copy a string to freshly allocated memory.
char* xstrdup(const char *s)
{
char *t;
if (s == NULL)
return NULL;
t = strdup(s);
if (t == NULL) {
fprintf (stderr, "Memory allocation failed");
exit (EXIT_FAILURE);
}
return t;
}
char* hex2bin(char *dst, const char *str, int count)
{
errno = EINVAL;
while (*str && count) {
uint8_t val;
uint8_t c = *str++;
if (isdigit(c))
val = c - '0';
else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
val = (c|0x20) - ('a' - 10);
else
return NULL;
val <<= 4;
c = *str;
if (isdigit(c))
val |= c - '0';
else if ((c|0x20) >= 'a' && (c|0x20) <= 'f')
val |= (c|0x20) - ('a' - 10);
else if (c == ':' || c == '\0')
val >>= 4;
else
return NULL;
*dst++ = val;
if (c != '\0')
str++;
if (*str == ':')
str++;
count--;
}
errno = (*str ? ERANGE : 0);
return dst;
}
#define DIE_ON_ERROR AI_CANONNAME
/* host: "1.2.3.4[:port]", "www.google.com[:port]"
* port: if neither of above specifies port # */
static len_and_sockaddr* str2sockaddr(
const char *host, int port,
sa_family_t af,
int ai_flags)
{
int rc;
len_and_sockaddr *r;
struct addrinfo *result = NULL;
struct addrinfo *used_res;
const char *org_host = host; /* only for error msg */
const char *cp;
struct addrinfo hint;
r = NULL;
/* Ugly parsing of host:addr */
if (host[0] == '[') {
/* Even uglier parsing of [xx]:nn */
host++;
cp = strchr(host, ']');
if (!cp || (cp[1] != ':' && cp[1] != '\0')) {
/* Malformed: must be [xx]:nn or [xx] */
fprintf(stderr, "bad address '%s'", org_host);
if (ai_flags & DIE_ON_ERROR) {
exit (EXIT_FAILURE);
}
return NULL;
}
} else {
cp = strrchr(host, ':');
if (cp && strchr(host, ':') != cp) {
/* There is more than one ':' (e.g. "::1") */
cp = NULL; /* it's not a port spec */
}
}
if (cp) { /* points to ":" or "]:" */
int sz = cp - host + 1;
host = safe_strncpy(alloca(sz), host, sz);
if (*cp != ':') {
cp++; /* skip ']' */
if (*cp == '\0') /* [xx] without port */
goto skip;
}
cp++; /* skip ':' */
port = bb_strtou(cp, NULL, 10);
if (errno || (unsigned)port > 0xffff) {
fprintf(stderr, "bad port spec '%s'", org_host);
if (ai_flags & DIE_ON_ERROR) {
exit (EXIT_FAILURE);
}
return NULL;
}
skip: ;
}
/* Next two if blocks allow to skip getaddrinfo()
* in case host name is a numeric IP(v6) address.
* getaddrinfo() initializes DNS resolution machinery,
* scans network config and such - tens of syscalls.
*/
/* If we were not asked specifically for IPv6,
* check whether this is a numeric IPv4 */
if(af != AF_INET6) {
struct in_addr in4;
if (inet_aton(host, &in4) != 0) {
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in));
r->len = sizeof(struct sockaddr_in);
r->u.sa.sa_family = AF_INET;
r->u.sin.sin_addr = in4;
goto set_port;
}
}
/* If we were not asked specifically for IPv4,
* check whether this is a numeric IPv6 */
if (af != AF_INET) {
struct in6_addr in6;
if (inet_pton(AF_INET6, host, &in6) > 0) {
r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_in6));
r->len = sizeof(struct sockaddr_in6);
r->u.sa.sa_family = AF_INET6;
r->u.sin6.sin6_addr = in6;
goto set_port;
}
}
memset(&hint, 0 , sizeof(hint));
hint.ai_family = af;
/* Need SOCK_STREAM, or else we get each address thrice (or more)
* for each possible socket type (tcp,udp,raw...): */
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = ai_flags & ~DIE_ON_ERROR;
rc = getaddrinfo(host, NULL, &hint, &result);
if (rc || !result) {
fprintf (stderr, "bad address '%s'", org_host);
if (ai_flags & DIE_ON_ERROR) {
exit (EXIT_FAILURE);
}
goto ret;
}
used_res = result;
r = xmalloc(LSA_LEN_SIZE + used_res->ai_addrlen);
r->len = used_res->ai_addrlen;
memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen);
set_port:
set_nport(&r->u.sa, htons(port));
ret:
if (result)
freeaddrinfo(result);
return r;
}
len_and_sockaddr* host2sockaddr(const char *host, int port) {
return str2sockaddr(host, port, AF_UNSPEC, 0);
}
len_and_sockaddr* xhost2sockaddr(const char *host, int port) {
return str2sockaddr(host, port, AF_UNSPEC, DIE_ON_ERROR);
}
void* xmalloc(size_t size) {
void *ptr = malloc(size);
if (ptr == NULL && size != 0) {
fprintf (stderr, "Memory allocation failed");
exit (EXIT_FAILURE);
}
return ptr;
}
void set_nport(struct sockaddr *sa, unsigned port)
{
if (sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (void*) sa;
sin6->sin6_port = port;
return;
}
if (sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (void*) sa;
sin->sin_port = port;
return;
}
/* What? UNIX socket? IPX?? :) */
}
int xsocket(int domain, int type, int protocol) {
int r = socket(domain, type, protocol);
if (r < 0) {
/* Hijack vaguely related config option */
const char *s = "INET";
# ifdef AF_PACKET
if (domain == AF_PACKET) s = "PACKET";
# endif
# ifdef AF_NETLINK
if (domain == AF_NETLINK) s = "NETLINK";
# endif
if (domain == AF_INET6) s = "INET6";
fprintf (stderr, "Error socket (AF_%s,%d,%d)", s, type, protocol);
exit (EXIT_FAILURE);
}
return r;
}
// Die with an error message if we can't bind a socket to an address.
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) {
if (bind(sockfd, my_addr, addrlen)) {
fprintf (stderr, "Error: bind");
exit (EXIT_FAILURE);
}
}
int ioctl_or_perror(int fd, unsigned request, void *argp) {
va_list p;
int ret = ioctl(fd, request, argp);
if (ret < 0) {
perror ("Error ioctl");
}
return ret;
}
/* Like strncpy but make sure the resulting string is always 0 terminated. */
char* safe_strncpy(char *dst, const char *src, size_t size) {
if (!size) return dst;
dst[--size] = '\0';
return strncpy(dst, src, size);
}
/* Like strcpy but can copy overlapping strings. */
void overlapping_strcpy(char *dst, const char *src) {
/* Cheap optimization for dst == src case -
* better to have it here than in many callers.
*/
if (dst != src) {
while ((*dst = *src) != '\0') {
dst++;
src++;
}
}
}
// Die if we can't allocate and zero size bytes of memory.
void* xzalloc(size_t size) {
void *ptr = xmalloc(size);
memset(ptr, 0, size);
return ptr;
}
void* xrealloc(void *ptr, size_t size) {
ptr = realloc(ptr, size);
if (ptr == NULL && size != 0) {
fprintf (stderr, "Memory allocation failed");
exit (EXIT_FAILURE);
}
return ptr;
}
ssize_t safe_read(int fd, void *buf, size_t count) {
ssize_t n;
do {
n = read(fd, buf, count);
} while (n < 0 && errno == EINTR);
return n;
}
uint16_t inet_cksum(uint16_t *addr, int nleft) {
/*
* Our algorithm is simple, using a 32 bit accumulator,
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
unsigned sum = 0;
while (nleft > 1) {
sum += *addr++;
nleft -= 2;
}
/* Mop up an odd byte, if necessary */
if (nleft == 1) {
if (BB_LITTLE_ENDIAN)
sum += *(uint8_t*)addr;
else
sum += *(uint8_t*)addr << 8;
}
/* Add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
return (uint16_t)~sum;
}
/* Emit a string of hex representation of bytes */
char* bin2hex(char *p, const char *cp, int count) {
while (count) {
unsigned char c = *cp++;
/* put lowercase hex digits */
*p++ = 0x20 | bb_hexdigits_upcase[c >> 4];
*p++ = 0x20 | bb_hexdigits_upcase[c & 0xf];
count--;
}
return p;
}
char* xasprintf(const char *format, ...) {
va_list p;
int r;
char *string_ptr;
va_start(p, format);
r = vasprintf(&string_ptr, format, p);
va_end(p);
if (r < 0) {
fprintf (stderr, "Memory allocation failed");
exit (EXIT_FAILURE);
}
return string_ptr;
}
static unsigned long long ret_ERANGE(void)
{
errno = ERANGE; /* this ain't as small as it looks (on glibc) */
return ULLONG_MAX;
}
static unsigned long long handle_errors(unsigned long long v, char **endp)
{
char next_ch = **endp;
/* errno is already set to ERANGE by strtoXXX if value overflowed */
if (next_ch) {
/* "1234abcg" or out-of-range? */
if (isalnum(next_ch) || errno)
return ret_ERANGE();
/* good number, just suspicious terminator */
errno = EINVAL;
}
return v;
}
unsigned bb_strtou(const char *arg, char **endp, int base) {
unsigned long v;
char *endptr;
if (!endp) endp = &endptr;
*endp = (char*) arg;
if (!isalnum(arg[0])) return ret_ERANGE();
errno = 0;
v = strtoul(arg, endp, base);
if (v > UINT_MAX) return ret_ERANGE();
return handle_errors(v, endp);
}
char* strncpy_IFNAMSIZ(char *dst, const char *src) {
#ifndef IFNAMSIZ
enum { IFNAMSIZ = 16 };
#endif
return strncpy(dst, src, IFNAMSIZ);
}
void setsockopt_reuseaddr(int fd) {
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1));
}
int setsockopt_broadcast(int fd) {
return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &const_int_1, sizeof(const_int_1));
}
#ifdef SO_BINDTODEVICE
int setsockopt_bindtodevice(int fd, const char *iface) {
int r;
struct ifreq ifr;
strncpy_IFNAMSIZ(ifr.ifr_name, iface);
/* NB: passing (iface, strlen(iface) + 1) does not work!
* (maybe it works on _some_ kernels, but not on 2.6.26)
* Actually, ifr_name is at offset 0, and in practice
* just giving char[IFNAMSIZ] instead of struct ifreq works too.
* But just in case it's not true on some obscure arch... */
r = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
if (r)
fprintf (stderr, "can't bind to interface %s", iface);
return r;
}
#else
int setsockopt_bindtodevice(int fd, const char *iface) {
fprintf (stderr, "SO_BINDTODEVICE is not supported on this system");
return -1;
}
#endif
unsigned monotonic_sec(void) {
return time(NULL);
}
ssize_t safe_write(int fd, const void *buf, size_t count) {
ssize_t n;
do {
n = write(fd, buf, count);
} while (n < 0 && errno == EINTR);
return n;
}

View File

@ -1,198 +0,0 @@
#ifndef __EXTRA_H__
#define __EXTRA_H__ 1
#include <netinet/in.h>
#include <stddef.h>
/* In this form code with pipes is much more readable */
struct fd_pair { int rd; int wr; };
#define piped_pair(pair) pipe(&((pair).rd))
#define xpiped_pair(pair) xpipe(&((pair).rd))
#define ALIGN1 __attribute__((aligned(1)))
#define ALIGN2 __attribute__((aligned(2)))
#define PACKED __attribute__ ((__packed__))
#define ALIGNED(m) __attribute__ ((__aligned__(m)))
#define NOINLINE __attribute__((__noinline__))
#define CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS 80
#define host_and_af2sockaddr(host, port, af) host2sockaddr((host), (port))
#define xhost_and_af2sockaddr(host, port, af) xhost2sockaddr((host), (port))
/* ---- Endian Detection ------------------------------------ */
#include <limits.h>
#if defined(__digital__) && defined(__unix__)
# include <sex.h>
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__APPLE__)
# include <sys/resource.h> /* rlimit */
# include <machine/endian.h>
# define bswap_64 __bswap64
# define bswap_32 __bswap32
# define bswap_16 __bswap16
#else
# include <byteswap.h>
# include <endian.h>
#endif
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
# define BB_BIG_ENDIAN 1
# define BB_LITTLE_ENDIAN 0
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#elif defined(__386__)
# define BB_BIG_ENDIAN 0
# define BB_LITTLE_ENDIAN 1
#else
# error "Can't determine endianness"
#endif
#if ULONG_MAX > 0xffffffff
# define bb_bswap_64(x) bswap_64(x)
#endif
/* SWAP_LEnn means "convert CPU<->little_endian by swapping bytes" */
#if BB_BIG_ENDIAN
# define SWAP_BE16(x) (x)
# define SWAP_BE32(x) (x)
# define SWAP_BE64(x) (x)
# define SWAP_LE16(x) bswap_16(x)
# define SWAP_LE32(x) bswap_32(x)
# define SWAP_LE64(x) bb_bswap_64(x)
# define IF_BIG_ENDIAN(...) __VA_ARGS__
# define IF_LITTLE_ENDIAN(...)
#else
# define SWAP_BE16(x) bswap_16(x)
# define SWAP_BE32(x) bswap_32(x)
# define SWAP_BE64(x) bb_bswap_64(x)
# define SWAP_LE16(x) (x)
# define SWAP_LE32(x) (x)
# define SWAP_LE64(x) (x)
# define IF_BIG_ENDIAN(...)
# define IF_LITTLE_ENDIAN(...) __VA_ARGS__
#endif
/* At 4.4 gcc become much more anal about this, need to use "aliased" types */
#if __GNUC_PREREQ(4,4)
# define FIX_ALIASING __attribute__((__may_alias__))
#else
# define FIX_ALIASING
#endif
/* ---- Unaligned access ------------------------------------ */
#include <stdint.h>
typedef int bb__aliased_int FIX_ALIASING;
typedef long bb__aliased_long FIX_ALIASING;
typedef uint16_t bb__aliased_uint16_t FIX_ALIASING;
typedef uint32_t bb__aliased_uint32_t FIX_ALIASING;
typedef uint64_t bb__aliased_uint64_t FIX_ALIASING;
/* NB: unaligned parameter should be a pointer, aligned one -
* a lvalue. This makes it more likely to not swap them by mistake
*/
#if defined(i386) || defined(__x86_64__) || defined(__powerpc__)
# define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp))
# define move_from_unaligned_long(v, longp) ((v) = *(bb__aliased_long*)(longp))
# define move_from_unaligned16(v, u16p) ((v) = *(bb__aliased_uint16_t*)(u16p))
# define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p))
# define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v))
# define move_to_unaligned32(u32p, v) (*(bb__aliased_uint32_t*)(u32p) = (v))
/* #elif ... - add your favorite arch today! */
#else
/* performs reasonably well (gcc usually inlines memcpy here) */
# define move_from_unaligned_int(v, intp) (memcpy(&(v), (intp), sizeof(int)))
# define move_from_unaligned_long(v, longp) (memcpy(&(v), (longp), sizeof(long)))
# define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2))
# define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4))
# define move_to_unaligned16(u16p, v) do { \
uint16_t __t = (v); \
memcpy((u16p), &__t, 2); \
} while (0)
# define move_to_unaligned32(u32p, v) do { \
uint32_t __t = (v); \
memcpy((u32p), &__t, 4); \
} while (0)
#endif
#if defined(i386) || defined(__x86_64__) || defined(__mips__) || defined(__cris__)
/* add other arches which benefit from this... */
typedef signed char smallint;
typedef unsigned char smalluint;
#else
/* for arches where byte accesses generate larger code: */
typedef int smallint;
typedef unsigned smalluint;
#endif
extern const int const_int_1;
typedef struct len_and_sockaddr {
socklen_t len;
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} u;
} len_and_sockaddr;
enum {
LSA_LEN_SIZE = offsetof(len_and_sockaddr, u),
LSA_SIZEOF_SA = sizeof(
union {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
}
)
};
void bb_signals(int sigs, void (*f)(int));
void close_on_exec_on(int fd);
void xpipe(int filedes[2]);
void ndelay_on(int fd);
void ndelay_off(int fd);
char* xstrdup(const char *s);
char* hex2bin(char *dst, const char *str, int count);
char* bin2hex(char *p, const char *cp, int count);
len_and_sockaddr* host2sockaddr(const char *host, int port);
len_and_sockaddr* xhost2sockaddr(const char *host, int port);
void* xmalloc(size_t size);
void set_nport(struct sockaddr *sa, unsigned port);
int xsocket(int domain, int type, int protocol);
void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
int ioctl_or_perror(int fd, unsigned request, void *argp);
char* safe_strncpy(char *dst, const char *src, size_t size);
void overlapping_strcpy(char *dst, const char *src);
void* xzalloc(size_t size);
void* xrealloc(void *ptr, size_t size);
ssize_t safe_read(int fd, void *buf, size_t count);
ssize_t safe_write(int fd, const void *buf, size_t count);
uint16_t inet_cksum(uint16_t *addr, int nleft);
char* xasprintf(const char *format, ...);
unsigned bb_strtou(const char *arg, char **endp, int base);
char* strncpy_IFNAMSIZ(char *dst, const char *src);
void setsockopt_reuseaddr(int fd);
int setsockopt_broadcast(int fd);
int setsockopt_bindtodevice(int fd, const char *iface);
unsigned monotonic_sec(void);
#endif

View File

@ -1,40 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "dhcpc.h"
int main (int argc, char *argv[]) {
/* Preparar el pipe que viene en STDOUT */
int pipe;
int null_fd;
pipe = dup (STDOUT_FILENO);
null_fd = open ("/dev/null", O_RDWR);
close (STDOUT_FILENO);
close (STDIN_FILENO);
dup2 (null_fd, STDOUT_FILENO);
dup2 (null_fd, STDIN_FILENO);
close (null_fd);
/* Parsear aquí los argumentos */
if (argc < 2) {
fprintf (stderr, "Missing interface argument");
return EXIT_FAILURE;
}
udhcpc_main (pipe, argv[1]);
close (STDOUT_FILENO);
return 0;
}

View File

@ -1,194 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Packet ops
*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netpacket/packet.h>
void udhcp_init_header(struct dhcp_packet *packet, char type)
{
memset(packet, 0, sizeof(*packet));
packet->op = BOOTREQUEST; /* if client to a server */
switch (type) {
case DHCPOFFER:
case DHCPACK:
case DHCPNAK:
packet->op = BOOTREPLY; /* if server to client */
}
packet->htype = 1; /* ethernet */
packet->hlen = 6;
packet->cookie = htonl(DHCP_MAGIC);
if (DHCP_END != 0)
packet->options[0] = DHCP_END;
udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
}
/* Read a packet from socket fd, return -1 on read error, -2 on packet error */
int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
{
int bytes;
memset(packet, 0, sizeof(*packet));
bytes = safe_read(fd, packet, sizeof(*packet));
if (bytes < 0) {
log1("Packet read error, ignoring");
return bytes; /* returns -1 */
}
if (bytes < offsetof(struct dhcp_packet, options)
|| packet->cookie != htonl(DHCP_MAGIC)
) {
fprintf (stderr, "Packet with bad magic, ignoring");
return -2;
}
log1("Received a packet");
udhcp_dump_packet(packet);
return bytes;
}
/* Construct a ip/udp header for a packet, send packet */
int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_nip, int source_port,
uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
int ifindex)
{
struct sockaddr_ll dest_sll;
struct ip_udp_dhcp_packet packet;
unsigned padding;
int fd;
int result = -1;
const char *msg;
fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
if (fd < 0) {
msg = "socket(%s)";
goto ret_msg;
}
memset(&dest_sll, 0, sizeof(dest_sll));
memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
packet.data = *dhcp_pkt; /* struct copy */
dest_sll.sll_family = AF_PACKET;
dest_sll.sll_protocol = htons(ETH_P_IP);
dest_sll.sll_ifindex = ifindex;
dest_sll.sll_halen = 6;
memcpy(dest_sll.sll_addr, dest_arp, 6);
if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
msg = "bind(%s)";
goto ret_close;
}
/* We were sending full-sized DHCP packets (zero padded),
* but some badly configured servers were seen dropping them.
* Apparently they drop all DHCP packets >576 *ethernet* octets big,
* whereas they may only drop packets >576 *IP* octets big
* (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
*
* In order to work with those buggy servers,
* we truncate packets after end option byte.
*
* However, RFC 1542 says "The IP Total Length and UDP Length
* must be large enough to contain the minimal BOOTP header of 300 octets".
* Thus, we retain enough padding to not go below 300 BOOTP bytes.
* Some devices have filters which drop DHCP packets shorter than that.
*/
padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
if (padding > DHCP_SIZE - 300)
padding = DHCP_SIZE - 300;
packet.ip.protocol = IPPROTO_UDP;
packet.ip.saddr = source_nip;
packet.ip.daddr = dest_nip;
packet.udp.source = htons(source_port);
packet.udp.dest = htons(dest_port);
/* size, excluding IP header: */
packet.udp.len = htons(UDP_DHCP_SIZE - padding);
/* for UDP checksumming, ip.len is set to UDP packet len */
packet.ip.tot_len = packet.udp.len;
packet.udp.check = inet_cksum((uint16_t *)&packet,
IP_UDP_DHCP_SIZE - padding);
/* but for sending, it is set to IP packet len */
packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
packet.ip.ihl = sizeof(packet.ip) >> 2;
packet.ip.version = IPVERSION;
packet.ip.ttl = IPDEFTTL;
packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip));
udhcp_dump_packet(dhcp_pkt);
result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
(struct sockaddr *) &dest_sll, sizeof(dest_sll));
msg = "sendto";
ret_close:
close(fd);
if (result < 0) {
ret_msg:
fprintf(stderr, msg, "PACKET");
}
return result;
}
/* Let the kernel do all the work for packet generation */
int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
uint32_t source_nip, int source_port,
uint32_t dest_nip, int dest_port)
{
struct sockaddr_in sa;
unsigned padding;
int fd;
int result = -1;
const char *msg;
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
msg = "socket(%s)";
goto ret_msg;
}
setsockopt_reuseaddr(fd);
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(source_port);
sa.sin_addr.s_addr = source_nip;
if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
msg = "bind(%s)";
goto ret_close;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(dest_port);
sa.sin_addr.s_addr = dest_nip;
if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
msg = "connect";
goto ret_close;
}
udhcp_dump_packet(dhcp_pkt);
padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
if (padding > DHCP_SIZE - 300)
padding = DHCP_SIZE - 300;
result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
msg = "write";
ret_close:
close(fd);
if (result < 0) {
ret_msg:
fprintf(stderr, msg, "UDP");
}
return result;
}

View File

@ -1,86 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* Signal pipe infrastructure. A reliable way of delivering signals.
*
* Russ Dill <Russ.Dill@asu.edu> December 2003
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "common.h"
#include "extra.h"
/* Global variable: we access it from signal handler */
static struct fd_pair signal_pipe;
static void signal_handler(int sig)
{
unsigned char ch = sig; /* use char, avoid dealing with partial writes */
if (write(signal_pipe.wr, &ch, 1) != 1) {
fprintf (stderr, "can't send signal");
}
}
/* Call this before doing anything else. Sets up the socket pair
* and installs the signal handler */
void udhcp_sp_setup(void)
{
/* was socketpair, but it needs AF_UNIX in kernel */
xpiped_pair(signal_pipe);
close_on_exec_on(signal_pipe.rd);
close_on_exec_on(signal_pipe.wr);
ndelay_on(signal_pipe.wr);
bb_signals(0
+ (1 << SIGUSR1)
+ (1 << SIGUSR2)
+ (1 << SIGTERM)
, signal_handler);
}
/* Quick little function to setup the rfds. Will return the
* max_fd for use with select. Limited in that you can only pass
* one extra fd */
int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
{
FD_ZERO(rfds);
FD_SET(signal_pipe.rd, rfds);
if (extra_fd >= 0) {
close_on_exec_on(extra_fd);
FD_SET(extra_fd, rfds);
}
return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd;
}
/* Read a signal from the signal pipe. Returns 0 if there is
* no signal, -1 on error (and sets errno appropriately), and
* your signal on success */
int udhcp_sp_read(const fd_set *rfds)
{
unsigned char sig;
if (!FD_ISSET(signal_pipe.rd, rfds))
return 0;
if (safe_read(signal_pipe.rd, &sig, 1) != 1)
return -1;
return sig;
}

View File

@ -1,122 +0,0 @@
/* vi: set sw=4 ts=4: */
/*
* DHCP server client/server socket creation
*
* udhcp client/server
* Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
* Chris Trew <ctrew@moreton.com.au>
*
* Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "extra.h"
#include "common.h"
int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac)
{
/* char buffer instead of bona-fide struct avoids aliasing warning */
char ifr_buf[sizeof(struct ifreq)];
struct ifreq *const ifr = (void *)ifr_buf;
int fd;
struct sockaddr_in *our_ip;
memset(ifr, 0, sizeof(*ifr));
fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
ifr->ifr_addr.sa_family = AF_INET;
strncpy_IFNAMSIZ(ifr->ifr_name, interface);
if (nip) {
if (ioctl_or_perror(fd, SIOCGIFADDR, ifr)
) {
close(fd);
return -1;
}
our_ip = (struct sockaddr_in *) &ifr->ifr_addr;
*nip = our_ip->sin_addr.s_addr;
log1("IP %s", inet_ntoa(our_ip->sin_addr));
}
if (ifindex) {
if (ioctl_or_perror(fd, SIOCGIFINDEX, ifr) != 0) {
close(fd);
return -1;
}
log1("Adapter index %d", ifr->ifr_ifindex);
*ifindex = ifr->ifr_ifindex;
}
if (mac) {
if (ioctl_or_perror(fd, SIOCGIFHWADDR, ifr) != 0) {
close(fd);
return -1;
}
memcpy(mac, ifr->ifr_hwaddr.sa_data, 6);
log1("MAC %02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
close(fd);
return 0;
}
/* 1. None of the callers expects it to ever fail */
/* 2. ip was always INADDR_ANY */
int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
{
int fd;
struct sockaddr_in addr;
char *colon;
log1("Opening listen socket on *:%d %s", port, inf);
fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
setsockopt_reuseaddr(fd);
if (setsockopt_broadcast(fd) == -1) {
fprintf (stderr, "SO_BROADCAST");
exit (EXIT_FAILURE);
}
/* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
colon = strrchr(inf, ':');
if (colon)
*colon = '\0';
if (setsockopt_bindtodevice(fd, inf)) {
exit (EXIT_FAILURE); /* warning is already printed */
}
if (colon)
*colon = ':';
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
/* addr.sin_addr.s_addr = ip; - all-zeros is INADDR_ANY */
xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
return fd;
}

View File

@ -1,292 +0,0 @@
/* Convenience header for conditional use of GNU <libintl.h>.
Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2016 Free Software
Foundation, Inc.
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include <libintl.h>
/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by
the gettext() and ngettext() macros. This is an alternative to calling
textdomain(), and is useful for libraries. */
# ifdef DEFAULT_TEXT_DOMAIN
# undef gettext
# define gettext(Msgid) \
dgettext (DEFAULT_TEXT_DOMAIN, Msgid)
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \
dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N)
# endif
#else
/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
chokes if dcgettext is defined as a macro. So include it now, to make
later inclusions of <locale.h> a NOP. We don't include <libintl.h>
as well because people using "gettext.h" will not include <libintl.h>,
and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
is OK. */
#if defined(__sun)
# include <locale.h>
#endif
/* Many header files from the libstdc++ coming with g++ 3.3 or newer include
<libintl.h>, which chokes if dcgettext is defined as a macro. So include
it now, to make later inclusions of <libintl.h> a NOP. */
#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3)
# include <cstdlib>
# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H
# include <libintl.h>
# endif
#endif
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
# undef gettext
# define gettext(Msgid) ((const char *) (Msgid))
# undef dgettext
# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
# undef dcgettext
# define dcgettext(Domainname, Msgid, Category) \
((void) (Category), dgettext (Domainname, Msgid))
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 \
? ((void) (Msgid2), (const char *) (Msgid1)) \
: ((void) (Msgid1), (const char *) (Msgid2)))
# undef dngettext
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((void) (Domainname), ngettext (Msgid1, Msgid2, N))
# undef dcngettext
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N))
# undef textdomain
# define textdomain(Domainname) ((const char *) (Domainname))
# undef bindtextdomain
# define bindtextdomain(Domainname, Dirname) \
((void) (Domainname), (const char *) (Dirname))
# undef bind_textdomain_codeset
# define bind_textdomain_codeset(Domainname, Codeset) \
((void) (Domainname), (const char *) (Codeset))
#endif
/* Prefer gnulib's setlocale override over libintl's setlocale override. */
#ifdef GNULIB_defined_setlocale
# undef setlocale
# define setlocale rpl_setlocale
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
/* The separator between msgctxt and msgid in a .mo file. */
#define GETTEXT_CONTEXT_GLUE "\004"
/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a
MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be
short and rarely need to change.
The letter 'p' stands for 'particular' or 'special'. */
#ifdef DEFAULT_TEXT_DOMAIN
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#else
# define pgettext(Msgctxt, Msgid) \
pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#endif
#define dpgettext(Domainname, Msgctxt, Msgid) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES)
#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \
pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category)
#ifdef DEFAULT_TEXT_DOMAIN
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#else
# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#endif
#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \
npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
pgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
int category)
{
const char *translation = dcgettext (domain, msg_ctxt_id, category);
if (translation == msg_ctxt_id)
return msgid;
else
return translation;
}
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
npgettext_aux (const char *domain,
const char *msg_ctxt_id, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
const char *translation =
dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
if (translation == msg_ctxt_id || translation == msgid_plural)
return (n == 1 ? msgid : msgid_plural);
else
return translation;
}
/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID
can be arbitrary expressions. But for string literals these macros are
less efficient than those above. */
#include <string.h>
#if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \
/* || __STDC_VERSION__ >= 199901L */ )
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1
#else
# define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0
#endif
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
#include <stdlib.h>
#endif
#define pgettext_expr(Msgctxt, Msgid) \
dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES)
#define dpgettext_expr(Domainname, Msgctxt, Msgid) \
dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcgettext (domain, msg_ctxt_id, category);
found_translation = (translation != msg_ctxt_id);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (found_translation)
return translation;
}
return msgid;
}
#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \
dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES)
#ifdef __GNUC__
__inline
#else
#ifdef __cplusplus
inline
#endif
#endif
static const char *
dcnpgettext_expr (const char *domain,
const char *msgctxt, const char *msgid,
const char *msgid_plural, unsigned long int n,
int category)
{
size_t msgctxt_len = strlen (msgctxt) + 1;
size_t msgid_len = strlen (msgid) + 1;
const char *translation;
#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
char msg_ctxt_id[msgctxt_len + msgid_len];
#else
char buf[1024];
char *msg_ctxt_id =
(msgctxt_len + msgid_len <= sizeof (buf)
? buf
: (char *) malloc (msgctxt_len + msgid_len));
if (msg_ctxt_id != NULL)
#endif
{
int found_translation;
memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1);
msg_ctxt_id[msgctxt_len - 1] = '\004';
memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len);
translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category);
found_translation = !(translation == msg_ctxt_id || translation == msgid_plural);
#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS
if (msg_ctxt_id != buf)
free (msg_ctxt_id);
#endif
if (found_translation)
return translation;
}
return (n == 1 ? msgid : msgid_plural);
}
#endif /* _LIBGETTEXT_H */

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
* interfaces.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - Félix Arreola Rodríguez
* Copyright (C) 2019, 2020 - 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
@ -23,28 +23,17 @@
#ifndef __INTERFACES_H__
#define __INTERFACES_H__
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include "common.h"
#include "network-inador.h"
void interfaces_init (NetworkInadorHandle *handle);
int interface_receive_message_newlink (struct nl_msg *msg, void *arg);
int interface_receive_message_dellink (struct nl_msg *msg, void *arg);
extern int global_nl_seq;
void interfaces_list_all (NetworkInadorHandle *handle, int sock);
Interface * interfaces_locate_by_index (Interface *list, int index);
void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h, int first_time);
void interfaces_del_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h);
void interfaces_add_or_update_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h);
void interfaces_del_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h);
IPv4 * _interfaces_serach_ipv4 (Interface *interface, struct in_addr address, uint32_t prefix);
void interfaces_clear_all_ipv4_address (NetworkInadorHandle *handle, Interface *interface);
void interfaces_manual_add_ipv4 (int sock, Interface *interface, IPv4 *address);
void interfaces_manual_del_ipv4 (int sock, Interface *interface, IPv4 *address);
void interfaces_bring_up (int sock, Interface *interface);
void interfaces_bring_down (int sock, Interface *interface);
int interfaces_change_mac_address (NetworkInadorHandle *handle, int index, void *new_mac);
int interfaces_change_mtu (NetworkInadorHandle *handle, int index, uint32_t new_mtu);
int interfaces_change_set_up (NetworkInadorHandle *handle, int index);
int interfaces_change_set_down (NetworkInadorHandle *handle, int index);
int interfaces_change_name (NetworkInadorHandle *handle, int index, char * new_name);
#endif

0
src/ip-address.c 100644
View File

0
src/ip-address.h 100644
View File

View File

@ -1,8 +1,8 @@
/*
* network-inador.c
* main.c
* This file is part of Network-inador
*
* Copyright (C) 2011 - Félix Arreola Rodríguez
* Copyright (C) 2019, 2020 - 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
@ -22,74 +22,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <sys/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <signal.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h>
#include "network-inador.h"
#include <netlink/socket.h>
#include <netlink/msg.h>
#include "common.h"
#include "interfaces.h"
#include "netlink-events.h"
#include "manager.h"
#include "bridge.h"
#include "routes.h"
#include "wireless.h"
#include "manager-events.h"
#include "dhcp.h"
static GMainLoop *loop = NULL;
int create_route_netlink_socket (int groups) {
int fd;
struct sockaddr_nl local;
fd = socket (AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (fd < 0) {
return -1;
}
memset(&local, 0, sizeof(local)); /* fill-in local address information */
local.nl_family = AF_NETLINK;
local.nl_pid = 0;
local.nl_groups = groups;
if (bind (fd, (struct sockaddr *) &local, sizeof(local)) < 0) {
perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support");
close (fd);
return -1;
}
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (fd, (struct sockaddr *) &local_nl, &local_size);
printf ("Primer puerto es %ld\n", local_nl.nl_pid);
return fd;
}
/* Usados para salir en caso de una señal */
static int sigterm_pipe_fds[2] = { -1, -1 };
static void sigterm_handler (int signum) {
static void _init_handle (NetworkInadorHandle *handle) {
assert (handle != NULL);
handle->interfaces = NULL;
}
static void _sigterm_handler (int signum) {
//fprintf (stderr, "SIGTERM SIGINT Handler\n");
if (sigterm_pipe_fds[1] >= 0) {
if (write (sigterm_pipe_fds[1], "", 1) == -1 ) {
@ -100,11 +60,12 @@ static void sigterm_handler (int signum) {
}
}
static gboolean quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
static gboolean _main_quit_handler (GIOChannel *source, GIOCondition cond, gpointer data) {
GMainLoop *loop = (GMainLoop *) data;
g_main_loop_quit (loop);
}
static void setup_signal (void) {
static void _main_setup_signal (void *loop) {
struct sigaction act;
sigset_t empty_mask;
@ -118,7 +79,7 @@ static void setup_signal (void) {
sigemptyset (&empty_mask);
act.sa_mask = empty_mask;
act.sa_flags = 0;
act.sa_handler = &sigterm_handler;
act.sa_handler = &_sigterm_handler;
if (sigaction (SIGTERM, &act, NULL) < 0) {
perror ("Failed to register SIGTERM handler");
}
@ -133,30 +94,30 @@ static void setup_signal (void) {
io = g_io_channel_unix_new (sigterm_pipe_fds[0]);
g_io_channel_set_close_on_unref (io, TRUE);
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, quit_handler, NULL);
}
}
void clean_process (NetworkInadorHandle *handle) {
Interface *iface;
iface = handle->interfaces;
while (iface != NULL) {
if (iface->dhcp_info.process_pid != 0) {
kill (iface->dhcp_info.process_pid, SIGTERM);
}
g_io_add_watch (io, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR, _main_quit_handler, loop);
}
}
int main (int argc, char *argv[]) {
NetworkInadorHandle handle;
int nl_sock;
int nl_watch;
Interface *to_up;
GMainLoop *loop = NULL;
struct nl_sock * sock_req;
//signal (SIGPIPE, SIG_IGN);
//signal (SIGCHLD, SIG_IGN);
_init_handle (&handle);
/* Crear el socket de peticiones */
sock_req = nl_socket_alloc ();
if (nl_connect (sock_req, NETLINK_ROUTE) != 0) {
perror ("Falló conectar netlink socket\n");
return -1;
}
handle.nl_sock_route = sock_req;
/* Crear el socket que escucha eventos */
netlink_events_setup (&handle);
#if !defined(GLIB_VERSION_2_36)
g_type_init ();
@ -164,27 +125,9 @@ int main (int argc, char *argv[]) {
loop = g_main_loop_new (NULL, FALSE);
setup_signal ();
_main_setup_signal (loop);
/* Inicializar nuestra estructura principal */
handle.interfaces = NULL;
handle.rtable_v4 = NULL;
/* Crear los sockets de petición */
nl_sock = create_route_netlink_socket (0);
handle.netlink_sock_request = nl_sock;
nl_watch = create_route_netlink_socket (-1);
wireless_init (&handle);
manager_events_setup (&handle);
manager_setup_socket (&handle);
interfaces_list_all (&handle, nl_sock);
routes_list (&handle, nl_sock);
netlink_events_setup_loop (&handle, nl_watch);
interfaces_init (&handle);
g_main_loop_run (loop);

View File

@ -1,195 +0,0 @@
/*
* manager-events.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/wireless.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h>
#include "network-inador.h"
#include "manager-events.h"
#define EVENTS_SOCKET_PATH "/tmp/network-inador.events"
#define MANAGER_EVENTS_MAX_CLIENT 50
static int _manager_events_clients[MANAGER_EVENTS_MAX_CLIENT];
static int _manager_events_client_count = 0;
static gboolean _manager_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
char buffer[128];
int sock;
int ret;
int g;
sock = g_io_channel_unix_get_fd (source);
ret = read (sock, buffer, sizeof (buffer));
if (ret == 0) {
/* El socket del cliente se cerró */
for (g = 0; g < _manager_events_client_count; g++) {
if (_manager_events_clients[g] == sock) {
/* Te encontré */
if (_manager_events_client_count - 1 == g) {
/* Es el último socket del arreglo */
_manager_events_clients[g] = 0;
_manager_events_client_count--;
} else {
/* Recorrer el último en posición de éste */
_manager_events_clients[g] = _manager_events_clients[_manager_events_client_count - 1];
_manager_events_clients[_manager_events_client_count - 1] = 0;
_manager_events_client_count--;
}
break;
}
}
close (sock);
} else {
/* Procesar data o errores de lectura */
}
}
static gboolean _manager_events_handle_new_conn (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock;
int new_c;
GIOChannel *channel;
sock = g_io_channel_unix_get_fd (source);
new_c = accept (sock, NULL, NULL);
if (new_c < 0) {
printf ("Error al aceptar cliente\n");
return TRUE;
}
if (fcntl (new_c, F_SETFD, FD_CLOEXEC) < 0) {
printf ("Error set close-on-exec");
}
if (_manager_events_client_count == MANAGER_EVENTS_MAX_CLIENT) {
/* Rechazar el cliente por estar al máximo de capacidad */
close (new_c);
return TRUE;
}
channel = g_io_channel_unix_new (new_c);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_read, handle);
/* Agregar a la lista de clientes */
_manager_events_clients [_manager_events_client_count] = new_c;
_manager_events_client_count++;
return TRUE;
}
void manager_events_notify_ipv4_address_added (Interface *iface, IPv4 *address) {
char buffer[128];
int size;
int g;
buffer[0] = 0;
buffer[1] = MANAGER_EVENT_IPV4_ADDED;
buffer[2] = iface->index;
memcpy (&buffer[3], &address->sin_addr, sizeof (address->sin_addr));
buffer[7] = address->prefix;
size = 8;
for (g = 0; g < _manager_events_client_count; g++) {
write (_manager_events_clients [g], buffer, size);
}
}
void manager_events_setup (NetworkInadorHandle *handle) {
int sock;
struct sockaddr_un socket_name;
GIOChannel *channel;
sock = socket (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (sock < 0) {
perror ("Failed to create AF_UNIX socket");
return;
}
memset (_manager_events_clients, 0, sizeof (_manager_events_clients));
memset (&socket_name, 0, sizeof (struct sockaddr_un));
socket_name.sun_family = AF_UNIX;
strncpy (socket_name.sun_path, EVENTS_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
unlink (EVENTS_SOCKET_PATH);
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
perror ("Bind");
close (sock);
return;
}
if (listen (sock, 20)) {
perror ("Listen");
close (sock);
unlink (EVENTS_SOCKET_PATH);
return;
}
/* TODO: Aplicar permisos aquí */
chmod (EVENTS_SOCKET_PATH, 0666);
channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_events_handle_new_conn, handle);
}

View File

@ -1,37 +0,0 @@
/*
* manager-events.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 __MANAGER_EVENTS_H__
#define __MANAGER_EVENTS_H__
#include "network-inador.h"
enum {
MANAGER_EVENT_IPV4_ADDED = 1,
MANAGER_EVENT_IPV4_REMOVED,
};
void manager_events_notify_ipv4_address_added (Interface *iface, IPv4 *address);
void manager_events_setup (NetworkInadorHandle *handle);
#endif

View File

@ -1,577 +0,0 @@
/*
* manager.c
* This file is part of Network-inador
*
* Copyright (C) 2011 - 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 <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <linux/if_addr.h>
#include <sys/stat.h>
#include "manager.h"
#include "interfaces.h"
#include "network-inador.h"
#include "dhcp.h"
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
enum {
MANAGER_EVENT = 0,
MANAGER_COMMAND_REQUEST = 1,
MANAGER_COMMAND_LIST_IFACES = 1,
MANAGER_COMMAND_BRING_UP_IFACE,
MANAGER_COMMAND_BRING_DOWN_IFACE,
MANAGER_COMMAND_CLEAR_IPV4,
MANAGER_COMMAND_ADD_IPV4,
MANAGER_COMMAND_REMOVE_IPV4,
MANAGER_COMMAND_LIST_IPV4,
MANAGER_COMMAND_RUN_DHCP_CLIENT,
MANAGER_COMMAND_STOP_DHCP_CLIENT,
MANAGER_COMMAND_LIST_ROUTES,
MANAGER_COMMAND_ADD_ROUTE_V4,
MANAGER_COMMAND_REMOVE_ROUTE_V4,
MANAGER_RESPONSE = 128,
MANAGER_RESPONSE_REQUEST_INVALID = 128,
MANAGER_RESPONSE_PROCESSING,
MANAGER_RESPONSE_LIST_IFACES,
MANAGER_RESPONSE_LIST_IPV4,
MANAGER_RESPONSE_LIST_ROUTES,
};
enum {
MANAGER_ERROR_UNKNOWN = 0,
MANAGER_ERROR_INCOMPLETE_REQUEST,
MANAGER_ERROR_UNKNOWN_COMMAND,
MANAGER_ERROR_PREFIX_INVALID,
MANAGER_ERROR_IFACE_INVALID,
MANAGER_ERROR_IPV4_INVALID,
MANAGER_ERROR_DHCP_ALREADY_RUNNING,
MANAGER_ERROR_DHCP_NOT_RUNNING
};
#define MANAGER_IFACE_TYPE_WIRELESS 0x02
#define MANAGER_IFACE_TYPE_BRIDGE 0x04
#define MANAGER_IFACE_TYPE_LOOPBACK 0x8
#define MANAGER_IFACE_TYPE_VLAN 0x10
#define MANAGER_IFACE_TYPE_NLMON 0x20
#define MANAGER_IFACE_IPV4_ADDRESS_SECONDARY 0x01
typedef struct {
int sock;
struct sockaddr_un client;
socklen_t socklen;
int seq;
int command;
unsigned char *full_buffer;
unsigned char *command_data;
int full_len;
int command_len;
} ManagerCommandRequest;
static void _manager_send_invalid_request (ManagerCommandRequest *request, int error) {
unsigned char buffer[128];
buffer[0] = MANAGER_RESPONSE_REQUEST_INVALID;
buffer[1] = request->seq;
sendto (request->sock, buffer, 2, 0, (struct sockaddr *) &request->client, request->socklen);
}
static void _manager_send_processing (ManagerCommandRequest *request) {
unsigned char buffer[128];
buffer[0] = MANAGER_RESPONSE_PROCESSING;
buffer[1] = request->seq;
sendto (request->sock, buffer, 2, 0, (struct sockaddr *) &request->client, request->socklen);
}
static void _manager_send_response (ManagerCommandRequest *request, unsigned char *buffer, int len) {
sendto (request->sock, buffer, len, 0, (struct sockaddr *) &request->client, request->socklen);
}
static void _manager_send_list_interfaces (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
unsigned char buffer[8192];
Interface *iface_g;
int pos;
int flags;
buffer[0] = MANAGER_RESPONSE_LIST_IFACES;
buffer[1] = request->seq;
iface_g = handle->interfaces;
pos = 2;
while (iface_g != NULL) {
buffer[pos] = iface_g->index;
flags = 0;
if (iface_g->is_loopback) {
flags |= MANAGER_IFACE_TYPE_LOOPBACK;
}
if (iface_g->is_wireless) {
flags |= MANAGER_IFACE_TYPE_WIRELESS;
}
if (iface_g->is_bridge) {
flags |= MANAGER_IFACE_TYPE_BRIDGE;
}
if (iface_g->is_vlan) {
flags |= MANAGER_IFACE_TYPE_VLAN;
}
if (iface_g->is_nlmon) {
flags |= MANAGER_IFACE_TYPE_NLMON;
}
buffer[pos + 1] = flags;
/* Copiar la mac address */
memcpy (&buffer[pos + 2], iface_g->real_hw, ETHER_ADDR_LEN);
/* Copiar el nombre y el terminador de cadena */
memcpy (&buffer[pos + 2 + ETHER_ADDR_LEN], iface_g->name, strlen (iface_g->name) + 1);
pos += 2 + ETHER_ADDR_LEN + strlen (iface_g->name) + 1;
iface_g = iface_g->next;
}
buffer[pos] = 0;
pos++;
_manager_send_response (request, buffer, pos);
}
static void _manager_handle_clear_iface (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
*/
int index;
Interface *iface;
if (request->command_len < 1) {
/* Bytes unsuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
interfaces_clear_all_ipv4_address (handle, iface);
_manager_send_processing (request);
}
static void _manager_handle_bring_up_down_iface (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
*/
int index;
Interface *iface;
if (request->command_len < 1) {
/* Bytes unsuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
if (request->command == MANAGER_COMMAND_BRING_UP_IFACE) {
interfaces_bring_up (handle->netlink_sock_request, iface);
} else {
interfaces_bring_down (handle->netlink_sock_request, iface);
}
_manager_send_processing (request);
}
static void _manager_handle_interface_add_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
* 4 bytes de la dirección
* 1 byte del prefix
*/
uint32_t prefix;
int index;
Interface *iface;
IPv4 address;
if (request->command_len < 6) {
/* Bytes insuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
prefix = request->command_data[5];
if (prefix < 0 || prefix > 32) {
_manager_send_invalid_request (request, MANAGER_ERROR_PREFIX_INVALID);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
memcpy (&address.sin_addr, &request->command_data[1], sizeof (struct in_addr));
address.prefix = prefix;
address.next = NULL;
interfaces_manual_add_ipv4 (handle->netlink_sock_request, iface, &address);
_manager_send_processing (request);
}
static void _manager_handle_interface_del_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
* 4 bytes de la dirección
* 1 byte del prefix
*/
uint32_t prefix;
struct in_addr sin_addr;
int index;
Interface *iface;
IPv4 *to_del;
if (request->command_len < 6) {
/* Bytes insuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
prefix = request->command_data[5];
if (prefix < 0 || prefix > 32) {
_manager_send_invalid_request (request, MANAGER_ERROR_PREFIX_INVALID);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
memcpy (&sin_addr, &request->command_data[1], sizeof (struct in_addr));
to_del = _interfaces_serach_ipv4 (iface, sin_addr, prefix);
if (to_del == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IPV4_INVALID);
return;
}
interfaces_manual_del_ipv4 (handle->netlink_sock_request, iface, to_del);
_manager_send_processing (request);
}
static void _manager_send_list_ipv4 (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
*/
int index;
Interface *iface;
unsigned char buffer[8192];
IPv4 *ip_g;
int pos;
int count;
if (request->command_len < 1) {
/* Bytes unsuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
buffer[0] = MANAGER_RESPONSE_LIST_IPV4;
buffer[1] = request->seq;
ip_g = iface->v4_address;
count = 0;
pos = 6;
while (ip_g != NULL) {
memcpy (&buffer[pos], &ip_g->sin_addr, sizeof (ip_g->sin_addr));
pos = pos + sizeof (ip_g->sin_addr);
buffer[pos] = ip_g->prefix;
buffer[pos + 1] = 0;
if (ip_g->flags & IFA_F_SECONDARY) {
buffer[pos + 1] |= MANAGER_IFACE_IPV4_ADDRESS_SECONDARY;
}
pos = pos + 2;
ip_g = ip_g->next;
count++;
}
memcpy (&buffer[2], &count, sizeof (int));
_manager_send_response (request, buffer, pos);
}
static void _manager_handle_interface_set_dhcp (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
/* Primero, validar que haya suficientes bytes:
* 1 byte de la interfaz
*/
int index;
Interface *iface;
unsigned char buffer[8192];
IPv4 *ip_g;
int pos;
int count;
if (request->command_len < 1) {
/* Bytes unsuficientes */
_manager_send_invalid_request (request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return;
}
index = request->command_data[0];
iface = interfaces_locate_by_index (handle->interfaces, index);
if (iface == NULL) {
_manager_send_invalid_request (request, MANAGER_ERROR_IFACE_INVALID);
return;
}
if (request->command == MANAGER_COMMAND_RUN_DHCP_CLIENT && iface->dhcp_info.type != IFACE_NO_DHCP_RUNNING) {
_manager_send_invalid_request (request, MANAGER_ERROR_DHCP_ALREADY_RUNNING);
} else if (request->command == MANAGER_COMMAND_STOP_DHCP_CLIENT && iface->dhcp_info.type == IFACE_NO_DHCP_RUNNING) {
_manager_send_invalid_request (request, MANAGER_ERROR_DHCP_NOT_RUNNING);
} else if (request->command == MANAGER_COMMAND_RUN_DHCP_CLIENT) {
dhcp_run_client (handle, iface);
_manager_send_processing (request);
} else if (request->command == MANAGER_COMMAND_STOP_DHCP_CLIENT) {
dhcp_stop_client (handle, iface);
_manager_send_processing (request);
}
}
static void _manager_send_list_routes (NetworkInadorHandle *handle, ManagerCommandRequest *request) {
unsigned char buffer[8192];
Routev4 *route_g;
int pos;
int flags;
unsigned int count;
buffer[0] = MANAGER_RESPONSE_LIST_ROUTES;
buffer[1] = request->seq;
route_g = handle->rtable_v4;
count = 0;
pos = 6;
while (route_g != NULL) {
memcpy (&buffer[pos], &route_g->dest, sizeof (route_g->dest));
pos = pos + sizeof (route_g->dest);
buffer[pos] = route_g->prefix;
buffer[pos + 1] = route_g->index;
buffer[pos + 2] = route_g->table;
buffer[pos + 3] = route_g->type;
pos = pos + 4;
memcpy (&buffer[pos], &route_g->gateway, sizeof (route_g->gateway));
pos = pos + 4;
route_g = route_g->next;
count++;
}
memcpy (&buffer[2], &count, sizeof (int));
_manager_send_response (request, buffer, pos);
}
static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
unsigned char buffer[4096];
ManagerCommandRequest request;
request.full_buffer = buffer;
request.sock = g_io_channel_unix_get_fd (source);
request.socklen = sizeof (request.client);
request.full_len = recvfrom (request.sock, buffer, sizeof (buffer), 0, (struct sockaddr *) &request.client, &request.socklen);
request.command_data = &buffer[2];
request.command_len = request.full_len - 2;
request.seq = 0;
/* Procesar aquí la petición */
if (request.full_len < 2) {
_manager_send_invalid_request (&request, MANAGER_ERROR_INCOMPLETE_REQUEST);
return TRUE;
}
request.command = buffer[0];
request.seq = buffer[1];
switch (request.command) {
case MANAGER_COMMAND_LIST_IFACES:
_manager_send_list_interfaces (handle, &request);
break;
case MANAGER_COMMAND_BRING_UP_IFACE:
case MANAGER_COMMAND_BRING_DOWN_IFACE:
_manager_handle_bring_up_down_iface (handle, &request);
break;
case MANAGER_COMMAND_CLEAR_IPV4:
_manager_handle_clear_iface (handle, &request);
break;
case MANAGER_COMMAND_ADD_IPV4:
_manager_handle_interface_add_ipv4 (handle, &request);
break;
case MANAGER_COMMAND_REMOVE_IPV4:
_manager_handle_interface_del_ipv4 (handle, &request);
break;
case MANAGER_COMMAND_RUN_DHCP_CLIENT:
case MANAGER_COMMAND_STOP_DHCP_CLIENT:
_manager_handle_interface_set_dhcp (handle, &request);
break;
case MANAGER_COMMAND_LIST_IPV4:
_manager_send_list_ipv4 (handle, &request);
break;
case MANAGER_COMMAND_LIST_ROUTES:
_manager_send_list_routes (handle, &request);
break;
default:
_manager_send_invalid_request (&request, MANAGER_ERROR_UNKNOWN_COMMAND);
}
return TRUE;
}
int manager_setup_socket (NetworkInadorHandle *handle) {
int sock;
struct sockaddr_un socket_name;
GIOChannel *channel;
sock = socket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (sock < 0) {
perror ("Failed to create AF_UNIX socket");
return -1;
}
memset (&socket_name, 0, sizeof (struct sockaddr_un));
socket_name.sun_family = AF_UNIX;
strncpy (socket_name.sun_path, COMMAND_SOCKET_PATH, sizeof (socket_name.sun_path) - 1);
unlink (COMMAND_SOCKET_PATH);
if (bind (sock, (struct sockaddr *) &socket_name, sizeof (struct sockaddr_un)) < 0) {
perror ("Bind");
return -1;
}
/* TODO: Aplicar permisos aquí */
chmod (COMMAND_SOCKET_PATH, 0666);
channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _manager_client_data, handle);
return 0;
}

View File

@ -1,31 +0,0 @@
/*
* manager.h
* This file is part of Network-inador
*
* Copyright (C) 2011 - 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 __MANAGER_H__
#define __MANAGER_H__
#include "network-inador.h"
int manager_setup_socket (NetworkInadorHandle *handle);
#endif

View File

@ -2,7 +2,7 @@
* netlink-events.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - Félix Arreola Rodríguez
* Copyright (C) 2019, 2020 - 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
@ -20,107 +20,59 @@
* Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/wireless.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <glib.h>
#include "netlink-events.h"
#include "network-inador.h"
#include "common.h"
#include "interfaces.h"
#include "routes.h"
static int _netlink_events_route_dispatcher (struct nl_msg *msg, void *arg) {
struct nlmsghdr *reply;
reply = nlmsg_hdr (msg);
switch (reply->nlmsg_type) {
case RTM_NEWLINK:
interface_receive_message_newlink (msg, arg);
break;
case RTM_DELLINK:
interface_receive_message_dellink (msg, arg);
break;
}
}
static gboolean _netlink_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock;
sock = g_io_channel_unix_get_fd (source);
char reply[8192]; /* a large buffer */
struct sockaddr_nl kernel;
int len;
struct iovec io;
/* Para la respuesta */
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct msghdr rtnl_reply; /* generic msghdr structure */
struct iovec io_reply;
/* Esperar la respuesta */
memset(&io_reply, 0, sizeof(io_reply));
memset(&rtnl_reply, 0, sizeof(rtnl_reply));
io.iov_base = reply;
io.iov_len = sizeof (reply);
rtnl_reply.msg_iov = &io;
rtnl_reply.msg_iovlen = 1;
rtnl_reply.msg_name = &kernel;
rtnl_reply.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_reply, 0);
if (len == 0) {
printf ("Lectura de eventos regresó 0\n");
return FALSE;
} else if (len < 0) {
perror ("Error en recvmsg\n");
return TRUE;
}
msg_ptr = (struct nlmsghdr *) reply;
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
printf ("Msg type: %i\n", msg_ptr->nlmsg_type);
if (msg_ptr->nlmsg_type == RTM_NEWLINK) {
printf ("Mensaje dinámico de nueva interfaz\n");
interfaces_add_or_update_rtnl_link (handle, msg_ptr, 0);
} else if (msg_ptr->nlmsg_type == RTM_DELLINK) {
printf ("Mensaje dinámico de eliminar interfaz\n");
interfaces_del_rtnl_link (handle, msg_ptr);
} else if (msg_ptr->nlmsg_type == RTM_NEWADDR) {
printf ("Mensaje dinámico de nueva IP\n");
interfaces_add_or_update_ipv4 (handle, msg_ptr);
} else if (msg_ptr->nlmsg_type == RTM_DELADDR) {
printf ("Mensaje dinámico de eliminar IP\n");
interfaces_del_ipv4 (handle, msg_ptr);
} else if (msg_ptr->nlmsg_type == RTM_NEWROUTE) {
printf ("Mensaje dinámico de nueva ruta\n");
routes_add_or_update_rtm (handle, msg_ptr);
} else if (msg_ptr->nlmsg_type == RTM_DELROUTE) {
printf ("Mensaje dinámico de eliminar ruta\n");
routes_del_rtm (handle, msg_ptr);
}
}
nl_recvmsgs_default (handle->nl_sock_route_events);
return TRUE;
}
void netlink_events_setup_loop (NetworkInadorHandle *handle, int sock) {
void netlink_events_setup (NetworkInadorHandle *handle) {
struct nl_sock * sock_req;
int fd;
GIOChannel *channel;
channel = g_io_channel_unix_new (sock);
sock_req = nl_socket_alloc ();
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_read, handle);
if (nl_connect (sock_req, NETLINK_ROUTE) != 0) {
perror ("Falló conectar netlink socket para eventos\n");
return;
}
nl_socket_set_nonblocking (sock_req);
nl_socket_add_memberships (sock_req, RTNLGRP_LINK, 0);
nl_socket_disable_seq_check (sock_req);
nl_socket_modify_cb (sock_req, NL_CB_VALID, NL_CB_CUSTOM, _netlink_events_route_dispatcher, handle);
fd = nl_socket_get_fd (sock_req);
channel = g_io_channel_unix_new (fd);
handle->route_events_source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _netlink_events_handle_read, handle);
handle->nl_sock_route_events = sock_req;
}

View File

@ -2,7 +2,7 @@
* netlink-events.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - Félix Arreola Rodríguez
* Copyright (C) 2019, 2020 - 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
@ -23,9 +23,8 @@
#ifndef __NETLINK_EVENTS_H__
#define __NETLINK_EVENTS_H__
#include "network-inador.h"
#include "common.h"
void netlink_events_setup_loop (NetworkInadorHandle *handle, int sock);
void netlink_events_setup (NetworkInadorHandle *handle);
#endif

View File

@ -1,579 +0,0 @@
/*
* routes.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 <stdint.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "network-inador.h"
#include "interfaces.h"
#include "rta_aux.h"
static uint32_t _routes_utils_ip4_prefix_to_netmask (uint32_t prefix) {
return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
}
static Routev4 * _routes_append_routev4_to_struct (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix) {
Routev4 *new_route, *last;
new_route = (Routev4 *) malloc (sizeof (Routev4));
memset (new_route, 0, sizeof (Routev4));
new_route->dest = dest;
new_route->prefix = prefix;
new_route->next = NULL;
if (handle->rtable_v4 == NULL) {
handle->rtable_v4 = new_route;
} else {
last = handle->rtable_v4;
while (last->next != NULL) {
last = last->next;
}
last->next = new_route;
}
return new_route;
}
static Routev4 * _routes_search_ipv4 (NetworkInadorHandle *handle, struct in_addr dest, uint32_t prefix, unsigned int index) {
Routev4 *list;
list = handle->rtable_v4;
while (list != NULL) {
if (list->dest.s_addr == dest.s_addr &&
list->prefix == prefix &&
list->index == index) {
return list;
}
list = list->next;
}
return NULL;
}
static void _routes_delete_by_chain (NetworkInadorHandle *handle, Routev4 *route) {
Routev4 *list, *next, *before;
struct in_addr mask;
struct in_addr with_mask;
struct in_addr dest_masked;
/* Si esta es una ruta local sin gateway, lo más seguro es que se eliminó una IP,
* hay que eliminar todas las rutas que contengan un gateway que haga match
* con el destino de la ruta y la interfaz
* Esto asegura que se eliminen rutas como 0.0.0.0/0
*/
if (route->gateway.s_addr != 0) {
return;
}
list = handle->rtable_v4;
mask.s_addr = _routes_utils_ip4_prefix_to_netmask (route->prefix);
dest_masked.s_addr = route->dest.s_addr & mask.s_addr;
while (list != NULL) {
next = list->next;
if (list == route) {
/* Solo por seguridad, la ruta ya debería estar desligada de la lista */
list = next;
continue;
}
if (list->index != route->index) {
/* Son de diferentes interfaces, no aplica */
list = next;
continue;
}
if (list->gateway.s_addr != 0) {
with_mask.s_addr = list->gateway.s_addr & mask.s_addr;
if (with_mask.s_addr == dest_masked.s_addr) {
/* Eres una ruta que será eliminada */
if (list == handle->rtable_v4) {
/* Excelente, primera de la lista */
handle->rtable_v4 = list->next;
} else {
before = handle->rtable_v4;
while (before->next != list) {
before = before->next;
}
before->next = list->next;
}
printf ("Ruta eliminada en cadena\n");
free (list);
}
}
list = next;
}
}
void routes_manual_add_ipv4 (int sock, Interface *interface, IPv4 *dest, struct in_addr gateway) {
struct msghdr rtnl_msg;
struct iovec io;
struct sockaddr_nl kernel;
char buffer[8192];
int len;
struct nlmsghdr *nl;
struct rtmsg *route_addr;
struct rtattr *rta;
struct nlmsgerr *l_err;
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
nl = (struct nlmsghdr *) buffer;
nl->nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
nl->nlmsg_type = RTM_NEWROUTE;
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE | NLM_F_CREATE;
nl->nlmsg_seq = global_nl_seq++;
nl->nlmsg_pid = local_nl.nl_pid;
route_addr = (struct rtmsg *) NLMSG_DATA (nl);
route_addr->rtm_family = AF_INET;
route_addr->rtm_table = RT_TABLE_MAIN;
route_addr->rtm_protocol = RTPROT_STATIC;
route_addr->rtm_scope = RT_SCOPE_UNIVERSE;
route_addr->rtm_type = RTN_UNICAST;
route_addr->rtm_dst_len = dest->prefix;
rta = (struct rtattr *) RTM_RTA (route_addr);
rta->rta_type = RTA_GATEWAY;
memcpy (RTA_DATA (rta), &gateway, sizeof (gateway));
rta->rta_len = RTA_LENGTH (sizeof (gateway));
nl->nlmsg_len = NLMSG_ALIGN (nl->nlmsg_len) + rta->rta_len;
len = sizeof (buffer) - nl->nlmsg_len;
rta = (struct rtattr*) RTA_NEXT (rta, len);
rta->rta_type = RTA_OIF;
rta->rta_len = RTA_LENGTH (sizeof (int));
*((int*)RTA_DATA(rta)) = interface->index;
nl->nlmsg_len += rta->rta_len;
if (dest->prefix != 0) {
/* Agregar el atributo destino */
len = sizeof (buffer) - nl->nlmsg_len;
rta = (struct rtattr*) RTA_NEXT (rta, len);
rta->rta_type = RTA_DST;
rta->rta_len = RTA_LENGTH (sizeof (struct in_addr));
memcpy (RTA_DATA(rta), &dest->sin_addr, sizeof (struct in_addr));
nl->nlmsg_len += rta->rta_len;
}
io.iov_base = buffer;
io.iov_len = nl->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_msg, 0);
nl = (struct nlmsghdr *) buffer;
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
if (nl->nlmsg_type == NLMSG_DONE) {
printf ("Route ADD Msg type: DONE!\n");
break;
}
if (nl->nlmsg_type == NLMSG_ERROR) {
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
printf ("Route ADD Error tamaño truncado\n");
} else if (l_err->error != 0) {
// Error:
printf ("Route ADD Error: %i\n", l_err->error);
}
break;
}
}
}
void routes_manual_del_v4 (int sock, Routev4 *route) {
struct msghdr rtnl_msg;
struct iovec io;
struct sockaddr_nl kernel;
char buffer[8192];
int len;
struct nlmsghdr *nl;
struct rtmsg *route_addr;
struct rtattr *rta;
struct nlmsgerr *l_err;
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (&io, 0, sizeof (io));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
nl = (struct nlmsghdr *) buffer;
nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nl->nlmsg_type = RTM_DELROUTE;
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nl->nlmsg_seq = global_nl_seq++;
nl->nlmsg_pid = local_nl.nl_pid;
route_addr = (struct rtmsg *) NLMSG_DATA (nl);
route_addr->rtm_family = AF_INET;
route_addr->rtm_scope = RT_SCOPE_NOWHERE;
route_addr->rtm_type = route->type;
route_addr->rtm_table = route->table;
route_addr->rtm_dst_len = route->prefix;
route_addr->rtm_protocol = 0;
if (route->prefix != 0) {
rta = (struct rtattr *) RTM_RTA (route_addr);
rta->rta_type = RTA_DST;
rta->rta_len = RTA_LENGTH (sizeof (struct in_addr));
memcpy (RTA_DATA(rta), &route->dest, sizeof (struct in_addr));
nl->nlmsg_len += rta->rta_len;
}
io.iov_base = buffer;
io.iov_len = nl->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_msg, 0);
nl = (struct nlmsghdr *) buffer;
for (; NLMSG_OK(nl, len); nl = NLMSG_NEXT(nl, len)) {
if (nl->nlmsg_type == NLMSG_DONE) {
printf ("Route DEL Msg type: DONE!\n");
break;
}
if (nl->nlmsg_type == NLMSG_ERROR) {
l_err = (struct nlmsgerr*) NLMSG_DATA (nl);
if (nl->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) {
printf ("Route DEL Error tamaño truncado\n");
} else if (l_err->error != 0) {
// Error:
printf ("Route DEL Error: %i\n", l_err->error);
}
break;
}
}
}
void routes_add_or_update_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) {
struct rtmsg *route_addr;
struct rtattr *attribute;
size_t len;
char ip_as_string[1024];
Routev4 *new;
struct in_addr dest;
int prefix;
struct in_addr gateway;
unsigned index = 0;
memset (&dest, 0, sizeof (dest));
memset (&gateway, 0, sizeof (gateway));
route_addr = NLMSG_DATA(h);
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
printf ("Omitiendo ruta local o broadcast\n");
return;
}
if (route_addr->rtm_family != AF_INET) {
/* Por el momento, las direcciones IPv6 no son procesadas */
return;
}
printf ("--------\n");
printf ("Route list, family: %d\n", route_addr->rtm_family);
printf ("Route Dest len: %d\n", route_addr->rtm_dst_len);
printf ("Route Table id: %d\n", route_addr->rtm_table);
printf ("Route type: %d\n", route_addr->rtm_type);
printf ("Route flags: %d\n", route_addr->rtm_flags);
printf ("Route protocol: %d\n", route_addr->rtm_protocol);
prefix = route_addr->rtm_dst_len;
len = RTM_PAYLOAD (h);
//len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
for_each_rattr (attribute, RTM_RTA (route_addr), len) {
//printf ("Attribute (addr): %d\n", attribute->rta_type);
if (attribute->rta_type == RTA_GATEWAY) {
memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr));
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
printf ("Gw Address: %s\n", ip_as_string);
} else if (attribute->rta_type == RTA_DST) {
memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr));
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
printf ("Destination Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len);
} else if (attribute->rta_type == RTA_OIF) {
index = *((int *) RTA_DATA (attribute));
printf ("!!!!!!!!! Output interface: %i\n", index);
} else if (attribute->rta_type == RTA_PREFSRC) {
//printf (
} else if (attribute->rta_type == RTA_TABLE) {
} else {
printf ("ROUTE Attribute: %d\n", attribute->rta_type);
}
}
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
printf ("Omitiendo ruta local o broadcast\n");
return;
}
new = _routes_search_ipv4 (handle, dest, prefix, index);
if (new == NULL) {
printf ("Agregando Ruta a la lista de rutas\n");
new = _routes_append_routev4_to_struct (handle, dest, prefix);
}
/* Actualizar la gateway si hubo gateway en el mensaje */
memcpy (&new->gateway, &gateway, sizeof (new->gateway));
new->index = index;
new->table = route_addr->rtm_table;
new->type = route_addr->rtm_type;
}
void routes_del_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h) {
struct rtmsg *route_addr;
Routev4 *route, *before;
struct rtattr *attribute;
size_t len;
char ip_as_string[1024];
struct in_addr dest;
int prefix;
int index;
memset (&dest, 0, sizeof (dest));
route_addr = NLMSG_DATA(h);
if (route_addr->rtm_type == RTN_BROADCAST || route_addr->rtm_type == RTN_LOCAL) {
//printf ("Omitiendo ruta local o broadcast\n");
//return;
}
if (route_addr->rtm_family != AF_INET) {
/* Por el momento, las direcciones IPv6 no son procesadas */
return;
}
printf ("--------> ROUTE DEL <--------\n");
printf ("Route list, family: %d\n", route_addr->rtm_family);
printf ("Route Dest len: %d\n", route_addr->rtm_dst_len);
printf ("Route Table id: %d\n", route_addr->rtm_table);
printf ("Route type: %d\n", route_addr->rtm_type);
printf ("Route flags: %d\n", route_addr->rtm_flags);
printf ("Route protocol: %d\n", route_addr->rtm_protocol);
prefix = route_addr->rtm_dst_len;
//len = RTM_PAYLOAD (h);
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
for (attribute = RTM_RTA (route_addr); RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
//printf ("Attribute (addr): %d\n", attribute->rta_type);
if (attribute->rta_type == RTA_GATEWAY) {
//memcpy (&gateway, RTA_DATA (attribute), sizeof (struct in_addr));
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
printf ("Gw Address: %s\n", ip_as_string);
} else if (attribute->rta_type == RTA_DST) {
memcpy (&dest, RTA_DATA (attribute), sizeof (struct in_addr));
inet_ntop (route_addr->rtm_family, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string));
printf ("Address: %s/%d\n", ip_as_string, route_addr->rtm_dst_len);
} else if (attribute->rta_type == RTA_OIF) {
index = *((int *) RTA_DATA (attribute));
printf ("Output interface: %i\n", index);
} else {
printf ("ROUTE Attribute: %d\n", attribute->rta_type);
}
}
route = _routes_search_ipv4 (handle, dest, prefix, index);
if (route == NULL) {
printf ("Me solicitaron eliminar una ruta y no existe\n");
} else {
if (route == handle->rtable_v4) {
handle->rtable_v4 = route->next;
} else {
before = handle->rtable_v4;
while (before->next != route) {
before = before->next;
}
before->next = route->next;
}
_routes_delete_by_chain (handle, route);
free (route);
}
}
void routes_list (NetworkInadorHandle *handle, int sock) {
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
struct iovec io;
struct rtmsg *rt;
struct sockaddr_nl kernel;
char buffer[8192]; /* a large buffer */
int len;
/* Para la respuesta */
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (sock, (struct sockaddr *) &local_nl, &local_size);
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (&kernel, 0, sizeof (kernel));
memset (&buffer, 0, sizeof (buffer));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
msg_ptr = (struct nlmsghdr *) buffer;
msg_ptr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
msg_ptr->nlmsg_type = RTM_GETROUTE;
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
msg_ptr->nlmsg_seq = global_nl_seq++;
msg_ptr->nlmsg_pid = local_nl.nl_pid;
rt = (struct rtmsg*) NLMSG_DATA (msg_ptr);
rt->rtm_family = AF_INET; /* Limitar la primer consulta a solo IPv4, por el momento */
io.iov_base = buffer;
io.iov_len = msg_ptr->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
sendmsg (sock, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof (kernel);
while ((len = recvmsg(sock, &rtnl_msg, 0)) > 0) { /* read lots of data */
msg_ptr = (struct nlmsghdr *) buffer;
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
/* Procesar solo los mensajes de nueva interfaz */
printf ("ROUTE Msg type: %i\n", msg_ptr->nlmsg_type);
if (msg_ptr->nlmsg_type == RTM_NEWROUTE) {
routes_add_or_update_rtm (handle, msg_ptr);
}
}
}
}

View File

@ -1,35 +0,0 @@
/*
* routes.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 __ROUTES_H__
#define __ROUTES_H__
#include "network-inador.h"
void routes_list (NetworkInadorHandle *handle, int sock);
void routes_add_or_update_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h);
void routes_del_rtm (NetworkInadorHandle *handle, struct nlmsghdr *h);
void routes_manual_add_ipv4 (int sock, Interface *interface, IPv4 *dest, struct in_addr gateway);
void routes_manual_del_v4 (int sock, Routev4 *route);
#endif

View File

@ -1,71 +0,0 @@
/*
* rta_aux.c
* This file is part of Network-inador
*
* Copyright (C) 2011 - 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 <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
int rta_addattr_l (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) {
int len = RTA_LENGTH (alen);
struct rtattr *rta;
if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) {
return -1;
}
rta = NLMSG_TAIL (n);
rta->rta_type = type;
rta->rta_len = len;
memcpy (RTA_DATA (rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
return 0;
}
struct rtattr * rta_addattr_nest (struct nlmsghdr *n, int maxlen, int type) {
struct rtattr *nest = NLMSG_TAIL (n);
rta_addattr_l (n, maxlen, type, NULL, 0);
return nest;
}
int rta_addattr_nest_end (struct nlmsghdr *n, struct rtattr *nest) {
nest->rta_len = (void *) NLMSG_TAIL (n) - (void *) nest;
return n->nlmsg_len;
}

View File

@ -1,34 +0,0 @@
/*
* rta_aux.h
* This file is part of Network-inador
*
* Copyright (C) 2011 - 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 __RTA_AUX_H__
#define __RTA_AUX_H__
#define for_each_rattr(n, buf, len) \
for (n = (struct rtattr*)buf; RTA_OK(n, len); n = RTA_NEXT(n, len))
int rta_addattr_l (struct nlmsghdr *n, int maxlen, int type, const void *data, int alen);
struct rtattr * rta_addattr_nest (struct nlmsghdr *n, int maxlen, int type);
int rta_addattr_nest_end (struct nlmsghdr *n, struct rtattr *nest);
#endif

View File

@ -1,39 +0,0 @@
#include <stdint.h>
#include <arpa/inet.h>
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;
}
/**
* nm_utils_ip4_prefix_to_netmask:
* @prefix: a CIDR prefix
*
* Returns: the netmask represented by the prefix, in network byte order
**/
uint32_t utils_ip4_prefix_to_netmask (uint32_t prefix) {
return prefix < 32 ? ~htonl(0xFFFFFFFF >> prefix) : 0xFFFFFFFF;
}

View File

@ -1,10 +0,0 @@
#ifndef __UTILS_H__
#define __UTILS_H__
#include <stdint.h>
uint32_t utils_ip4_netmask_to_prefix (uint32_t netmask);
uint32_t utils_ip4_prefix_to_netmask (uint32_t prefix);
#endif

View File

@ -1,611 +0,0 @@
/*
* wireless.c
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/genetlink.h>
#include <linux/nl80211.h>
#include "wireless.h"
#include "network-inador.h"
#include "interfaces.h"
#include "rta_aux.h"
static uint16_t nl80211_id = 0;
static uint16_t scan_multicast_group_id = 0;
static void _wireless_find_ssid (uint8_t *ies, uint32_t ies_len, unsigned char *ssid, uint32_t *ssid_len) {
#define WLAN_EID_SSID 0
ssid[0] = 0;
*ssid_len = 0;
while (ies_len > 2 && ies[0] != WLAN_EID_SSID) {
ies_len -= ies[1] + 2;
ies += ies[1] + 2;
}
if (ies_len < 2)
return;
if (ies_len < (uint32_t)(2 + ies[1]))
return;
*ssid_len = ies[1];
memcpy (ssid, ies + 2, ies[1]);
}
static int _wireless_create_generic_netlink_socket (void) {
int fd;
struct sockaddr_nl local;
fd = socket (AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
if (fd < 0) {
return -1;
}
memset(&local, 0, sizeof(local)); /* fill-in local address information */
local.nl_family = AF_NETLINK;
local.nl_pid = 0;
local.nl_groups = 0;
if (bind (fd, (struct sockaddr *) &local, sizeof(local)) < 0) {
perror("cannot bind, are you root ? if yes, check netlink/rtnetlink kernel support");
close (fd);
return -1;
}
return fd;
}
static uint16_t _wireless_parse_family_id (struct nlmsghdr *msg_ptr) {
struct genlmsghdr *ghdr;
struct rtattr *attribute;
int len;
uint16_t n80211_family;
struct rtattr *nest2_attr, *nest3_attr;
int nest2_size, nest3_size;
int sub2_len, sub3_len;
ghdr = NLMSG_DATA (msg_ptr);
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
//printf ("Attribute: %d\n", attribute->rta_type);
if (attribute->rta_type == CTRL_ATTR_FAMILY_ID) {
memcpy (&n80211_family, RTA_DATA (attribute), 2);
//printf ("El id del nl80211 es: %hu\n", n80211_family);
} else if (attribute->rta_type == CTRL_ATTR_MCAST_GROUPS) {
//printf ("_____________ Descubriendo la familia nl80211. Multicast groups: \n");
int id_multicast_group;
char multicast_group_name[512];
nest2_size = attribute->rta_len;
nest2_attr = RTA_DATA (attribute);
while (nest2_size > sizeof (nest2_attr)) {
sub2_len = nest2_attr->rta_len;
if (sub2_len > nest2_size) {
break;
}
nest3_size = nest2_attr->rta_len;
nest3_attr = RTA_DATA (nest2_attr);
id_multicast_group = 0;
multicast_group_name[0] = 0;
while (nest3_size > sizeof (nest3_attr)) {
sub3_len = nest3_attr->rta_len;
if (sub3_len > nest3_size) {
//printf ("Los sub atributos se acabaron prematuramente\n");
break;
}
//printf ("sub attributo type: %i, size: %d\n", nest3_attr->rta_type, nest3_attr->rta_len);
if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_ID) {
memcpy (&id_multicast_group, RTA_DATA (nest3_attr), sizeof (id_multicast_group));
} else if (nest3_attr->rta_type == CTRL_ATTR_MCAST_GRP_NAME) {
strncpy (multicast_group_name, RTA_DATA (nest3_attr), sizeof (multicast_group_name));
}
nest3_size -= RTA_ALIGN (sub3_len);
nest3_attr = (struct rtattr *) (((char *) nest3_attr) + RTA_ALIGN (sub3_len));
}
if (strcmp (multicast_group_name, "scan") == 0) {
scan_multicast_group_id = id_multicast_group;
//printf ("ID del grupo multicast SCAN: %i\n", id_multicast_group);
}
nest2_size -= RTA_ALIGN (sub2_len);
nest2_attr = (struct rtattr *) (((char *) nest2_attr) + RTA_ALIGN (sub2_len));
}
}
}
return n80211_family;
}
static void _wireless_parse_message_get_iface (struct nlmsghdr *msg_ptr, Interface *iface) {
struct genlmsghdr *ghdr;
struct rtattr *attribute;
int len;
int wiphy;
/* Anexar la estructura wireless al objeto interfaz */
WirelessInfo *winfo;
winfo = (WirelessInfo *) malloc (sizeof (WirelessInfo));
if (winfo == NULL) {
return;
}
memset (winfo, 0, sizeof (winfo));
iface->wireless = winfo;
ghdr = NLMSG_DATA (msg_ptr);
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
printf ("Wireless Attribute: %d\n", attribute->rta_type);
if (attribute->rta_type == NL80211_ATTR_WIPHY) {
memcpy (&wiphy, RTA_DATA (attribute), 4);
iface->wireless->wiphy = wiphy;
}
/*switch(attribute->rta_type) {
default:
printf ("Del interface RTA Attribute \"%hu\" no procesado\n", attribute->rta_type);
}*/
}
}
static void _wireless_parse_scan (NetworkInadorHandle *handle, struct nlmsghdr *msg_ptr) {
struct genlmsghdr *ghdr;
struct rtattr *attribute;
int len;
int iface = -1;
ghdr = NLMSG_DATA (msg_ptr);
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
//printf ("Wireless scan Attribute: %d\n", attribute->rta_type);
if (attribute->rta_type == NL80211_ATTR_IFINDEX) {
memcpy (&iface, RTA_DATA (attribute), 4);
}
}
/* Ejecutar el GET Scan */
if (iface != -1) {
wireless_do_get_scan (handle, iface);
}
}
static void _wireless_parse_station (struct nlmsghdr *msg_ptr, Interface *iface) {
struct genlmsghdr *ghdr;
struct rtattr *attribute;
int len;
char bss_info[1024];
int has_bss = 0;
int bss_len;
ghdr = NLMSG_DATA (msg_ptr);
len = msg_ptr->nlmsg_len - NLMSG_LENGTH (sizeof (struct genlmsghdr));
attribute = (struct rtattr*) (((char *) ghdr) + GENL_HDRLEN);
for (; RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) {
//printf ("Wireless scan Attribute: %d\n", attribute->rta_type);
if (attribute->rta_type == NL80211_ATTR_BSS) {
has_bss = 1;
bss_len = attribute->rta_len;
memcpy (bss_info, RTA_DATA (attribute), bss_len);
}
}
if (has_bss == 0) {
/* No hay BSS info */
return;
}
printf ("Imprimiendo BSS Attrs:\n");
attribute = (struct rtattr *) bss_info;
for (; RTA_OK (attribute, bss_len); attribute = RTA_NEXT (attribute, len)) {
if (attribute->rta_type == NL80211_BSS_BSSID) {
char *mac = RTA_DATA (attribute);
//printf ("MAC access point: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
} else if (attribute->rta_type == NL80211_BSS_INFORMATION_ELEMENTS) {
char essid[64];
essid[0] = 0;
int essid_len = 0;
_wireless_find_ssid (RTA_DATA (attribute), attribute->rta_len, essid, &essid_len);
essid[essid_len] = 0;
printf ("Essid: %s\n", essid);
} else if (attribute->rta_type == NL80211_BSS_STATUS) {
int status;
memcpy (&status, RTA_DATA (attribute), 4);
printf ("-> Bss estatus: %i\n", status);
} else {
printf ("BSS Scan Attribute: %d\n", attribute->rta_type);
}
}
}
void wireless_do_get_scan (NetworkInadorHandle *handle, int ifindex) {
printf ("DO Scan for iface: %i\n", ifindex);
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
struct iovec io;
struct genlmsghdr *ghdr;
struct rtattr *rta;
struct sockaddr_nl kernel;
char buffer[8192]; /* a large buffer */
int len;
Interface *iface;
/* Localizar el iface por el índice */
iface = interfaces_locate_by_index (handle->interfaces, ifindex);
if (iface == NULL) {
return;
}
/* Para la respuesta */
struct nlmsgerr *l_err;
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
msg_ptr = (struct nlmsghdr *) buffer;
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
msg_ptr->nlmsg_type = nl80211_id;
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
msg_ptr->nlmsg_seq = global_nl_seq++;
msg_ptr->nlmsg_pid = local_nl.nl_pid;
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
ghdr->cmd = NL80211_CMD_GET_SCAN;
ghdr->version = 0;
rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &ifindex, 4);
//rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->wiphy, 4);
io.iov_base = buffer;
io.iov_len = msg_ptr->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
len = sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof (kernel);
len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
if (len <= 0) {
return;
}
msg_ptr = (struct nlmsghdr *) buffer;
printf ("Procesando mensajes de solicitud de escaneo\n");
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
if (msg_ptr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *l_err;
l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr);
printf ("DO Scan message error, num: %i\n", l_err->error);
break;
} else if (msg_ptr->nlmsg_type == NLMSG_DONE) {
printf ("DO Scan, end of DUMP\n");
break;
} else if (msg_ptr->nlmsg_type == nl80211_id) {
ghdr = NLMSG_DATA (msg_ptr);
//printf ("DO SCAN! Generic command: %i\n", ghdr->cmd);
if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
_wireless_parse_station (msg_ptr, iface);
}
}
}
}
gboolean _wireless_events_handle_read (GIOChannel *source, GIOCondition condition, gpointer data) {
NetworkInadorHandle *handle = (NetworkInadorHandle *) data;
int sock;
sock = g_io_channel_unix_get_fd (source);
char reply[8192]; /* a large buffer */
struct sockaddr_nl kernel;
int len;
struct iovec io;
/* Para la respuesta */
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct msghdr rtnl_reply; /* generic msghdr structure */
struct iovec io_reply;
struct genlmsghdr *ghdr;
/* Esperar la respuesta */
memset(&io_reply, 0, sizeof(io_reply));
memset(&rtnl_reply, 0, sizeof(rtnl_reply));
io.iov_base = reply;
io.iov_len = sizeof (reply);
rtnl_reply.msg_iov = &io;
rtnl_reply.msg_iovlen = 1;
rtnl_reply.msg_name = &kernel;
rtnl_reply.msg_namelen = sizeof(kernel);
len = recvmsg(sock, &rtnl_reply, 0);
if (len == 0) {
printf ("Lectura de eventos regresó 0\n");
return FALSE;
} else if (len < 0) {
perror ("Error en recvmsg\n");
return TRUE;
}
msg_ptr = (struct nlmsghdr *) reply;
for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) {
printf ("Msg type: %i\n", msg_ptr->nlmsg_type);
if (msg_ptr->nlmsg_type == nl80211_id) {
ghdr = NLMSG_DATA (msg_ptr);
printf ("Generic command: %i\n", ghdr->cmd);
if (ghdr->cmd == NL80211_CMD_NEW_SCAN_RESULTS) {
_wireless_parse_scan (handle, msg_ptr);
}
}
}
return TRUE;
}
void wireless_init (NetworkInadorHandle *handle) {
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
struct iovec io;
struct genlmsghdr *ghdr;
struct rtattr *rta;
struct sockaddr_nl kernel;
char buffer[8192]; /* a large buffer */
int len;
GIOChannel *channel;
/* Para la respuesta */
struct nlmsgerr *l_err;
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Crear un netlink de la familia generica para nuestras peticiones */
handle->netlink_sock_request_generic = _wireless_create_generic_netlink_socket ();
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
msg_ptr = (struct nlmsghdr *) buffer;
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
msg_ptr->nlmsg_type = GENL_ID_CTRL;
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
msg_ptr->nlmsg_seq = global_nl_seq++;
msg_ptr->nlmsg_pid = local_nl.nl_pid;
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
ghdr->cmd = CTRL_CMD_GETFAMILY;
ghdr->version = 1;
len = strlen (NL80211_GENL_NAME) + 1;
rta_addattr_l (msg_ptr, sizeof (buffer), CTRL_ATTR_FAMILY_NAME, NL80211_GENL_NAME, len);
io.iov_base = buffer;
io.iov_len = msg_ptr->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof (kernel);
/*len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
msg_ptr = (struct nlmsghdr *) buffer;
_wireless_parse_family_id (msg_ptr);
len = recvmsg (handle->netlink_sock_request_generic, &rtnl_msg, 0);
msg_ptr = (struct nlmsghdr *) buffer;*/
while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */
msg_ptr = (struct nlmsghdr *) buffer;
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
if (msg_ptr->nlmsg_type == NLMSG_ERROR) break;
if (msg_ptr->nlmsg_type == GENL_ID_CTRL) {
nl80211_id = _wireless_parse_family_id (msg_ptr);
}
}
/* Generar otro socket netlink generic para eventos */
int sock_for_wireless_events;
int group;
sock_for_wireless_events = _wireless_create_generic_netlink_socket ();
group = scan_multicast_group_id;
setsockopt (sock_for_wireless_events, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof (group));
/* Instalar un GIOChannel */
channel = g_io_channel_unix_new (sock_for_wireless_events);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, _wireless_events_handle_read, handle);
}
//void test_wireless
void wireless_check_is_wireless_interface (NetworkInadorHandle *handle, Interface *iface) {
struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */
struct iovec io;
struct genlmsghdr *ghdr;
struct rtattr *rta;
struct sockaddr_nl kernel;
char buffer[8192]; /* a large buffer */
int len;
/* Para la respuesta */
struct nlmsgerr *l_err;
struct nlmsghdr *msg_ptr; /* pointer to current part */
struct sockaddr_nl local_nl;
socklen_t local_size;
/* Recuperar el puerto local del netlink */
local_size = sizeof (local_nl);
getsockname (handle->netlink_sock_request_generic, (struct sockaddr *) &local_nl, &local_size);
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (&kernel, 0, sizeof (kernel));
memset (buffer, 0, sizeof (buffer));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */
kernel.nl_groups = 0;
msg_ptr = (struct nlmsghdr *) buffer;
msg_ptr->nlmsg_len = NLMSG_LENGTH (sizeof (struct genlmsghdr));
msg_ptr->nlmsg_type = nl80211_id;
msg_ptr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
msg_ptr->nlmsg_seq = global_nl_seq++;
msg_ptr->nlmsg_pid = local_nl.nl_pid;
ghdr = (struct genlmsghdr *) NLMSG_DATA (msg_ptr);
ghdr->cmd = NL80211_CMD_GET_INTERFACE;
ghdr->version = 0;
rta_addattr_l (msg_ptr, sizeof (buffer), NL80211_ATTR_IFINDEX, &iface->index, 4);
io.iov_base = buffer;
io.iov_len = msg_ptr->nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);
sendmsg (handle->netlink_sock_request_generic, (struct msghdr *) &rtnl_msg, 0);
/* Esperar la respuesta */
memset (&io, 0, sizeof (io));
memset (&rtnl_msg, 0, sizeof (rtnl_msg));
memset (buffer, 0, sizeof (buffer));
io.iov_base = buffer;
io.iov_len = sizeof (buffer);
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof (kernel);
while ((len = recvmsg(handle->netlink_sock_request_generic, &rtnl_msg, 0)) > 0) { /* read lots of data */
msg_ptr = (struct nlmsghdr *) buffer;
if (msg_ptr->nlmsg_type == NLMSG_DONE) break;
if (msg_ptr->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *l_err;
l_err = (struct nlmsgerr*) NLMSG_DATA (msg_ptr);
break;
}
if (msg_ptr->nlmsg_type == nl80211_id) {
_wireless_parse_message_get_iface (msg_ptr, iface);
}
}
}

View File

@ -1,32 +0,0 @@
/*
* wireless.h
* This file is part of Network-inador
*
* Copyright (C) 2018 - 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 __WIRELESS_H__
#define __WIRELESS_H__
#include "network-inador.h"
void wireless_init (NetworkInadorHandle *handle);
void wireless_check_is_wireless_interface (NetworkInadorHandle *handle, Interface *iface);
void wireless_do_get_scan (NetworkInadorHandle *handle, int ifindex);
#endif