From 060cc4773501d15347d5dd9045097b15e34edc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Tue, 31 Dec 2019 11:05:50 -0600 Subject: [PATCH] Reescritura para usar libnl3. --- configure.ac | 12 +- po/POTFILES.in | 2 +- src/Makefile.am | 18 +- src/bridge.c | 300 ------ src/bridge.h | 33 - src/{network-inador.h => common.h} | 101 +- src/dhcp.c | 286 ------ src/dhcp.h | 29 - src/dhcpc/Makefile.am | 17 - src/dhcpc/common.c | 441 --------- src/dhcpc/common.h | 317 ------ src/dhcpc/dhcpc.c | 1444 ---------------------------- src/dhcpc/dhcpc.h | 39 - src/dhcpc/dhcpd.h | 128 --- src/dhcpc/extra.c | 499 ---------- src/dhcpc/extra.h | 198 ---- src/dhcpc/nidhcpc.c | 40 - src/dhcpc/packet.c | 194 ---- src/dhcpc/signalpipe.c | 86 -- src/dhcpc/socket.c | 122 --- src/gettext.h | 292 ------ src/interfaces.c | 1266 +++++++++--------------- src/interfaces.h | 31 +- src/ip-address.c | 0 src/ip-address.h | 0 src/{network-inador.c => main.c} | 137 +-- src/manager-events.c | 195 ---- src/manager-events.h | 37 - src/manager.c | 577 ----------- src/manager.h | 31 - src/netlink-events.c | 130 +-- src/netlink-events.h | 7 +- src/routes.c | 579 ----------- src/routes.h | 35 - src/rta_aux.c | 71 -- src/rta_aux.h | 34 - src/utils.c | 39 - src/utils.h | 10 - src/wireless.c | 611 ------------ src/wireless.h | 32 - 40 files changed, 567 insertions(+), 7853 deletions(-) delete mode 100644 src/bridge.c delete mode 100644 src/bridge.h rename src/{network-inador.h => common.h} (52%) delete mode 100644 src/dhcp.c delete mode 100644 src/dhcp.h delete mode 100644 src/dhcpc/Makefile.am delete mode 100644 src/dhcpc/common.c delete mode 100644 src/dhcpc/common.h delete mode 100644 src/dhcpc/dhcpc.c delete mode 100644 src/dhcpc/dhcpc.h delete mode 100644 src/dhcpc/dhcpd.h delete mode 100644 src/dhcpc/extra.c delete mode 100644 src/dhcpc/extra.h delete mode 100644 src/dhcpc/nidhcpc.c delete mode 100644 src/dhcpc/packet.c delete mode 100644 src/dhcpc/signalpipe.c delete mode 100644 src/dhcpc/socket.c delete mode 100644 src/gettext.h create mode 100644 src/ip-address.c create mode 100644 src/ip-address.h rename src/{network-inador.c => main.c} (50%) delete mode 100644 src/manager-events.c delete mode 100644 src/manager-events.h delete mode 100644 src/manager.c delete mode 100644 src/manager.h delete mode 100644 src/routes.c delete mode 100644 src/routes.h delete mode 100644 src/rta_aux.c delete mode 100644 src/rta_aux.h delete mode 100644 src/utils.c delete mode 100644 src/utils.h delete mode 100644 src/wireless.c delete mode 100644 src/wireless.h diff --git a/configure.ac b/configure.ac index 2d4f179..bf062b0 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/po/POTFILES.in b/po/POTFILES.in index 7dd830f..1221e82 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,2 +1,2 @@ # List of source files which contain translatable strings. -src/network-inador.c +src/main.c diff --git a/src/Makefile.am b/src/Makefile.am index 175a2f5..6da7387 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/bridge.c b/src/bridge.c deleted file mode 100644 index fc9d4e0..0000000 --- a/src/bridge.c +++ /dev/null @@ -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 -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#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; - } - } -} diff --git a/src/bridge.h b/src/bridge.h deleted file mode 100644 index 842871c..0000000 --- a/src/bridge.h +++ /dev/null @@ -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 - diff --git a/src/network-inador.h b/src/common.h similarity index 52% rename from src/network-inador.h rename to src/common.h index 0de19bd..b3539c4 100644 --- a/src/network-inador.h +++ b/src/common.h @@ -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 +#ifndef __COMMON_H__ +#define __COMMON_H__ #include -#include #include - -#include +#include #include +#include -/* 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__ */ diff --git a/src/dhcp.c b/src/dhcp.c deleted file mode 100644 index 0720fa9..0000000 --- a/src/dhcp.c +++ /dev/null @@ -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 -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#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); - } -} - diff --git a/src/dhcp.h b/src/dhcp.h deleted file mode 100644 index ffc873b..0000000 --- a/src/dhcp.h +++ /dev/null @@ -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 diff --git a/src/dhcpc/Makefile.am b/src/dhcpc/Makefile.am deleted file mode 100644 index 5c159a2..0000000 --- a/src/dhcpc/Makefile.am +++ /dev/null @@ -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) - diff --git a/src/dhcpc/common.c b/src/dhcpc/common.c deleted file mode 100644 index e3bc4d0..0000000 --- a/src/dhcpc/common.c +++ /dev/null @@ -1,441 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Rewrite by Russ Dill July 2001 - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ - -#include -#include - -#include -#include - -#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 - ); -} diff --git a/src/dhcpc/common.h b/src/dhcpc/common.h deleted file mode 100644 index afc4c3a..0000000 --- a/src/dhcpc/common.h +++ /dev/null @@ -1,317 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Russ Dill September 2001 - * Rewritten by Vladimir Oleynik (C) 2003 - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - */ -#ifndef UDHCP_COMMON_H -#define UDHCP_COMMON_H 1 - -#include -#include - -#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 diff --git a/src/dhcpc/dhcpc.c b/src/dhcpc/dhcpc.c deleted file mode 100644 index e3c4563..0000000 --- a/src/dhcpc/dhcpc.c +++ /dev/null @@ -1,1444 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * udhcp client - * - * Russ Dill 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 -#include -#include -#include -#include - -#include - -#include - -/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ -#define WANT_PIDFILE 1 -#include "common.h" -#include "extra.h" - -//#include "dhcpd.h" -#include "dhcpc.h" - -#include -#include -#include - -#include -#include -#include - -struct client_config_t client_config; - -/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ - -/*** Script execution code ***/ - -/* get a rough idea of how long an option will be (rounding up...) */ -static const uint8_t len_of_option_as_string[] = { - [OPTION_IP ] = sizeof("255.255.255.255 "), - [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, - [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), - [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "), - [OPTION_STRING ] = 1, - [OPTION_STRING_HOST ] = 1, -#if ENABLE_FEATURE_UDHCP_RFC3397 - [OPTION_DNS_STRING ] = 1, /* unused */ - /* Hmmm, this severely overestimates size if SIP_SERVERS option - * is in domain name form: N-byte option in binary form - * mallocs ~16*N bytes. But it is freed almost at once. - */ - [OPTION_SIP_SERVERS ] = sizeof("255.255.255.255 "), -#endif -// [OPTION_BOOLEAN ] = sizeof("yes "), - [OPTION_U8 ] = sizeof("255 "), - [OPTION_U16 ] = sizeof("65535 "), -// [OPTION_S16 ] = sizeof("-32768 "), - [OPTION_U32 ] = sizeof("4294967295 "), - [OPTION_S32 ] = sizeof("-2147483684 "), -}; - -/* note: ip is a pointer to an IP in network order, possibly misaliged */ -static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) -{ - return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); -} - -/* really simple implementation, just count the bits */ -static int mton(uint32_t mask) -{ - int i = 0; - mask = ntohl(mask); /* 111110000-like bit pattern */ - while (mask) { - i++; - mask <<= 1; - } - return i; -} - -/* Check if a given label represents a valid DNS label - * Return pointer to the first character after the label upon success, - * NULL otherwise. - * See RFC1035, 2.3.1 - */ -/* We don't need to be particularly anal. For example, allowing _, hyphen - * at the end, or leading and trailing dots would be ok, since it - * can't be used for attacks. (Leading hyphen can be, if someone uses - * cmd "$hostname" - * in the script: then hostname may be treated as an option) - */ -static const char *valid_domain_label(const char *label) -{ - unsigned char ch; - unsigned pos = 0; - - for (;;) { - ch = *label; - if ((ch|0x20) < 'a' || (ch|0x20) > 'z') { - if (pos == 0) { - /* label must begin with letter */ - return NULL; - } - if (ch < '0' || ch > '9') { - if (ch == '\0' || ch == '.') - return label; - /* DNS allows only '-', but we are more permissive */ - if (ch != '-' && ch != '_') - return NULL; - } - } - label++; - pos++; - //Do we want this? - //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */ - // return NULL; - } -} - -/* Check if a given name represents a valid DNS name */ -/* See RFC1035, 2.3.1 */ -static int good_hostname(const char *name) -{ - //const char *start = name; - - for (;;) { - name = valid_domain_label(name); - if (!name) - return 0; - if (!name[0]) - return 1; - //Do we want this? - //return ((name - start) < 1025); /* NS_MAXDNAME */ - name++; - } -} - -#define DHCPC_PIPEOUT_HAS_IP 0x01 -#define DHCPC_PIPEOUT_HAS_SERVER_IP 0x02 -#define DHCPC_PIPEOUT_HAS_OPTS 0x04 - -static void fill_dhcpc_pipe_data (struct dhcp_packet *packet, unsigned char *output_buffer, int *output_len) { - int g; - uint8_t *option; - unsigned char opt_code, byte; - uint8_t type; - int optlen, len; - char *dest; - - uint8_t critical_opts[] = { - 0x01, /* DHCP_SUBNET */ - 0x03, /* DHCP_ROUTER */ - 0x06, /* DHCP_DNS_SERVER */ - 0x0c, /* DHCP_HOST_NAME */ - 0x0f, /* DHCP_DOMAIN_NAME */ - 0x2a, /* DHCP_NTP_SERVER */ - 0 - }; - - uint8_t opts_types[] = { - OPTION_IP, - OPTION_IP | OPTION_LIST, - OPTION_IP | OPTION_LIST, - OPTION_STRING_HOST, - OPTION_STRING_HOST, - OPTION_IP | OPTION_LIST, - }; - - if (packet == NULL) { - /* Enviar un cero para indicar que no hay ni IP o server address */ - byte = 0; - output_buffer[*output_len] = byte; - (*output_len)++; - - return; - } - - byte = DHCPC_PIPEOUT_HAS_IP | DHCPC_PIPEOUT_HAS_OPTS; - - if (packet->siaddr_nip) { - byte |= DHCPC_PIPEOUT_HAS_SERVER_IP; - } - - /* Enviar la lista de banderas activadas para esta configuración */ - output_buffer[*output_len] = byte; - (*output_len)++; - - /* Enviar la IP */ - memcpy (&output_buffer[*output_len], &packet->yiaddr, 4); - *output_len += 4; - - /* Enviar el servidor IP si existe */ - if (packet->siaddr_nip) { - memcpy (&output_buffer[*output_len], &packet->siaddr_nip, 4); - *output_len += 4; - } - - g = 0; - while (critical_opts[g] != 0) { - opt_code = critical_opts[g]; - option = udhcp_get_option(packet, opt_code); - - if (option) { - type = opts_types[g] & OPTION_TYPE_MASK; - optlen = dhcp_option_lengths[type]; - - byte = opt_code; - output_buffer[*output_len] = byte; - (*output_len)++; - - len = option[-1]; - if (opts_types[g] & OPTION_LIST) { - /* Para las opciones que son lista, enviar un byte indicando cuantos elementos hay en la lista */ - byte = len / optlen; - output_buffer[*output_len] = byte; - (*output_len)++; - } - - while (len >= optlen) { - switch (type) { - case OPTION_IP: - memcpy (&output_buffer[*output_len], option, 4); - *output_len += 4; - break; - case OPTION_STRING_HOST: - dest = malloc (sizeof (char) * (len + 3)); - memcpy (dest, option, len); - dest[len] = '\0'; - if (type == OPTION_STRING_HOST && !good_hostname(dest)) { - memcpy (&output_buffer[*output_len], "bad", 4); - *output_len += 4; - } else { - memcpy (&output_buffer[*output_len], dest, len + 1); - *output_len += (len + 1); - } - break; - } - - if (type == OPTION_STRING_HOST) { - break; - } - - option += optlen; - len -= optlen; - } - } - g++; - } - - /* Enviar un 255 para indicar el final de las opciones */ - byte = 255; - output_buffer[*output_len] = byte; - (*output_len)++; -} - -/* Call a script with a par file and env vars */ -static void udhcp_run_script (int output_pipe, struct dhcp_packet *packet, const char *name) { - unsigned char type; - - unsigned char output_buffer[1024]; - int output_len = 0; - - if (strcmp (name, "deconfig") == 0) { - type = 1; - } else if (strcmp (name, "leasefail") == 0) { - type = 2; - } else if (strcmp (name, "bound") == 0) { - type = 3; - } else if (strcmp (name, "renew") == 0) { - type = 4; - } else if (strcmp (name, "nak") == 0) { - type = 5; - } - - output_buffer[output_len] = type; - output_len++; - - fill_dhcpc_pipe_data (packet, output_buffer, &output_len); - - /* Enviar todos los datos de un solo jalón, para que el otro extremo los lea en un solo bloque */ - write (output_pipe, output_buffer, output_len); -} - - -/*** Sending/receiving packets ***/ - -static uint32_t random_xid(void) -{ - return rand(); -} - -/* Initialize the packet with the proper defaults */ -static void init_packet(struct dhcp_packet *packet, char type) -{ - uint16_t secs; - - /* Fill in: op, htype, hlen, cookie fields; message type option: */ - udhcp_init_header(packet, type); - - packet->xid = random_xid(); - - client_config.last_secs = monotonic_sec(); - if (client_config.first_secs == 0) - client_config.first_secs = client_config.last_secs; - secs = client_config.last_secs - client_config.first_secs; - packet->secs = htons(secs); - - memcpy(packet->chaddr, client_config.client_mac, 6); - if (client_config.clientid) - udhcp_add_binary_option(packet, client_config.clientid); -} - -static void add_client_options(struct dhcp_packet *packet) -{ - int i, end, len; - - udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); - - /* Add a "param req" option with the list of options we'd like to have - * from stubborn DHCP servers. Pull the data from the struct in common.c. - * No bounds checking because it goes towards the head of the packet. */ - end = udhcp_end_option(packet->options); - len = 0; - for (i = 1; i < DHCP_END; i++) { - if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) { - packet->options[end + OPT_DATA + len] = i; - len++; - } - } - if (len) { - packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; - packet->options[end + OPT_LEN] = len; - packet->options[end + OPT_DATA + len] = DHCP_END; - } - - if (client_config.vendorclass) - udhcp_add_binary_option(packet, client_config.vendorclass); - if (client_config.hostname) - udhcp_add_binary_option(packet, client_config.hostname); - if (client_config.fqdn) - udhcp_add_binary_option(packet, client_config.fqdn); - - /* Request broadcast replies if we have no IP addr - if ((option_mask32 & OPT_B) && packet->ciaddr == 0) - packet->flags |= htons(BROADCAST_FLAG);*/ - - /* Add -x options if any */ - { - struct option_set *curr = client_config.options; - while (curr) { - udhcp_add_binary_option(packet, curr->data); - curr = curr->next; - } -// if (client_config.sname) -// strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1); -// if (client_config.boot_file) -// strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); - } - - // This will be needed if we remove -V VENDOR_STR in favor of - // -x vendor:VENDOR_STR - //if (!udhcp_find_option(packet.options, DHCP_VENDOR)) - // /* not set, set the default vendor ID */ - // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... -} - -/* RFC 2131 - * 4.4.4 Use of broadcast and unicast - * - * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM - * messages, unless the client knows the address of a DHCP server. - * The client unicasts DHCPRELEASE messages to the server. Because - * the client is declining the use of the IP address supplied by the server, - * the client broadcasts DHCPDECLINE messages. - * - * When the DHCP client knows the address of a DHCP server, in either - * INIT or REBOOTING state, the client may use that address - * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address. - * The client may also use unicast to send DHCPINFORM messages - * to a known DHCP server. If the client receives no response to DHCP - * messages sent to the IP address of a known DHCP server, the DHCP - * client reverts to using the IP broadcast address. - */ - -static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) -{ - return udhcp_send_raw_packet(packet, - /*src*/ INADDR_ANY, CLIENT_PORT, - /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, - client_config.ifindex); -} - -static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server) -{ - if (server) - return udhcp_send_kernel_packet(packet, - ciaddr, CLIENT_PORT, - server, SERVER_PORT); - return raw_bcast_from_client_config_ifindex(packet); -} - -/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ -/* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_discover(uint32_t xid, uint32_t requested) -{ - struct dhcp_packet packet; - - /* Fill in: op, htype, hlen, cookie, chaddr fields, - * random xid field (we override it below), - * client-id option (unless -C), message type option: - */ - init_packet(&packet, DHCPDISCOVER); - - packet.xid = xid; - if (requested) - udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); - - /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, - * "param req" option according to -O, options specified with -x - */ - add_client_options(&packet); - - fprintf (stderr, "Sending discover..."); - return raw_bcast_from_client_config_ifindex(&packet); -} - -/* Broadcast a DHCP request message */ -/* RFC 2131 3.1 paragraph 3: - * "The client _broadcasts_ a DHCPREQUEST message..." - */ -/* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) -{ - struct dhcp_packet packet; - struct in_addr addr; - -/* - * RFC 2131 4.3.2 DHCPREQUEST message - * ... - * If the DHCPREQUEST message contains a 'server identifier' - * option, the message is in response to a DHCPOFFER message. - * Otherwise, the message is a request to verify or extend an - * existing lease. If the client uses a 'client identifier' - * in a DHCPREQUEST message, it MUST use that same 'client identifier' - * in all subsequent messages. If the client included a list - * of requested parameters in a DHCPDISCOVER message, it MUST - * include that list in all subsequent messages. - */ - /* Fill in: op, htype, hlen, cookie, chaddr fields, - * random xid field (we override it below), - * client-id option (unless -C), message type option: - */ - init_packet(&packet, DHCPREQUEST); - - packet.xid = xid; - udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); - - udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); - - /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, - * "param req" option according to -O, and options specified with -x - */ - add_client_options(&packet); - - addr.s_addr = requested; - fprintf (stderr, "Sending select for %s...", inet_ntoa(addr)); - return raw_bcast_from_client_config_ifindex(&packet); -} - -/* Unicast or broadcast a DHCP renew message */ -/* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) -{ - struct dhcp_packet packet; - -/* - * RFC 2131 4.3.2 DHCPREQUEST message - * ... - * DHCPREQUEST generated during RENEWING state: - * - * 'server identifier' MUST NOT be filled in, 'requested IP address' - * option MUST NOT be filled in, 'ciaddr' MUST be filled in with - * client's IP address. In this situation, the client is completely - * configured, and is trying to extend its lease. This message will - * be unicast, so no relay agents will be involved in its - * transmission. Because 'giaddr' is therefore not filled in, the - * DHCP server will trust the value in 'ciaddr', and use it when - * replying to the client. - */ - /* Fill in: op, htype, hlen, cookie, chaddr fields, - * random xid field (we override it below), - * client-id option (unless -C), message type option: - */ - init_packet(&packet, DHCPREQUEST); - - packet.xid = xid; - packet.ciaddr = ciaddr; - - /* Add options: maxsize, - * optionally: hostname, fqdn, vendorclass, - * "param req" option according to -O, and options specified with -x - */ - add_client_options(&packet); - - fprintf (stderr, "Sending renew..."); - return bcast_or_ucast(&packet, ciaddr, server); -} - -#if ENABLE_FEATURE_UDHCPC_ARPING -/* Broadcast a DHCP decline message */ -/* NOINLINE: limit stack usage in caller */ -static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) -{ - struct dhcp_packet packet; - - /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, - * client-id option (unless -C), message type option: - */ - init_packet(&packet, DHCPDECLINE); - -#if 0 - /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, - * but in case the server is buggy and wants DHCPDECLINE's xid - * to match the xid which started entire handshake, - * we use the same xid we used in initial DHCPDISCOVER: - */ - packet.xid = xid; -#endif - /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ - udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); - - udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); - - fprintf(stderr, "Sending decline..."); - return raw_bcast_from_client_config_ifindex(&packet); -} -#endif - -/* Unicast a DHCP release message */ -static int send_release(uint32_t server, uint32_t ciaddr) -{ - struct dhcp_packet packet; - - /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, - * client-id option (unless -C), message type option: - */ - init_packet(&packet, DHCPRELEASE); - - /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ - packet.ciaddr = ciaddr; - - udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); - - fprintf (stderr, "Sending release..."); - /* Note: normally we unicast here since "server" is not zero. - * However, there _are_ people who run "address-less" DHCP servers, - * and reportedly ISC dhcp client and Windows allow that. - */ - return bcast_or_ucast(&packet, ciaddr, server); -} - -/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ -/* NOINLINE: limit stack usage in caller */ -static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) -{ - int bytes; - struct ip_udp_dhcp_packet packet; - uint16_t check; - unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - - /* used to use just safe_read(fd, &packet, sizeof(packet)) - * but we need to check for TP_STATUS_CSUMNOTREADY :( - */ - iov.iov_base = &packet; - iov.iov_len = sizeof(packet); - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = sizeof(cmsgbuf); - for (;;) { - bytes = recvmsg(fd, &msg, 0); - if (bytes < 0) { - if (errno == EINTR) - continue; - log1("Packet read error, ignoring"); - /* NB: possible down interface, etc. Caller should pause. */ - return bytes; /* returns -1 */ - } - break; - } - - if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { - log1("Packet is too short, ignoring"); - return -2; - } - - if (bytes < ntohs(packet.ip.tot_len)) { - /* packet is bigger than sizeof(packet), we did partial read */ - log1("Oversized packet, ignoring"); - return -2; - } - - /* ignore any extra garbage bytes */ - bytes = ntohs(packet.ip.tot_len); - - /* make sure its the right packet for us, and that it passes sanity checks */ - if (packet.ip.protocol != IPPROTO_UDP - || packet.ip.version != IPVERSION - || packet.ip.ihl != (sizeof(packet.ip) >> 2) - || packet.udp.dest != htons(CLIENT_PORT) - /* || bytes > (int) sizeof(packet) - can't happen */ - || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip)) - ) { - log1("Unrelated/bogus packet, ignoring"); - return -2; - } - - /* verify IP checksum */ - check = packet.ip.check; - packet.ip.check = 0; - if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { - log1("Bad IP header checksum, ignoring"); - return -2; - } - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_PACKET - && cmsg->cmsg_type == PACKET_AUXDATA - ) { - /* some VMs don't checksum UDP and TCP data - * they send to the same physical machine, - * here we detect this case: - */ - struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); - if (aux->tp_status & TP_STATUS_CSUMNOTREADY) - goto skip_udp_sum_check; - } - } - - /* verify UDP checksum. IP header has to be modified for this */ - memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); - /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ - packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ - check = packet.udp.check; - packet.udp.check = 0; - if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { - log1("Packet with bad UDP checksum received, ignoring"); - return -2; - } - skip_udp_sum_check: - - if (packet.data.cookie != htonl(DHCP_MAGIC)) { - fprintf (stderr, "Packet with bad magic, ignoring"); - return -2; - } - - //log1("Received a packet"); - udhcp_dump_packet(&packet.data); - - bytes -= sizeof(packet.ip) + sizeof(packet.udp); - memcpy(dhcp_pkt, &packet.data, bytes); - return bytes; -} - - -/*** Main ***/ - -static int sockfd = -1; - -#define LISTEN_NONE 0 -#define LISTEN_KERNEL 1 -#define LISTEN_RAW 2 -static smallint listen_mode; - -/* initial state: (re)start DHCP negotiation */ -#define INIT_SELECTING 0 -/* discover was sent, DHCPOFFER reply received */ -#define REQUESTING 1 -/* select/renew was sent, DHCPACK reply received */ -#define BOUND 2 -/* half of lease passed, want to renew it by sending unicast renew requests */ -#define RENEWING 3 -/* renew requests were not answered, lease is almost over, send broadcast renew */ -#define REBINDING 4 -/* manually requested renew (SIGUSR1) */ -#define RENEW_REQUESTED 5 -/* release, possibly manually requested (SIGUSR2) */ -#define RELEASED 6 -static smallint state; - -static int udhcp_raw_socket(int ifindex) -{ - int fd; - struct sockaddr_ll sock; - - /* - * Comment: - * - * I've selected not to see LL header, so BPF doesn't see it, too. - * The filter may also pass non-IP and non-ARP packets, but we do - * a more complete check when receiving the message in userspace. - * - * and filter shamelessly stolen from: - * - * http://www.flamewarmaster.de/software/dhcpclient/ - * - * There are a few other interesting ideas on that page (look under - * "Motivation"). Use of netlink events is most interesting. Think - * of various network servers listening for events and reconfiguring. - * That would obsolete sending HUP signals and/or make use of restarts. - * - * Copyright: 2006, 2007 Stefan Rompf . - * License: GPL v2. - * - * TODO: make conditional? - */ - static const struct sock_filter filter_instr[] = { - /* load 9th byte (protocol) */ - BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), - /* jump to L1 if it is IPPROTO_UDP, else to L4 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), - /* L1: load halfword from offset 6 (flags and frag offset) */ - BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), - /* jump to L4 if any bits in frag offset field are set, else to L2 */ - BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), - /* L2: skip IP header (load index reg with header len) */ - BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), - /* load udp destination port from halfword[header_len + 2] */ - BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), - /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), - /* L3: accept packet */ - BPF_STMT(BPF_RET|BPF_K, 0xffffffff), - /* L4: discard packet */ - BPF_STMT(BPF_RET|BPF_K, 0), - }; - static const struct sock_fprog filter_prog = { - .len = sizeof(filter_instr) / sizeof(filter_instr[0]), - /* casting const away: */ - .filter = (struct sock_filter *) filter_instr, - }; - - log1("Opening raw socket on ifindex %d", ifindex); //log2? - - fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); - log1("Got raw socket fd"); //log2? - - sock.sll_family = AF_PACKET; - sock.sll_protocol = htons(ETH_P_IP); - sock.sll_ifindex = ifindex; - xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); - - if (CLIENT_PORT == 68) { - /* Use only if standard port is in use */ - /* Ignoring error (kernel may lack support for this) */ - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, - sizeof(filter_prog)) >= 0) - log1("Attached filter to raw socket fd"); // log? - } - - if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, - &const_int_1, sizeof(int)) < 0 - ) { - if (errno != ENOPROTOOPT) { - //log1("Can't set PACKET_AUXDATA on raw socket"); - } - } - - log1("Created raw socket"); - - return fd; -} - -static void change_listen_mode(int new_mode) -{ - /*log1("Entering listen mode: %s", - new_mode != LISTEN_NONE - ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") - : "none" - );*/ - - listen_mode = new_mode; - if (sockfd >= 0) { - close(sockfd); - sockfd = -1; - } - if (new_mode == LISTEN_KERNEL) - sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); - else if (new_mode != LISTEN_NONE) - sockfd = udhcp_raw_socket(client_config.ifindex); - /* else LISTEN_NONE: sockfd stays closed */ -} - -/* Called only on SIGUSR1 */ -static void perform_renew(int pipe_fd) -{ - fprintf (stderr, "Performing a DHCP renew"); - switch (state) { - case BOUND: - change_listen_mode(LISTEN_KERNEL); - case RENEWING: - case REBINDING: - state = RENEW_REQUESTED; - break; - case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ - /* FIXME: Correr script aquí */ - udhcp_run_script(pipe_fd, NULL, "deconfig"); - case REQUESTING: - case RELEASED: - change_listen_mode(LISTEN_RAW); - state = INIT_SELECTING; - break; - case INIT_SELECTING: - break; - } -} - -static void perform_release(int pipe_fd, uint32_t server_addr, uint32_t requested_ip) -{ - char buffer[sizeof("255.255.255.255")]; - struct in_addr temp_addr; - - /* send release packet */ - if (state == BOUND || state == RENEWING || state == REBINDING) { - temp_addr.s_addr = server_addr; - strcpy(buffer, inet_ntoa(temp_addr)); - temp_addr.s_addr = requested_ip; - fprintf (stderr, "Unicasting a release of %s to %s", - inet_ntoa(temp_addr), buffer); - send_release(server_addr, requested_ip); /* unicast */ - /* FIXME: Aquí SCRIPT */ - udhcp_run_script (pipe_fd, NULL, "deconfig"); - } - fprintf (stderr, "Entering released state"); - - change_listen_mode(LISTEN_NONE); - state = RELEASED; -} - -static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) -{ - uint8_t *storage; - int len = strnlen(str, 255); - storage = xzalloc(len + extra + OPT_DATA); - storage[OPT_CODE] = code; - storage[OPT_LEN] = len + extra; - memcpy(storage + extra + OPT_DATA, str, len); - return storage; -} - -#if BB_MMU -static void client_background(void) -{ - bb_daemonize(0); - logmode &= ~LOGMODE_STDIO; - /* rewrite pidfile, as our pid is different now */ - write_pidfile(client_config.pidfile); -} -#endif - -//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 -//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ -//usage:#else -//usage:# define IF_UDHCP_VERBOSE(...) -//usage:#endif -//usage:#define udhcpc_trivial_usage -//usage: "[-fbq"IF_UDHCP_VERBOSE("v")IF_FEATURE_UDHCPC_ARPING("a")"RB] [-t N] [-T SEC] [-A SEC/-n]\n" -//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" -//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." -//usage:#define udhcpc_full_usage "\n" -//usage: IF_LONG_OPTS( -//usage: "\n -i,--interface IFACE Interface to use (default eth0)" -//usage: IF_FEATURE_UDHCP_PORT( -//usage: "\n -P,--client-port PORT Use PORT (default 68)" -//usage: ) -//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" -//usage: "\n -p,--pidfile FILE Create pidfile" -//usage: "\n -B,--broadcast Request broadcast replies" -//usage: "\n -t,--retries N Send up to N discover packets (default 3)" -//usage: "\n -T,--timeout SEC Pause between packets (default 3)" -//usage: "\n -A,--tryagain SEC Wait if lease is not obtained (default 20)" -//usage: "\n -n,--now Exit if lease is not obtained" -//usage: "\n -q,--quit Exit after obtaining lease" -//usage: "\n -R,--release Release IP on exit" -//usage: "\n -f,--foreground Run in foreground" -//usage: USE_FOR_MMU( -//usage: "\n -b,--background Background if lease is not obtained" -//usage: ) -//usage: "\n -S,--syslog Log to syslog too" -//usage: IF_FEATURE_UDHCPC_ARPING( -//usage: "\n -a,--arping Use arping to validate offered address" -//usage: ) -//usage: "\n -r,--request IP Request this IP address" -//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" -//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" -//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" -//usage: "\n Examples of string, numeric, and hex byte opts:" -//usage: "\n -x hostname:bbox - option 12" -//usage: "\n -x lease:3600 - option 51 (lease time)" -//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" -//usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" -//usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" -//usage: "\n -C,--clientid-none Don't send MAC as client identifier" -//usage: IF_UDHCP_VERBOSE( -//usage: "\n -v Verbose" -//usage: ) -//usage: ) -//usage: IF_NOT_LONG_OPTS( -//usage: "\n -i IFACE Interface to use (default eth0)" -//usage: IF_FEATURE_UDHCP_PORT( -//usage: "\n -P PORT Use PORT (default 68)" -//usage: ) -//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" -//usage: "\n -p FILE Create pidfile" -//usage: "\n -B Request broadcast replies" -//usage: "\n -t N Send up to N discover packets (default 3)" -//usage: "\n -T SEC Pause between packets (default 3)" -//usage: "\n -A SEC Wait if lease is not obtained (default 20)" -//usage: "\n -n Exit if lease is not obtained" -//usage: "\n -q Exit after obtaining lease" -//usage: "\n -R Release IP on exit" -//usage: "\n -f Run in foreground" -//usage: USE_FOR_MMU( -//usage: "\n -b Background if lease is not obtained" -//usage: ) -//usage: "\n -S Log to syslog too" -//usage: IF_FEATURE_UDHCPC_ARPING( -//usage: "\n -a Use arping to validate offered address" -//usage: ) -//usage: "\n -r IP Request this IP address" -//usage: "\n -o Don't request any options (unless -O is given)" -//usage: "\n -O OPT Request option OPT from server (cumulative)" -//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" -//usage: "\n Examples of string, numeric, and hex byte opts:" -//usage: "\n -x hostname:bbox - option 12" -//usage: "\n -x lease:3600 - option 51 (lease time)" -//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" -//usage: "\n -F NAME Ask server to update DNS mapping for NAME" -//usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" -//usage: "\n -C Don't send MAC as client identifier" -//usage: IF_UDHCP_VERBOSE( -//usage: "\n -v Verbose" -//usage: ) -//usage: ) -//usage: "\nSignals:" -//usage: "\n USR1 Renew lease" -//usage: "\n USR2 Release lease" - - -int udhcpc_main(int pipe_fd, char *interface) -{ - uint8_t *temp, *message; - // str_V se usa como argumento -V,--vendorclass VENDOR - // - const char *str_V, *str_h, *str_F, *str_r; - void *clientid_mac_ptr; - /*llist_t *list_O = NULL; - llist_t *list_x = NULL;*/ - int tryagain_timeout = 20; - int discover_timeout = 3; - int discover_retries = 3; - uint32_t server_addr = server_addr; /* for compiler */ - uint32_t requested_ip = 0; - uint32_t xid = xid; /* for compiler */ - int packet_num; - int timeout; /* must be signed */ - unsigned already_waited_sec; - unsigned opt; - int max_fd; - int retval; - fd_set rfds; - - /* Default options */ - /*IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) - IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)*/ - client_config.interface = interface; - //client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; - str_V = "nidhcpc 0.1"; - -#if 0 - while (list_O) { - char *optstr = llist_pop(&list_O); - unsigned n = bb_strtou(optstr, NULL, 0); - if (errno || n > 254) { - n = udhcp_option_idx(optstr); - n = dhcp_optflags[n].code; - } - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - } -#endif - /* Agregar la opciones request */ - unsigned n; - n = 0x01; // DHCP_SUBNET - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - - n = 0x03; // DHCP_ROUTER - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - - n = 0x06; // DHCP_DNS_SERVER - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - - n = 0x0c; // DHCP_HOST_NAME - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - - n = 0x0f; // DHCP_DOMAIN_NAME - client_config.opt_mask[n >> 3] |= 1 << (n & 7); - - n = 0x2a; // DHCP_NTP_SERVER - client_config.opt_mask[n >> 3] |= 1 << (n & 7); -#if 0 - while (list_x) { - char *optstr = llist_pop(&list_x); - char *colon = strchr(optstr, ':'); - if (colon) - *colon = ' '; - /* now it looks similar to udhcpd's config file line: - * "optname optval", using the common routine: */ - udhcp_str2optset(optstr, &client_config.options); - } -#endif - if (udhcp_read_interface(client_config.interface, - &client_config.ifindex, - NULL, - client_config.client_mac) - ) { - return 1; - } - - clientid_mac_ptr = NULL; - /* not suppressed and not set, set the default client ID */ - client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); - client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ - clientid_mac_ptr = client_config.clientid + OPT_DATA+1; - memcpy(clientid_mac_ptr, client_config.client_mac, 6); - if (str_V[0] != '\0') { - // can drop -V, str_V, client_config.vendorclass, - // but need to add "vendor" to the list of recognized - // string opts for this to work; - // and need to tweak add_client_options() too... - // ...so the question is, should we? - //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); - client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); - } - - openlog("udhcpc", LOG_PID, LOG_DAEMON); - //logmode |= LOGMODE_SYSLOG; - - /* Make sure fd 0,1,2 are open */ - //bb_sanitize_stdio(); - /* Equivalent of doing a fflush after every \n */ - //setlinebuf(stdout); - /* Create pidfile */ - //write_pidfile(client_config.pidfile); - /* Goes to stdout (unless NOMMU) and possibly syslog */ - //bb_info_msg("%s (v"BB_VER") started", applet_name); - /* Set up the signal pipe */ - udhcp_sp_setup(); - /* We want random_xid to be random... */ - srand((unsigned int) getpid ()); - - state = INIT_SELECTING; - /* FIXME: AQUI SCRIPT */ - udhcp_run_script (pipe_fd, NULL, "deconfig"); - change_listen_mode(LISTEN_RAW); - packet_num = 0; - timeout = 0; - already_waited_sec = 0; - - /* Main event loop. select() waits on signal pipe and possibly - * on sockfd. - * "continue" statements in code below jump to the top of the loop. - */ - for (;;) { - struct timeval tv; - struct dhcp_packet packet; - /* silence "uninitialized!" warning */ - unsigned timestamp_before_wait = timestamp_before_wait; - - //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); - - /* Was opening raw or udp socket here - * if (listen_mode != LISTEN_NONE && sockfd < 0), - * but on fast network renew responses return faster - * than we open sockets. Thus this code is moved - * to change_listen_mode(). Thus we open listen socket - * BEFORE we send renew request (see "case BOUND:"). */ - - max_fd = udhcp_sp_fd_set(&rfds, sockfd); - - tv.tv_sec = timeout - already_waited_sec; - tv.tv_usec = 0; - retval = 0; - /* If we already timed out, fall through with retval = 0, else... */ - if ((int)tv.tv_sec > 0) { - //log1("Waiting on select %u seconds", (int)tv.tv_sec); - timestamp_before_wait = (unsigned)monotonic_sec(); - retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); - if (retval < 0) { - /* EINTR? A signal was caught, don't panic */ - if (errno == EINTR) { - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; - continue; - } - /* Else: an error occured, panic! */ - fprintf (stderr, "Error: select ()\n"); - exit (EXIT_FAILURE); - } - } - - /* If timeout dropped to zero, time to become active: - * resend discover/renew/whatever - */ - if (retval == 0) { - /* When running on a bridge, the ifindex may have changed - * (e.g. if member interfaces were added/removed - * or if the status of the bridge changed). - * Refresh ifindex and client_mac: - */ - if (udhcp_read_interface(client_config.interface, - &client_config.ifindex, - NULL, - client_config.client_mac) - ) { - goto ret0; /* iface is gone? */ - } - if (clientid_mac_ptr) - memcpy(clientid_mac_ptr, client_config.client_mac, 6); - - /* We will restart the wait in any case */ - already_waited_sec = 0; - - switch (state) { - case INIT_SELECTING: - if (!discover_retries || packet_num < discover_retries) { - if (packet_num == 0) - xid = random_xid(); - /* broadcast */ - send_discover(xid, requested_ip); - timeout = discover_timeout; - packet_num++; - continue; - } - leasefail: - /* FIXME: AQUI SCRIPT */ - udhcp_run_script (pipe_fd, NULL, "leasefail"); - /* wait before trying again */ - timeout = tryagain_timeout; - packet_num = 0; - continue; - case REQUESTING: - if (!discover_retries || packet_num < discover_retries) { - /* send broadcast select packet */ - send_select(xid, server_addr, requested_ip); - timeout = discover_timeout; - packet_num++; - continue; - } - /* Timed out, go back to init state. - * "discover...select...discover..." loops - * were seen in the wild. Treat them similarly - * to "no response to discover" case */ - change_listen_mode(LISTEN_RAW); - state = INIT_SELECTING; - goto leasefail; - case BOUND: - /* 1/2 lease passed, enter renewing state */ - state = RENEWING; - client_config.first_secs = 0; /* make secs field count from 0 */ - change_listen_mode(LISTEN_KERNEL); - //log1("Entering renew state"); - /* fall right through */ - case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ - case_RENEW_REQUESTED: - case RENEWING: - if (timeout > 60) { - /* send an unicast renew request */ - /* Sometimes observed to fail (EADDRNOTAVAIL) to bind - * a new UDP socket for sending inside send_renew. - * I hazard to guess existing listening socket - * is somehow conflicting with it, but why is it - * not deterministic then?! Strange. - * Anyway, it does recover by eventually failing through - * into INIT_SELECTING state. - */ - send_renew(xid, server_addr, requested_ip); - timeout >>= 1; - continue; - } - /* Timed out, enter rebinding state */ - //log1("Entering rebinding state"); - state = REBINDING; - /* fall right through */ - case REBINDING: - /* Switch to bcast receive */ - change_listen_mode(LISTEN_RAW); - /* Lease is *really* about to run out, - * try to find DHCP server using broadcast */ - if (timeout > 0) { - /* send a broadcast renew request */ - send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); - timeout >>= 1; - continue; - } - /* Timed out, enter init state */ - fprintf (stderr, "Lease lost, entering init state"); - /* FIXME: AQUI SCRIPT */ - udhcp_run_script (pipe_fd, NULL, "deconfig"); - state = INIT_SELECTING; - client_config.first_secs = 0; /* make secs field count from 0 */ - /*timeout = 0; - already is */ - packet_num = 0; - continue; - /* case RELEASED: */ - } - /* yah, I know, *you* say it would never happen */ - timeout = INT_MAX; - continue; /* back to main loop */ - } /* if select timed out */ - - /* select() didn't timeout, something happened */ - - /* Is it a signal? */ - /* note: udhcp_sp_read checks FD_ISSET before reading */ - switch (udhcp_sp_read(&rfds)) { - case SIGUSR1: - fprintf (stderr, "SIGUSR1\n"); - client_config.first_secs = 0; /* make secs field count from 0 */ - already_waited_sec = 0; - perform_renew(pipe_fd); - if (state == RENEW_REQUESTED) { - /* We might be either on the same network - * (in which case renew might work), - * or we might be on a completely different one - * (in which case renew won't ever succeed). - * For the second case, must make sure timeout - * is not too big, or else we can send - * futile renew requests for hours. - * (Ab)use -A TIMEOUT value (usually 20 sec) - * as a cap on the timeout. - */ - if (timeout > tryagain_timeout) - timeout = tryagain_timeout; - goto case_RENEW_REQUESTED; - } - /* Start things over */ - packet_num = 0; - /* Kill any timeouts, user wants this to hurry along */ - timeout = 0; - continue; - case SIGUSR2: - perform_release (pipe_fd, server_addr, requested_ip); - timeout = INT_MAX; - continue; - case SIGTERM: - fprintf (stderr, "Received SIGTERM"); - goto ret0; - } - - /* Is it a packet? */ - if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) - continue; /* no */ - - { - int len; - - /* A packet is ready, read it */ - if (listen_mode == LISTEN_KERNEL) - len = udhcp_recv_kernel_packet(&packet, sockfd); - else - len = udhcp_recv_raw_packet(&packet, sockfd); - if (len == -1) { - /* Error is severe, reopen socket */ - fprintf (stderr, "Read error: %s, reopening socket", strerror(errno)); - sleep(discover_timeout); /* 3 seconds by default */ - change_listen_mode(listen_mode); /* just close and reopen */ - } - /* If this packet will turn out to be unrelated/bogus, - * we will go back and wait for next one. - * Be sure timeout is properly decreased. */ - already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; - if (len < 0) - continue; - } - - if (packet.xid != xid) { - log1("xid %x (our is %x), ignoring packet", - (unsigned)packet.xid, (unsigned)xid); - continue; - } - - /* Ignore packets that aren't for us */ - if (packet.hlen != 6 - || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 - ) { -//FIXME: need to also check that last 10 bytes are zero - //log1("chaddr does not match, ignoring packet"); // log2? - continue; - } - - message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); - if (message == NULL) { - fprintf (stderr, "no message type option, ignoring packet"); - continue; - } - - switch (state) { - case INIT_SELECTING: - /* Must be a DHCPOFFER */ - if (*message == DHCPOFFER) { -/* What exactly is server's IP? There are several values. - * Example DHCP offer captured with tchdump: - * - * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src - * BOOTP fields: - * Your-IP 10.34.25.202 - * Server-IP 10.34.32.125 // "next server" IP - * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use) - * DHCP options: - * DHCP-Message Option 53, length 1: Offer - * Server-ID Option 54, length 4: 10.34.255.7 // "server ID" - * Default-Gateway Option 3, length 4: 10.34.25.254 // router - * - * We think that real server IP (one to use in renew/release) - * is one in Server-ID option. But I am not 100% sure. - * IP header's src and Gateway-IP (same in this example) - * might work too. - * "Next server" and router are definitely wrong ones to use, though... - */ -/* We used to ignore pcakets without DHCP_SERVER_ID. - * I've got user reports from people who run "address-less" servers. - * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. - * They say ISC DHCP client supports this case. - */ - server_addr = 0; - temp = udhcp_get_option(&packet, DHCP_SERVER_ID); - if (!temp) { - fprintf (stderr, "no server ID, using 0.0.0.0"); - } else { - /* it IS unaligned sometimes, don't "optimize" */ - move_from_unaligned32(server_addr, temp); - } - /*xid = packet.xid; - already is */ - requested_ip = packet.yiaddr; - - /* enter requesting state */ - state = REQUESTING; - timeout = 0; - packet_num = 0; - already_waited_sec = 0; - } - continue; - case REQUESTING: - case RENEWING: - case RENEW_REQUESTED: - case REBINDING: - if (*message == DHCPACK) { - uint32_t lease_seconds; - struct in_addr temp_addr; - - temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); - if (!temp) { - fprintf (stderr, "no lease time with ACK, using 1 hour lease"); - lease_seconds = 60 * 60; - } else { - /* it IS unaligned sometimes, don't "optimize" */ - move_from_unaligned32(lease_seconds, temp); - lease_seconds = ntohl(lease_seconds); - /* paranoia: must not be too small and not prone to overflows */ - if (lease_seconds < 0x10) - lease_seconds = 0x10; - if (lease_seconds >= 0x10000000) - lease_seconds = 0x0fffffff; - } - /* enter bound state */ - timeout = lease_seconds / 2; - temp_addr.s_addr = packet.yiaddr; - fprintf (stderr, "Lease of %s obtained, lease time %u", - inet_ntoa(temp_addr), (unsigned)lease_seconds); - requested_ip = packet.yiaddr; - /* FIXME: Aquí SCRIPT */ - udhcp_run_script (pipe_fd, &packet, state == REQUESTING ? "bound" : "renew"); - - state = BOUND; - change_listen_mode(LISTEN_NONE); - /* future renew failures should not exit (JM) */ - //opt &= ~OPT_n; - /* make future renew packets use different xid */ - /* xid = random_xid(); ...but why bother? */ - already_waited_sec = 0; - continue; /* back to main loop */ - } - if (*message == DHCPNAK) { - /* return to init state */ - fprintf (stderr, "Received DHCP NAK"); - /* FIXME: AQUI SCRIPT */ - udhcp_run_script (pipe_fd, &packet, "nak"); - if (state != REQUESTING) { - /* FIXME: AQUI SCRIPT */ - udhcp_run_script (pipe_fd, NULL, "deconfig"); - } - change_listen_mode(LISTEN_RAW); - sleep(3); /* avoid excessive network traffic */ - state = INIT_SELECTING; - client_config.first_secs = 0; /* make secs field count from 0 */ - requested_ip = 0; - timeout = 0; - packet_num = 0; - already_waited_sec = 0; - } - continue; - /* case BOUND: - ignore all packets */ - /* case RELEASED: - ignore all packets */ - } - /* back to main loop */ - } /* for (;;) - main loop ends */ - - ret0: - perform_release (pipe_fd, server_addr, requested_ip); - retval = 0; - ret: - /*if (client_config.pidfile) - remove_pidfile has its own check */ - //remove_pidfile(client_config.pidfile); - return retval; -} diff --git a/src/dhcpc/dhcpc.h b/src/dhcpc/dhcpc.h deleted file mode 100644 index b63c58a..0000000 --- a/src/dhcpc/dhcpc.h +++ /dev/null @@ -1,39 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2, see file LICENSE in this source tree. - */ -#include - -#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 diff --git a/src/dhcpc/dhcpd.h b/src/dhcpc/dhcpd.h deleted file mode 100644 index 1ae6d04..0000000 --- a/src/dhcpc/dhcpd.h +++ /dev/null @@ -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 diff --git a/src/dhcpc/extra.c b/src/dhcpc/extra.c deleted file mode 100644 index d640591..0000000 --- a/src/dhcpc/extra.c +++ /dev/null @@ -1,499 +0,0 @@ -#define _GNU_SOURCE -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -#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; -} - diff --git a/src/dhcpc/extra.h b/src/dhcpc/extra.h deleted file mode 100644 index 157978e..0000000 --- a/src/dhcpc/extra.h +++ /dev/null @@ -1,198 +0,0 @@ -#ifndef __EXTRA_H__ -#define __EXTRA_H__ 1 - -#include -#include - -/* 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 -#if defined(__digital__) && defined(__unix__) -# include -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ - || defined(__APPLE__) -# include /* rlimit */ -# include -# define bswap_64 __bswap64 -# define bswap_32 __bswap32 -# define bswap_16 __bswap16 -#else -# include -# include -#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 -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 diff --git a/src/dhcpc/nidhcpc.c b/src/dhcpc/nidhcpc.c deleted file mode 100644 index d5b6594..0000000 --- a/src/dhcpc/nidhcpc.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include - -#include - -#include -#include -#include - -#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; -} diff --git a/src/dhcpc/packet.c b/src/dhcpc/packet.c deleted file mode 100644 index 59a7f4f..0000000 --- a/src/dhcpc/packet.c +++ /dev/null @@ -1,194 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Packet ops - * - * Rewrite by Russ Dill July 2001 - * - * Licensed under GPLv2, see file LICENSE in this source tree. - */ - -#include -#include -#include -#include - -#include "common.h" -#include -#include -#include - -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; -} diff --git a/src/dhcpc/signalpipe.c b/src/dhcpc/signalpipe.c deleted file mode 100644 index 8d03ed4..0000000 --- a/src/dhcpc/signalpipe.c +++ /dev/null @@ -1,86 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Signal pipe infrastructure. A reliable way of delivering signals. - * - * Russ Dill 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 -#include -#include - -#include - -#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; -} diff --git a/src/dhcpc/socket.c b/src/dhcpc/socket.c deleted file mode 100644 index 6326a9d..0000000 --- a/src/dhcpc/socket.c +++ /dev/null @@ -1,122 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * DHCP server client/server socket creation - * - * udhcp client/server - * Copyright (C) 1999 Matthew Ramsay - * Chris Trew - * - * Rewrite by Russ Dill 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 -#include -#include - -#include -#include -#include - -#include - -#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; -} diff --git a/src/gettext.h b/src/gettext.h deleted file mode 100644 index 841b072..0000000 --- a/src/gettext.h +++ /dev/null @@ -1,292 +0,0 @@ -/* Convenience header for conditional use of GNU . - 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 . */ - -#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 - -/* 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 a NOP. We don't include - as well because people using "gettext.h" will not include , - and also including would fail on SunOS 4, whereas - is OK. */ -#if defined(__sun) -# include -#endif - -/* Many header files from the libstdc++ coming with g++ 3.3 or newer include - , which chokes if dcgettext is defined as a macro. So include - it now, to make later inclusions of a NOP. */ -#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) -# include -# if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H -# include -# 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 - -#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 -#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 */ diff --git a/src/interfaces.c b/src/interfaces.c index de20766..5c59a8a 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -2,7 +2,7 @@ * interfaces.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,936 +20,538 @@ * Boston, MA 02110-1301 USA */ -#include -#include #include -#include +#include +#include -#include - -#include -#include - -#include -#include -#include -#include - -#include #include -#include -#include -#include "interfaces.h" -#include "wireless.h" -#include "manager-events.h" +#include -Interface * interfaces_locate_by_index (Interface *list, int index); -static IPv4 * _interfaces_append_ipv4_to_struct (Interface *interface, struct in_addr address, uint32_t prefix); +#include "common.h" -int global_nl_seq = 1; +static int _interfaces_receive_message_interface (struct nl_msg *msg, void *arg, int first_time); +Interface * _interfaces_locate_by_index (GList *list, int index); -typedef struct { - struct nlmsghdr hdr; - struct rtgenmsg gen; -} nl_req_t; - -Interface * interfaces_locate_by_index (Interface *list, int index) { - Interface *iface; - - iface = list; - - while (iface != NULL) { - if (iface->index == index) { - return iface; - } - iface = iface->next; - } - - return NULL; +static int _interfaces_list_first_time (struct nl_msg *msg, void *arg) { + return _interfaces_receive_message_interface (msg, arg, TRUE); } -static IPv4 * _interfaces_append_ipv4_to_struct (Interface *interface, struct in_addr address, uint32_t prefix) { - IPv4 *new_addr, *last; - - new_addr = (IPv4 *) malloc (sizeof (IPv4)); - - new_addr->sin_addr = address; - new_addr->prefix = prefix; - - new_addr->next = NULL; - - if (interface->v4_address == NULL) { - interface->v4_address = new_addr; - } else { - last = interface->v4_address; - - while (last->next != NULL) { - last = last->next; - } - - last->next = new_addr; - } - - return new_addr; +int interface_receive_message_newlink (struct nl_msg *msg, void *arg) { + return _interfaces_receive_message_interface (msg, arg, FALSE); } -IPv4 * _interfaces_serach_ipv4 (Interface *interface, struct in_addr address, uint32_t prefix) { - IPv4 *list; - - list = interface->v4_address; - - while (list != NULL) { - if (list->sin_addr.s_addr == address.s_addr && list->prefix == prefix) { - return list; - } - list = list->next; - } - - return NULL; -} - -static void _interfaces_list_ipv4_address (NetworkInadorHandle *handle, int sock) { - struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ - struct iovec io; - struct ifaddrmsg *ifa; - 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 ifaddrmsg)); - msg_ptr->nlmsg_type = RTM_GETADDR; - 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; - - ifa = (struct ifaddrmsg *) NLMSG_DATA (msg_ptr); - ifa->ifa_family = AF_INET; - - 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 ("Msg type: %i\n", msg_ptr->nlmsg_type); - if (msg_ptr->nlmsg_type == RTM_NEWADDR) { - interfaces_add_or_update_ipv4 (handle, msg_ptr); - } - } - } -} - -void interfaces_add_or_update_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h, int first_time) { - struct ifinfomsg *iface; - struct rtattr *attribute; - int len; - Interface *new, *last; +static int _interfaces_receive_message_interface (struct nl_msg *msg, void *arg, int first_time) { + struct nlmsghdr *reply; + struct ifinfomsg *iface_msg; + int remaining; + struct nlattr *attr; + NetworkInadorHandle *handle = (NetworkInadorHandle *) arg; int was_new = 0; - iface = NLMSG_DATA(h); - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); + Interface *iface; + uint32_t u32data; - //printf ("Mensaje de nueva interfaz: %i\n", iface->ifi_index); - new = interfaces_locate_by_index (handle->interfaces, iface->ifi_index); + reply = nlmsg_hdr (msg); - /* Si el objeto interface no existe, crearlo y ligarlo en la lista de interfaces */ - if (new == NULL) { - //printf ("Creando...\n"); - new = malloc (sizeof (Interface)); - memset (new, 0, sizeof (Interface)); - new->next = NULL; + if (reply->nlmsg_type != RTM_NEWLINK) return NL_SKIP; + + iface_msg = nlmsg_data (reply); + + iface = _interfaces_locate_by_index (handle->interfaces, iface_msg->ifi_index); + + if (iface == NULL) { + /* Crear esta interfaz */ + iface = g_new0 (Interface, 1); - if (handle->interfaces == NULL) { - handle->interfaces = new; - } else { - last = handle->interfaces; - - while (last->next != NULL) { - last = last->next; - } - - last->next = new; - } + handle->interfaces = g_list_append (handle->interfaces, iface); was_new = 1; } - if (iface->ifi_family == AF_BRIDGE) { + if (iface_msg->ifi_family == AF_BRIDGE) { /* Tenemos un evento especial, se está agregando una interfaz a un bridge */ - for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) { - switch(attribute->rta_type) { - case IFLA_MASTER: - memcpy (&new->master_index, RTA_DATA (attribute), 4); - break; + nlmsg_for_each_attr(attr, reply, sizeof (struct ifinfomsg), remaining) { + if (nla_type (attr) == IFLA_MASTER) { + if (nla_len (attr) != 4) { + /* Tamaño incorrecto para el nuevo master */ + return NL_SKIP; + } + u32data = nla_get_u32 (attr); + iface->master_index = u32data; } } - return; + printf ("Interface %d agregada a la interfaz %d (bridge)\n", iface->index, iface->master_index); + /* Generar EVENTO AQUI */ + return NL_SKIP; } - new->ifi_type = iface->ifi_type; + printf ("Interface %d ifi_type: %d\n", iface_msg->ifi_index, iface_msg->ifi_type); + iface->ifi_type = iface_msg->ifi_type; /* TODO: Checar aquí cambio de flags */ - new->flags = iface->ifi_flags; - new->index = iface->ifi_index; + printf ("Interface %d ifi_flags: %d\n", iface_msg->ifi_index, iface_msg->ifi_flags); + iface->flags = iface_msg->ifi_flags; + iface->index = iface_msg->ifi_index; - if (iface->ifi_type == ARPHRD_LOOPBACK) { + if (iface_msg->ifi_type == ARPHRD_LOOPBACK) { /* Es loopback */ - new->is_loopback = 1; + iface->is_loopback = 1; } - if (iface->ifi_type == ARPHRD_ETHER) { - /* Es ethernet */ - } - - for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) { - //printf ("Attribute: %d\n", attribute->rta_type); - switch(attribute->rta_type) { + nlmsg_for_each_attr(attr, reply, sizeof (struct ifinfomsg), remaining) { + switch (nla_type (attr)) { + //nla_len (Attr); case IFLA_IFNAME: - //printf ("Interface %d : %s\n", iface->ifi_index, (char *) RTA_DATA(attribute)); + printf ("Interface %d : %s\n", iface_msg->ifi_index, (char *) nla_data (attr)); // Actualizar el nombre de la interfaz */ - strncpy (new->name, RTA_DATA (attribute), IFNAMSIZ); + /* TODO Revisar cambio de nombre aquí y generar evento */ + strncpy (iface->name, nla_data (attr), IFNAMSIZ); break; case IFLA_ADDRESS: - /* FIXME: ¿Debería no actualizar la mac address siempre? */ - memcpy (new->real_hw, RTA_DATA (attribute), ETHER_ADDR_LEN); + if (nla_len (attr) > ETHER_ADDR_LEN) { + printf ("----- Warning, address es mayor que ETHER_ADDR_LEN\n"); + continue; + } + memcpy (iface->real_hw, nla_data (attr), nla_len (attr)); //printf ("Interface %d has hw addr: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", iface->ifi_index, new->real_hw[0], new->real_hw[1], new->real_hw[2], new->real_hw[3], new->real_hw[4], new->real_hw[5]); break; - case IFLA_WIRELESS: - /* TODO: Procesar enlaces los mensajes de enlaces inalambricos */ - break; case IFLA_MASTER: - if (first_time) { - memcpy (&new->master_index, RTA_DATA (attribute), 4); - //printf ("Interface %d has master: %i\n", iface->ifi_index, new->master_index); + if (nla_len (attr) != 4) { + /* Tamaño incorrecto para el nuevo master */ + continue; } + if (first_time == FALSE) continue; + u32data = nla_get_u32 (attr); + iface->master_index = u32data; + printf ("Interface %d has master: %d\n", iface->index, iface->master_index); break; case IFLA_MTU: - memcpy (&new->mtu, RTA_DATA (attribute), attribute->rta_len); - - //printf ("Interface %d has mtu: %u\n", iface->ifi_index, new->mtu); - break; - case IFLA_OPERSTATE: - { - unsigned int operstate; - memcpy (&operstate, RTA_DATA (attribute), sizeof (operstate)); + if (nla_len (attr) != 4) { + /* Tamaño incorrecto para el mtu */ + continue; } + u32data = nla_get_u32 (attr); + + /* TODO: Revisar cambio de mtu y generar EVENTO aqui */ + iface->mtu = u32data; + + //printf ("Interface %d has mtu: %u\n", iface->ifi_index, new->mtu); break; - /*case IFLA_AF_SPEC: - { - struct rtattr * sub_attr; - int sub_len; - int nla_len; - - sub_len = attribute->rta_len; - - sub_attr = RTA_DATA (attribute); - - while (sub_len > sizeof (sub_attr)) { - nla_len = sub_attr->rta_len; - - if (nla_len > sub_len) { - printf ("Los sub atributos se acabaron prematuramente\n"); - break; - } - printf ("Interface %d, IFLA_AF_SPEC, sub attributo type: %i\n", iface->ifi_index, sub_attr->rta_type); - - sub_len -= RTA_ALIGN (nla_len); - sub_attr = (struct rtattr *) (((char *) sub_attr) + RTA_ALIGN (nla_len)); - } - } - break;*/ case IFLA_LINKINFO: { - struct rtattr * nest_attr; - int nest_size; - int sub_len; + struct nlattr *sub_attr; + int sub_remaining; - nest_size = attribute->rta_len; - nest_attr = RTA_DATA (attribute); - - while (nest_size > sizeof (nest_attr)) { - sub_len = nest_attr->rta_len; - - if (sub_len > nest_size) { - //printf ("Los sub atributos se acabaron prematuramente\n"); - break; + nla_for_each_nested(sub_attr, attr, sub_remaining) { + switch (nla_type (sub_attr)) { + case IFLA_INFO_KIND: + printf ("IFLA_INFO_KIND: %s\n", nla_data (sub_attr)); + if (strcmp (nla_data (sub_attr), "vlan") == 0) { + iface->is_vlan = 1; + + } else if (strcmp (nla_data (sub_attr), "nlmon") == 0) { + iface->is_nlmon = 1; + } else if (strcmp (nla_data (sub_attr), "bridge") == 0) { + iface->is_bridge = 1; + } else if (strcmp (nla_data (sub_attr), "dummy") == 0) { + iface->is_dummy = 1; + } + break; } - //printf ("Interface %d, IFLA_LINKINFO, sub attributo type: %i\n", iface->ifi_index, nest_attr->rta_type); - - if (nest_attr->rta_type == IFLA_INFO_KIND) { - printf ("IFLA_INFO_KIND: %s\n", RTA_DATA (nest_attr)); - if (strcmp (RTA_DATA (nest_attr), "vlan") == 0) { - new->is_vlan = 1; - } else if (strcmp (RTA_DATA (nest_attr), "nlmon") == 0) { - new->is_nlmon = 1; - } else if (strcmp (RTA_DATA (nest_attr), "bridge") == 0) { - new->is_bridge = 1; - } - } - - nest_size -= RTA_ALIGN (sub_len); - nest_attr = (struct rtattr *) (((char *) nest_attr) + RTA_ALIGN (sub_len)); } } break; + case IFLA_LINK: + /* Corresponde a la interfaz real de una vlan */ + if (nla_len (attr) != 4) { + /* Tamaño incorrecto para el vlan parent */ + continue; + } + + u32data = nla_get_u32 (attr); + iface->vlan_parent = u32data; + printf ("Interface %d: tiene como padre a %d\n", iface->index, iface->vlan_parent); //default: - //printf ("RTA Attribute \"%hu\" no procesado\n", attribute->rta_type); + //printf ("RTA Attribute \"%hu\" no procesado\n", nla_type (attr)); } } - if (was_new) { - /* Como la interfaz es nueva, buscar si tiene extensiones wireless */ - wireless_check_is_wireless_interface (handle, new); - } + return NL_SKIP; } -void interfaces_del_rtnl_link (NetworkInadorHandle *handle, struct nlmsghdr *h) { - struct ifinfomsg *iface; - Interface *to_del, *last; - IPv4 *address; - struct rtattr *attribute; - char real_hw[10]; - int len; - int index; +Interface * _interfaces_locate_by_index (GList *list, int index) { + Interface *iface; - iface = NLMSG_DATA(h); - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); + GList *g; - printf ("Mensaje de eliminar interfaz: %i\n", iface->ifi_index); - to_del = interfaces_locate_by_index (handle->interfaces, iface->ifi_index); + for (g = list; g != NULL; g = g->next) { + iface = (Interface *) g->data; + + if (iface->index == index) { + return iface; + } + } - if (to_del == NULL) { + return NULL; +} + +static int _interfaces_wait_ack_or_error (struct nl_msg *msg, void *arg) { + int *ret = (int *) arg; + struct nlmsgerr *l_err; + struct nlmsghdr *reply; + + reply = nlmsg_hdr (msg); + + if (reply->nlmsg_type == NLMSG_ERROR) { + l_err = nlmsg_data (reply); + + *ret = l_err->error; + } + + return NL_SKIP; +} + +static int _interfaces_wait_error (struct sockaddr_nl *nla, struct nlmsgerr *l_err, void *arg) { + int *ret = (int *) arg; + + *ret = l_err->error; + + return NL_SKIP; +} + +int interface_receive_message_dellink (struct nl_msg *msg, void *arg) { + NetworkInadorHandle *handle = (NetworkInadorHandle *) arg; + Interface *iface; + struct ifinfomsg *iface_msg; + int remaining; + uint32_t u32data; + struct nlmsghdr *reply; + struct nlattr *attr; + + reply = nlmsg_hdr (msg); + + if (reply->nlmsg_type != RTM_NEWLINK) return NL_SKIP; + + iface_msg = nlmsg_data (reply); + + iface = _interfaces_locate_by_index (handle->interfaces, iface_msg->ifi_index); + + if (iface == NULL) { printf ("Error, solicitaron eliminar interfaz que ya no existe\n"); - return; + return NL_SKIP; } - if (iface->ifi_family == AF_BRIDGE) { - /* Tenemos un evento especial, se está eliminando una interfaz a un bridge */ - for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len)) { - switch(attribute->rta_type) { - case IFLA_MASTER: - memcpy (&index, RTA_DATA (attribute), 4); - to_del->master_index = 0; - break; + if (iface_msg->ifi_family == AF_BRIDGE) { + /* Tenemos un evento especial, se está eliminando una interfaz de un bridge */ + nlmsg_for_each_attr(attr, reply, sizeof (struct ifinfomsg), remaining) { + if (nla_type (attr) == IFLA_MASTER) { + if (nla_len (attr) != 4) { + /* Tamaño incorrecto para el nuevo master */ + return NL_SKIP; + } + u32data = nla_get_u32 (attr); + iface->master_index = 0; } } - return; + printf ("Interface %d eliminada de la interfaz %d (bridge)\n", iface->index, iface->master_index); + /* Generar EVENTO AQUI */ + return NL_SKIP; } - /* Borrar las estructuras IP que contenga */ - address = to_del->v4_address; + handle->interfaces = g_list_remove (handle->interfaces, iface); - while (address != NULL) { - to_del->v4_address = address->next; - - free (address); - - address = to_del->v4_address; - } - - /* Borrar el objeto interfaz */ - if (to_del == handle->interfaces) { - /* Primero de la lista */ - - handle->interfaces = to_del->next; - } else { - last = handle->interfaces; - - while (last->next != to_del) { - last = last->next; - } - - last->next = to_del->next; - } - - free (to_del); + g_free (iface); } -void interfaces_add_or_update_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h) { - struct ifaddrmsg *addr; - struct rtattr *attribute; - struct in_addr ip; - char ip_as_string[1024]; +int interfaces_change_mac_address (NetworkInadorHandle *handle, int index, void *new_mac) { + /* ETHER_ADDR_LEN */ + struct nl_msg * msg; + struct ifinfomsg iface_hdr; + int ret, error; Interface *iface; - IPv4 *new; - uint32_t prefix; - addr = NLMSG_DATA(h); - - prefix = addr->ifa_prefixlen; - - iface = interfaces_locate_by_index (handle->interfaces, addr->ifa_index); + iface = _interfaces_locate_by_index (handle->interfaces, index); if (iface == NULL) { - /* No encuentro la interfaz... */ - return; - } - - printf ("IP para la interfaz: %d, de la familia: %d\n", addr->ifa_index, addr->ifa_family); - size_t len = IFA_PAYLOAD (h); - - for (attribute = IFA_RTA (addr); RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { - //printf ("Attribute (addr): %d\n", attribute->rta_type); + printf ("Error, solicitaron eliminar interfaz que ya no existe\n"); - if (attribute->rta_type == IFA_LOCAL) { - memcpy (&ip, RTA_DATA (attribute), sizeof (struct in_addr)); - - inet_ntop (AF_INET, &ip, ip_as_string, sizeof (ip_as_string)); - printf ("Address: %s/%d\n", ip_as_string, addr->ifa_prefixlen); - break; - } else if (attribute->rta_type == IFA_ADDRESS && addr->ifa_family == AF_INET6) { - inet_ntop (AF_INET6, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); - printf ("Address v6: %s/%d\n", ip_as_string, addr->ifa_prefixlen); - } + return -1; } - if (addr->ifa_family != AF_INET) { - /* Por el momento, las direcciones IPv6 no son procesadas */ - return; + iface_hdr.ifi_family = AF_UNSPEC; + iface_hdr.ifi_type = iface->ifi_type; + iface_hdr.ifi_index = iface->index; + iface_hdr.ifi_flags = iface->flags; + iface_hdr.ifi_change = 0xFFFFFFFF; + + msg = nlmsg_alloc_simple (RTM_NEWLINK, NLM_F_REQUEST); + ret = nlmsg_append (msg, &iface_hdr, sizeof (iface_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + nlmsg_free (msg); + + return -1; } - new = _interfaces_serach_ipv4 (iface, ip, prefix); + ret = nla_put (msg, IFLA_ADDRESS, ETHER_ADDR_LEN, new_mac); - if (new == NULL) { - printf ("Agregando IP a la lista de IP's\n"); - new = _interfaces_append_ipv4_to_struct (iface, ip, prefix); - manager_events_notify_ipv4_address_added (iface, new); + if (ret != 0) { + nlmsg_free (msg); + + return -1; } - new->flags = addr->ifa_flags; + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + if (ret <= 0) { + return -1; + } + + error = 0; + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_INVALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_ACK, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_err_cb (handle->nl_sock_route, NL_CB_CUSTOM, _interfaces_wait_error, &error); + + nl_recvmsgs_default (handle->nl_sock_route); + + if (ret != 0 || error < 0) { + return -1; + } + + return 0; } -void interfaces_del_ipv4 (NetworkInadorHandle *handle, struct nlmsghdr *h) { - struct ifaddrmsg *addr; - struct rtattr *attribute; - struct in_addr ip; - char ip_as_string[1024]; +int interfaces_change_mtu (NetworkInadorHandle *handle, int index, uint32_t new_mtu) { + /* ETHER_ADDR_LEN */ + struct nl_msg * msg; + struct ifinfomsg iface_hdr; + int ret, error; Interface *iface; - IPv4 *new, *before; - uint32_t prefix; - addr = NLMSG_DATA(h); - - prefix = addr->ifa_prefixlen; - - iface = interfaces_locate_by_index (handle->interfaces, addr->ifa_index); + iface = _interfaces_locate_by_index (handle->interfaces, index); if (iface == NULL) { - /* No encuentro la interfaz... */ - return; - } - - printf ("IP eliminada para la interfaz: %d, de la familia: %d\n", addr->ifa_index, addr->ifa_family); - - size_t len = IFA_PAYLOAD (h); - - for (attribute = IFA_RTA (addr); RTA_OK (attribute, len); attribute = RTA_NEXT (attribute, len)) { - //printf ("Attribute (addr): %d\n", attribute->rta_type); + printf ("Error, solicitaron eliminar interfaz que ya no existe\n"); - if (attribute->rta_type == IFA_LOCAL) { - memcpy (&ip, RTA_DATA (attribute), sizeof (struct in_addr)); - - inet_ntop (AF_INET, &ip, ip_as_string, sizeof (ip_as_string)); - printf ("Address: %s/%d\n", ip_as_string, addr->ifa_prefixlen); - break; - } else if (attribute->rta_type == IFA_ADDRESS && addr->ifa_family == AF_INET6) { - inet_ntop (AF_INET6, RTA_DATA (attribute), ip_as_string, sizeof (ip_as_string)); - printf ("Address v6: %s/%d\n", ip_as_string, addr->ifa_prefixlen); - } + return -1; } - if (addr->ifa_family != AF_INET) { - /* Por el momento, las direcciones IPv6 no son procesadas */ - return; + iface_hdr.ifi_family = AF_UNSPEC; + iface_hdr.ifi_type = iface->ifi_type; + iface_hdr.ifi_index = iface->index; + iface_hdr.ifi_flags = iface->flags; + iface_hdr.ifi_change = 0xFFFFFFFF; + + msg = nlmsg_alloc_simple (RTM_NEWLINK, NLM_F_REQUEST); + ret = nlmsg_append (msg, &iface_hdr, sizeof (iface_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + nlmsg_free (msg); + + return -1; } - new = _interfaces_serach_ipv4 (iface, ip, prefix); + ret = nla_put (msg, IFLA_MTU, sizeof (new_mtu), &new_mtu); - if (new == NULL) { - printf ("Me solicitaron eliminar la IP y NO existe\n"); + if (ret != 0) { + nlmsg_free (msg); + + return -1; + } + + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + if (ret <= 0) { + return -1; + } + + error = 0; + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_INVALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_ACK, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_err_cb (handle->nl_sock_route, NL_CB_CUSTOM, _interfaces_wait_error, &error); + + nl_recvmsgs_default (handle->nl_sock_route); + + if (ret != 0 || error < 0) { + return -1; + } + + return 0; +} + +static int _interfaces_change_admin_up (NetworkInadorHandle *handle, int index, int up) { + struct nl_msg * msg; + struct ifinfomsg iface_hdr; + int ret, error; + Interface *iface; + + iface = _interfaces_locate_by_index (handle->interfaces, index); + + if (iface == NULL) { + printf ("Error, solicitaron eliminar interfaz que ya no existe\n"); + + return -1; + } + + if (up && (iface->flags & IFF_UP)) { + /* Ningún cambio necesario, ya está activa */ + return 0; + } else if (up == FALSE && ((iface->flags & IFF_UP) == 0)) { + /* Ningún cambio necesario, ya está desactivada */ + return 0; + } + + iface_hdr.ifi_family = AF_UNSPEC; + iface_hdr.ifi_type = iface->ifi_type; + iface_hdr.ifi_index = iface->index; + if (up) { + iface_hdr.ifi_flags = iface->flags | IFF_UP; } else { - if (new == iface->v4_address) { - iface->v4_address = new->next; - } else { - before = iface->v4_address; - - while (before->next != new) { - before = before->next; - } - - before->next = new->next; - } + iface_hdr.ifi_flags = iface->flags & ~IFF_UP; + } + iface_hdr.ifi_change = 0xFFFFFFFF; + + msg = nlmsg_alloc_simple (RTM_NEWLINK, NLM_F_REQUEST); + ret = nlmsg_append (msg, &iface_hdr, sizeof (iface_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + nlmsg_free (msg); - free (new); - } -} - -void interfaces_manual_del_ipv4 (int sock, Interface *interface, IPv4 *address) { - struct msghdr rtnl_msg; - struct iovec io; - struct sockaddr_nl kernel; - char buffer[8192]; - int len; - struct nlmsghdr *nl; - struct ifaddrmsg *ifa; - 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 ifaddrmsg)); - nl->nlmsg_type = RTM_DELADDR; - nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nl->nlmsg_seq = global_nl_seq++; - nl->nlmsg_pid = local_nl.nl_pid; - - ifa = (struct ifaddrmsg*) NLMSG_DATA (nl); - ifa->ifa_family = AF_INET; // we only get ipv4 address here - ifa->ifa_prefixlen = address->prefix; - ifa->ifa_flags = IFA_F_PERMANENT; - ifa->ifa_scope = 0; - ifa->ifa_index = interface->index; - - rta = (struct rtattr*) IFA_RTA(ifa); - rta->rta_type = IFA_LOCAL; - memcpy (RTA_DATA(rta), &address->sin_addr, sizeof (struct in_addr)); - rta->rta_len = RTA_LENGTH(sizeof (struct in_addr)); - // update nlmsghdr length - nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + rta->rta_len; - - // del interface address - len = sizeof (buffer) - nl->nlmsg_len; - rta = (struct rtattr*) RTA_NEXT (rta, len); - rta->rta_type = IFA_ADDRESS; - memcpy (RTA_DATA(rta), &address->sin_addr, sizeof (struct in_addr)); - rta->rta_len = RTA_LENGTH(sizeof (struct in_addr)); - // update nlmsghdr length - 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)); - - 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 ("DEL IP 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 ("DEL IP Error tamaño truncado\n"); - } else if (l_err->error != 0) { - // Error: - printf ("DEL IP Error: %i\n", l_err->error); - } - break; - } - } -} - -void interfaces_manual_add_ipv4 (int sock, Interface *interface, IPv4 *address) { - struct msghdr rtnl_msg; - struct iovec io; - struct sockaddr_nl kernel; - char buffer[8192]; - int len; - struct nlmsghdr *nl; - struct ifaddrmsg *ifa; - 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 ifaddrmsg)); - nl->nlmsg_type = RTM_NEWADDR; - nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nl->nlmsg_seq = global_nl_seq++; - nl->nlmsg_pid = local_nl.nl_pid; - - ifa = (struct ifaddrmsg*) NLMSG_DATA (nl); - ifa->ifa_family = AF_INET; // we only get ipv4 address here - ifa->ifa_prefixlen = address->prefix; - ifa->ifa_flags = IFA_F_PERMANENT; - ifa->ifa_scope = 0; - ifa->ifa_index = interface->index; - - rta = (struct rtattr*) IFA_RTA(ifa); - rta->rta_type = IFA_LOCAL; - memcpy (RTA_DATA(rta), &address->sin_addr, sizeof (struct in_addr)); - rta->rta_len = RTA_LENGTH(sizeof (struct in_addr)); - // update nlmsghdr length - nl->nlmsg_len = NLMSG_ALIGN(nl->nlmsg_len) + rta->rta_len; - - // add interface address - len = sizeof (buffer) - nl->nlmsg_len; - rta = (struct rtattr*) RTA_NEXT (rta, len); - rta->rta_type = IFA_ADDRESS; - memcpy (RTA_DATA(rta), &address->sin_addr, sizeof (struct in_addr)); - rta->rta_len = RTA_LENGTH(sizeof (struct in_addr)); - // update nlmsghdr length - 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 ("Add IP 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 ("Add IP Error tamaño truncado\n"); - } else if (l_err->error != 0) { - // Error: - printf ("Add IP Error: %i\n", l_err->error); - } - break; - } - } -} - -void interfaces_bring_up (int sock, Interface *interface) { - 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 (&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; - - 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_PACKET; - ifi->ifi_index = interface->index; - ifi->ifi_change |= IFF_UP; - ifi->ifi_flags |= IFF_UP; - - 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)); - - 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 ("Bring UP 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 ("Bring up Error tamaño truncado\n"); - } else if (l_err->error != 0) { - // Error: - printf ("Bring up Error: %i\n", l_err->error); - } - break; - } - } -} - -void interfaces_bring_down (int sock, Interface *interface) { - 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 (&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; - - 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_PACKET; - ifi->ifi_index = interface->index; - ifi->ifi_change |= IFF_UP; - - 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)); - - 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 ("Bring DOWN 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 ("Bring down Error tamaño truncado\n"); - } else if (l_err->error != 0) { - // Error: - printf ("Bring down Error: %i\n", l_err->error); - } - break; - } - } -} - -void interfaces_clear_all_ipv4_address (NetworkInadorHandle *handle, Interface *interface) { - IPv4 *address; - - address = interface->v4_address; - - while (address != NULL) { - interfaces_manual_del_ipv4 (handle->netlink_sock_request, interface, address); - address = address->next; - } -} - -void interfaces_list_all (NetworkInadorHandle *handle, int sock) { - struct msghdr rtnl_msg; /* generic msghdr struct for use with sendmsg */ - struct iovec io; - nl_req_t req; - struct sockaddr_nl kernel; - char reply[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(&req, 0, sizeof(req)); - - kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination of our message) */ - kernel.nl_groups = 0; - - req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); - req.hdr.nlmsg_type = RTM_GETLINK; - req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - req.hdr.nlmsg_seq = global_nl_seq++; - req.hdr.nlmsg_pid = local_nl.nl_pid; - req.gen.rtgen_family = AF_PACKET; /* no preferred AF, we will get *all* interfaces */ - - io.iov_base = &req; - io.iov_len = req.hdr.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)); - - io.iov_base = reply; - io.iov_len = sizeof (reply); - 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 *) reply; - if (msg_ptr->nlmsg_type == NLMSG_DONE) break; - - for (; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len)) { - /* Como listamos interfaces, buscamos todos los mensajes RTM_NEWLINK */ - if (msg_ptr->nlmsg_type == RTM_NEWLINK) { - interfaces_add_or_update_rtnl_link (handle, msg_ptr, 1); - } - } + return -1; } - _interfaces_list_ipv4_address (handle, sock); + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + if (ret <= 0) { + return -1; + } + + error = 0; + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_INVALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_ACK, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_err_cb (handle->nl_sock_route, NL_CB_CUSTOM, _interfaces_wait_error, &error); + + nl_recvmsgs_default (handle->nl_sock_route); + + if (ret != 0 || error < 0) { + return -1; + } + + return 0; } +int interfaces_change_set_up (NetworkInadorHandle *handle, int index) { + return _interfaces_change_admin_up (handle, index, TRUE); +} + +int interfaces_change_set_down (NetworkInadorHandle *handle, int index) { + return _interfaces_change_admin_up (handle, index, FALSE); +} + +int interfaces_change_name (NetworkInadorHandle *handle, int index, char * new_name) { + /* IFNAMSIZ */ + struct nl_msg * msg; + struct ifinfomsg iface_hdr; + int ret, error; + Interface *iface; + + iface = _interfaces_locate_by_index (handle->interfaces, index); + + if (iface == NULL) { + printf ("Error, solicitaron eliminar interfaz que ya no existe\n"); + + return -1; + } + + if (strlen (new_name) > IFNAMSIZ) { + return -1; + } + + iface_hdr.ifi_family = AF_UNSPEC; + iface_hdr.ifi_type = iface->ifi_type; + iface_hdr.ifi_index = iface->index; + iface_hdr.ifi_flags = iface->flags; + iface_hdr.ifi_change = 0xFFFFFFFF; + + msg = nlmsg_alloc_simple (RTM_NEWLINK, NLM_F_REQUEST); + ret = nlmsg_append (msg, &iface_hdr, sizeof (iface_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + nlmsg_free (msg); + + return -1; + } + + ret = nla_put (msg, IFLA_IFNAME, strlen (new_name) + 1, new_name); + + if (ret != 0) { + nlmsg_free (msg); + + return -1; + } + + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + if (ret <= 0) { + return -1; + } + + error = 0; + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_INVALID, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_ACK, NL_CB_CUSTOM, _interfaces_wait_ack_or_error, &error); + nl_socket_modify_err_cb (handle->nl_sock_route, NL_CB_CUSTOM, _interfaces_wait_error, &error); + + ret = nl_recvmsgs_default (handle->nl_sock_route); + + if (ret != 0 || error < 0) { + return -1; + } + + return 0; +} + +void interfaces_init (NetworkInadorHandle *handle) { + /* Si es la primera vez que nos llaman, descargar una primera lista de interfaces */ + struct nl_msg * msg; + struct rtgenmsg rt_hdr = { + .rtgen_family = AF_PACKET, + }; + int ret; + + msg = nlmsg_alloc_simple (RTM_GETLINK, NLM_F_REQUEST | NLM_F_DUMP); + ret = nlmsg_append (msg, &rt_hdr, sizeof (rt_hdr), NLMSG_ALIGNTO); + + if (ret != 0) { + return; + } + + nl_complete_msg (handle->nl_sock_route, msg); + + ret = nl_send (handle->nl_sock_route, msg); + + nlmsg_free (msg); + + nl_socket_modify_cb (handle->nl_sock_route, NL_CB_VALID, NL_CB_CUSTOM, _interfaces_list_first_time, handle); + + nl_recvmsgs_default (handle->nl_sock_route); +} diff --git a/src/interfaces.h b/src/interfaces.h index 3a3c498..d427e51 100644 --- a/src/interfaces.h +++ b/src/interfaces.h @@ -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 -#include -#include +#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 diff --git a/src/ip-address.c b/src/ip-address.c new file mode 100644 index 0000000..e69de29 diff --git a/src/ip-address.h b/src/ip-address.h new file mode 100644 index 0000000..e69de29 diff --git a/src/network-inador.c b/src/main.c similarity index 50% rename from src/network-inador.c rename to src/main.c index 86a1cb9..44991fd 100644 --- a/src/network-inador.c +++ b/src/main.c @@ -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 #include -#include #include -#include +#include -#include +#include #include -#include -#include - #include -#include - -#include -#include -#include #include -#include "network-inador.h" +#include +#include + +#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); diff --git a/src/manager-events.c b/src/manager-events.c deleted file mode 100644 index 172be68..0000000 --- a/src/manager-events.c +++ /dev/null @@ -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 -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -#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); -} - diff --git a/src/manager-events.h b/src/manager-events.h deleted file mode 100644 index 6d057da..0000000 --- a/src/manager-events.h +++ /dev/null @@ -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 - diff --git a/src/manager.c b/src/manager.c deleted file mode 100644 index df87354..0000000 --- a/src/manager.c +++ /dev/null @@ -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 - -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#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; -} diff --git a/src/manager.h b/src/manager.h deleted file mode 100644 index f7d53f7..0000000 --- a/src/manager.h +++ /dev/null @@ -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 - diff --git a/src/netlink-events.c b/src/netlink-events.c index 5f3d200..7f1e009 100644 --- a/src/netlink-events.c +++ b/src/netlink-events.c @@ -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 -#include -#include - -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include +#include +#include #include -#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; } diff --git a/src/netlink-events.h b/src/netlink-events.h index 6a3baf4..f231122 100644 --- a/src/netlink-events.h +++ b/src/netlink-events.h @@ -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 - diff --git a/src/routes.c b/src/routes.c deleted file mode 100644 index 4bae017..0000000 --- a/src/routes.c +++ /dev/null @@ -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 -#include -#include -#include - -#include -#include -#include -#include - -#include - -#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); - } - } - } -} diff --git a/src/routes.h b/src/routes.h deleted file mode 100644 index ec3f6f9..0000000 --- a/src/routes.h +++ /dev/null @@ -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 - diff --git a/src/rta_aux.c b/src/rta_aux.c deleted file mode 100644 index 248aa42..0000000 --- a/src/rta_aux.c +++ /dev/null @@ -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 -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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; -} - diff --git a/src/rta_aux.h b/src/rta_aux.h deleted file mode 100644 index 4069976..0000000 --- a/src/rta_aux.h +++ /dev/null @@ -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 - diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index 1889119..0000000 --- a/src/utils.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -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; -} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 91e868e..0000000 --- a/src/utils.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __UTILS_H__ -#define __UTILS_H__ - -#include - -uint32_t utils_ip4_netmask_to_prefix (uint32_t netmask); -uint32_t utils_ip4_prefix_to_netmask (uint32_t prefix); - -#endif - diff --git a/src/wireless.c b/src/wireless.c deleted file mode 100644 index 669e6d7..0000000 --- a/src/wireless.c +++ /dev/null @@ -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 -#include -#include - -#include - -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#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); - } - } -} - diff --git a/src/wireless.h b/src/wireless.h deleted file mode 100644 index d1b891a..0000000 --- a/src/wireless.h +++ /dev/null @@ -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